RichFaces - Богатое дерево
В этой главе мы узнаем об обработке дерева в RichFaces. RichFaces предоставляет все необходимые компоненты для создания дерева и управления им.
<rich: treeNode>
Этот тег используется для создания иерархического дерева. Каждый узел, предоставленный внутри <treeNode>, будет дочерним узлом дерева. Этот тег будет использоваться с другим тегом под названием <rich: tree>. Все переменные экземпляра, которые мы используем для создания дерева, должны реализовывать любой из этих трех интерфейсов:org.richfaces.model.TreeNode, org.richfaces.model.TreeDataModel, и javax.swing.tree.TreeNode.
В следующем примере мы заполним дерево с помощью тега <rich: treeNode> из серверной части.
<?xml version = "1.0" encoding = "UTF-8"?>
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:h = "http://java.sun.com/jsf/html"
xmlns:f = "http://java.sun.com/jsf/core"
xmlns:ui = "http://java.sun.com/jsf/facelets"
xmlns:a4j = "http://richfaces.org/a4j"
xmlns:rich = "http://richfaces.org/rich">
<h:head>
<title>TreeNode Example</title>
<meta name = "viewport" content = "width = device-width, initial-scale = 1.0"/>
</h:head>
<h:body>
<h:form>
<rich:tree value = "#{tree.populateNode}" var = "tree">
<rich:treeNode>
<rich:treeModelRecursiveAdaptor>
</rich:treeModelRecursiveAdaptor>
<h:outputText value = "#{tree.data}" />
</rich:treeNode>
</rich:tree>
</h:form>
</h:body>
</html>
Ниже приведен связанный класс Java, который реализует “TreeNodeImpl” интерфейс.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import org.richfaces.model.TreeNodeImpl;
@ManagedBean
@RequestScoped
public class Tree extends TreeNodeImpl {
private Tree stationRoot;
private Tree populateNode;
private Object data;
public Tree() {
super();
}
public Tree(boolean leaf, Object data) {
super(leaf);
this.data = data;
}
public Object getData() {
return data;
}
public Tree getPopulateNode() {
if (populateNode == null) {
String[] List_OF_Node = {
"Frist Node", "Second Node", "Third Node", "Fourth Node", "Fifth Node"};
stationRoot = new Tree(false, "Example Of Tree");
for (int i = 0; i < List_OF_Node.length; i++) {
Tree child = new Tree(true, List_OF_Node[i]);
stationRoot.addChild(i, child);
}
populateNode = new Tree();
populateNode.addChild(0, stationRoot);
}
return populateNode;
}
}
Приведенный выше фрагмент кода создаст в браузере следующий результат.
<rich: treeModelAdaptor>
Этот компонент принимает карту в качестве входных данных, выполняет итерацию по ней и производит требуемый вывод в браузере. Когда нам нужно заполнить рекурсивную карту, мы можем использовать другой тег с именем<rich:recursiveTreeModelAdaptor>.
В следующем примере показано, как визуализировать структуру проекта в браузере. В RichFaces 3 эти два тега используются <rich: treeNodeAdaptor> и <rich: recursiveTreeNodeAdaptor>.
<?xml version = "1.0" encoding = "UTF-8"?>
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:h = "http://java.sun.com/jsf/html"
xmlns:f = "http://java.sun.com/jsf/core"
xmlns:ui = "http://java.sun.com/jsf/facelets"
xmlns:a4j = "http://richfaces.org/a4j"
xmlns:rich = "http://richfaces.org/rich">
<h:head>
<title>Tree Model and Recursive Model Example</title>
</h:head>
<h:body>
<h:form id = "form">
<rich:tree toggleType = "AJAX" var = "item" style = "max-width: 400px">
<rich:treeModelRecursiveAdaptor roots = "#{fileSystemBean.sourceRoots}"
nodes = "#{item.directories}">
<rich:treeNode>
#{item.shortPath}
</rich:treeNode>
<rich:treeModelAdaptor nodes = "#{item.files}">
<rich:treeNode>#{item}</rich:treeNode>
</rich:treeModelAdaptor>
</rich:treeModelRecursiveAdaptor>
</rich:tree>
</h:form>
</h:body>
</html>
Для этого примера нам нужно создать два новых Java-бина. Ниже приведен фрагмент кода для класса компонента «FileSystemBean.java», который содержит требуемое имя папки.
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean
@RequestScoped
public class FileSystemBean {
private static final String SRC_PATH = "/WEB-INF";
private List<FileSystemNode> srcRoots;
public synchronized List<FileSystemNode> getSourceRoots() {
if (srcRoots == null) {
srcRoots = new FileSystemNode(SRC_PATH).getDirectories();
}
return srcRoots;
}
}
Ниже приведен фрагмент кода для класса bean-компонента FileSystemNode.java, который содержит требуемый листовой узел проекта.
import static com.google.common.base.Predicates.containsPattern;
import static com.google.common.base.Predicates.not;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
public class FileSystemNode {
private static final Function<String, FileSystemNode>
FACTORY = new Function<String, FileSystemNode>() {
public FileSystemNode apply(String from) {
return new FileSystemNode(from.substring(0, from.length() - 1));
};
};
private static final Function<String, String>
TO_SHORT_PATH = new Function<String, String>() {
public String apply(String from) {
int idx = from.lastIndexOf('/');
if (idx < 0) {
return from;
}
return from.substring(idx + 1);
};
};
private String path;
private List<FileSystemNode> directories;
private List<String> files;
private String shortPath;
public FileSystemNode(String path) {
this.path = path;
int idx = path.lastIndexOf('/');
if (idx != -1) {
shortPath = path.substring(idx + 1);
} else {
shortPath = path;
}
}
public synchronized List<FileSystemNode> getDirectories() {
if (directories == null) {
directories = Lists.newArrayList();
Iterables.addAll(directories, transform(filter(
getResourcePaths(), containsPattern("/$")), FACTORY));
}
return directories;
}
public synchronized List<String> getFiles() {
if (files == null) {
files = new ArrayList<String>();
Iterables.addAll(files, transform(filter(
getResourcePaths(), not(containsPattern("/$"))), TO_SHORT_PATH));
}
return files;
}
private Iterable<String> getResourcePaths() {
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
Set<String> resourcePaths = externalContext.getResourcePaths(this.path);
if (resourcePaths == null) {
resourcePaths = Collections.emptySet();
}
return resourcePaths;
}
public String getShortPath() {
return shortPath;
}
}
В приведенном выше примере в браузере будет отображаться следующий результат.