Привет! Это мой первый пост, который рассчитан на новичков в веб-программировании. Требуются знания:
— Java;
— Знать как создавать сервлет;
— HTML;
— JavaScript;
— JQuery.
Задача такова:
— На основе данных БД построить дерево на веб-странице, все дерево сразу грузить было нельзя так, как слишком много данных.
В своем посте я покажу маленький поэтапный пример того, как построить дерево с помощью сервлета и плагина JsTree, с использованием Ajax в формате JSON, данные будут генерироваться по простому алгоритму.
Весь код доступен на GitHub.
Модель
В таблице БД были записи типа {«id»,«parentId»,«text»}, для такого типа данных идеально подходит плагин JsTree. JsTree понимает данные в таком формате:
{
id : "string" // required
parent : "string" // required
text : "string" // node text
icon : "string" // string for custom
}
На деле оказалось, что нужно еще одно поле children. В него всегда надо ставить true, ничего страшного, если у элемента нет детей. После ajax запроса плагин это поймет и уберет стрелочку.
Для начала нам нужна модель:
public class Node {
private String id;
private String parent;
private String text;
private boolean children;
public Node(String id, String parent, String text) {
this.id = id;
this.parent = parent;
this.text = text;
this.children = true;
}
}
Теперь стоит разобраться, как конвертировать данные в JSON, лично я использовал FasterXML/jackson-core. Для этого добавил зависимости в maven:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.2.2</version>
</dependency>
И сам метод для конвертирования:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
public class ConverterJSON {
public static String toJSON_String(Map map) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(map.values());
}
}
Чтобы работал метод, нужно расставить аннотации в Node:
import com.fasterxml.jackson.annotation.JsonProperty;
public class Node {
@JsonProperty("id")
private String id;
@JsonProperty("parent")
private String parent;
@JsonProperty("text")
private String text;
@JsonProperty("children")
private boolean children;
public Node(String id, String parent, String text) {
this.id = id;
this.parent = parent;
this.text = text;
this.children = true;
}
public String getId() {
return id;
}
}
Замечательно, у нас есть модель, теперь нужны данные.
DAO
public interface Data {
public Map getRoot();
public Map getById(String parentId);
}
import java.util.HashMap;
import java.util.Map;
//Класс Синглтон
public class LocalDataImpl implements Data {
public static final int MAX_ELEMENT = 10;
private static LocalDataImpl ourInstance = new LocalDataImpl();
public static LocalDataImpl getInstance() {
return ourInstance;
}
private LocalDataImpl() {
}
@Override
public Map getRoot() { //Получем корень нашего дерева Это будет 10 элементов
Map result = new HashMap();
for (int i = 1; i < MAX_ELEMENT; i++) {
Node node = new Node(Integer.toString(i),"#","Node "+i); //В корне у JsTree элементы имеют родителя = "#"
result.put(node.getId(),node);
}
return result;
}
@Override
public Map getById(String parentId) { //Получем детей нашего дерева Это будет тоже 10 элементов, при этом Если Родитель нечетный то у него не будей
Map result = new HashMap();
if (Integer.parseInt(parentId)%2==0)
for (int i = 1; i < MAX_ELEMENT; i++) {
String newId = parentId+Integer.toString(i);
Node node = new Node(newId, parentId,"Node "+newId);
result.put(node.getId(),node);
}
return result;
}
}
Controller
Теперь нужен сервлет, который будет принимать id узла родителя, и отдавать детей в формате JSON:
@WebServlet(urlPatterns = {"/ajax"})
public class AjaxTree extends HttpServlet {
private Data data;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("application/json; charset=utf-8");
String nodeId = request.getParameter("id");
PrintWriter out = response.getWriter();
try{
if (nodeId.equals("root"))
out.println(ConverterJSON.toJSON_String(data.getRoot()));
else
out.println(ConverterJSON.toJSON_String(data.getById(nodeId)));
}catch (IOException e)
{e.printStackTrace();}
finally {
out.close();
}
}
@Override
public void init() throws ServletException {
super.init();
data = LocalDataImpl.getInstance();
}
}
Теперь нужно проверить его работоспособность, нужно собрать проект. На деле оказывается, что это не самое простое дело, но не беда, есть отличная пошаговая инструкция на русском языке.
Собрали проект и при использовании нашего сервлета видим:
Нечетный родитель — нет детей:
Четный — 9 штук:
Web
Теперь дело за малым, будем встраивать это чудо в страницу. Для этого нужно скачать Jquery и JsTree.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Только дерево</title>
<link rel="stylesheet" href="themes/default/style.min.css" />
</head>
<body>
<!-- Подключаем Jquery -->
<script src="js/jquery-2.1.1.min.js"></script>
<!-- Подключаем JsTree-->
<script src="js/jstree.min.js"></script>
<!-- Плюс необходимый скрипт -->
<script>
$(function () {
$('#jstree')
.jstree({
"plugins": [ "sort", "json_data" ],
'core': {
'data': {
'url': function (node) {
return node.id === '#' ? 'ajax?id=root' : 'ajax?id=' + node.id; <!-- Первые адрес указывает откуда получить корень , Второй детей-->
},
'data': function (node) {
return { 'id': node.id };
}
}
}
});
});
</script>
<div id="jstree"></div> <!-- Контейнер для расположения нашего дерева-->
</body>
</html>
Спасибо за внимание, надеюсь, кто-нибудь почерпнёт что-то полезное.
Автор: BioQwer