Java實(shí)現(xiàn)級(jí)聯(lián)下拉結(jié)構(gòu)的示例代碼
前言
在開發(fā)過程中,會(huì)遇到很多的實(shí)體需要將查出的數(shù)據(jù)處理為下拉或者級(jí)聯(lián)下拉的結(jié)構(gòu),提供給前端進(jìn)行展示。
在數(shù)據(jù)庫查出的結(jié)構(gòu)中,可能是集合<實(shí)體類>的結(jié)構(gòu),也有可能是List<Map>的結(jié)構(gòu)。
在下拉或者級(jí)聯(lián)下拉的節(jié)點(diǎn)數(shù)據(jù)中,有時(shí)候還需要?jiǎng)討B(tài)的攜帶其他的參數(shù),已便于前端對(duì)某些數(shù)據(jù)的顯示
如區(qū)域的級(jí)聯(lián)下拉樹中,需要攜帶經(jīng)緯度的區(qū)域–在選擇的時(shí)候在地圖展示該區(qū)域
基于上面的業(yè)務(wù)場景,構(gòu)建了下面的工具類,不當(dāng)?shù)牡胤秸埓蠹叶喽嘀附?/p>
注:在構(gòu)建下拉樹的時(shí)候,會(huì)存在父類id的判斷,可能沒有涵蓋到你們的使用情況,自行修改添加
構(gòu)建統(tǒng)一返回下拉結(jié)構(gòu)
/**
* Treeselect樹結(jié)構(gòu)實(shí)體類
*
* @author gongl
*/
@ApiModel("下拉樹結(jié)構(gòu)")
public class TreeSelect implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 節(jié)點(diǎn)ID
*/
@ApiModelProperty("節(jié)點(diǎn)id")
private String id;
/**
* 節(jié)點(diǎn)名稱
*/
@ApiModelProperty("節(jié)點(diǎn)名")
private String label;
/**
* 下拉節(jié)點(diǎn)中攜帶數(shù)據(jù)
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@ApiModelProperty("節(jié)點(diǎn)攜帶數(shù)據(jù)")
private Map<String, Object> dataMap;
/**
* 子節(jié)點(diǎn)
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@ApiModelProperty("子節(jié)點(diǎn)集合")
private List<TreeSelect> children;
public TreeSelect() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public List<TreeSelect> getChildren() {
return children;
}
public void setChildren(List<TreeSelect> children) {
this.children = children;
}
public Map<String, Object> getDataMap() {
return dataMap;
}
public void setDataMap(Map<String, Object> dataMap) {
this.dataMap = dataMap;
}
構(gòu)建集合<對(duì)象>轉(zhuǎn)下拉樹工具類
/**
* 下拉和級(jí)聯(lián)下拉通用生成工具類
*
* @Author gongl
* @Create 2022-01-12
*/
public class TreeSelectUtils {
private static final Logger log = LoggerFactory.getLogger(TreeSelectUtils.class);
/**
* 默認(rèn)id名稱
*/
public static final String ID = "id";
/**
* 默認(rèn)父類id名稱
*/
public static final String PARENT = "parentId";
/**
* 默認(rèn)label名稱
*/
public static final String LABEL = "name";
/**
* 單層下拉結(jié)構(gòu)
*
* @param collection 目標(biāo)集合
* @param id 節(jié)點(diǎn)編號(hào)字段
* @param label 節(jié)點(diǎn)名字段
* @param clazz 集合元素類型
* @param args 需要攜帶的參數(shù)
* @return 轉(zhuǎn)換后的下拉結(jié)構(gòu) TreeSelect
*/
public static <E> List<TreeSelect> singleTree(Collection<E> collection, String id, String label,
Class<?> clazz, String... args) {
try {
if (collection == null || collection.isEmpty()) {
return null;
}
Field idField;
try {
idField = clazz.getDeclaredField(id);
} catch (NoSuchFieldException e1) {
idField = clazz.getSuperclass().getDeclaredField(id);
}
Field labelField;
try {
labelField = clazz.getDeclaredField(label);
} catch (NoSuchFieldException e1) {
labelField = clazz.getSuperclass().getDeclaredField(label);
}
idField.setAccessible(true);
labelField.setAccessible(true);
List<TreeSelect> list = new ArrayList<>();
for (E e : collection) {
TreeSelect select = new TreeSelect();
select.setId(String.valueOf(idField.get(e)));
select.setLabel(String.valueOf(labelField.get(e)));
list.add(select);
dynamicData(select, e, clazz, args);
}
idField.setAccessible(false);
labelField.setAccessible(false);
return list;
} catch (Exception e) {
log.error("單層下拉異常:", e);
e.printStackTrace();
return null;
}
}
/**
* 集合轉(zhuǎn)樹結(jié)構(gòu)(默認(rèn)樹結(jié)構(gòu)字段)
*
* @param collection 目標(biāo)集合
* @param clazz 集合元素類型
* @param args 需要攜帶的參數(shù)
* @return 轉(zhuǎn)換后的樹形結(jié)構(gòu) TreeSelect
*/
public static <E> List<TreeSelect> toTree(@NotNull Collection<E> collection, @NotNull Class<?> clazz,
String... args) {
return toTree(collection, null, null, null, clazz, args);
}
/**
* 集合轉(zhuǎn)樹結(jié)構(gòu)(自定義名稱字段)
*
* @param collection 目標(biāo)集合
* @param label 節(jié)點(diǎn)名字段
* @param clazz 集合元素類型
* @param args 需要攜帶的參數(shù)
* @return 轉(zhuǎn)換后的樹形結(jié)構(gòu) TreeSelect
*/
public static <E> List<TreeSelect> toTree(@NotNull Collection<E> collection, @NotEmpty String label,
@NotNull Class<?> clazz, String... args) {
return toTree(collection, null, null, label, clazz, args);
}
/**
* 集合轉(zhuǎn)樹結(jié)構(gòu)(默認(rèn)父類id字段為parentId,其他自定義)
*
* @param collection 目標(biāo)集合
* @param id 節(jié)點(diǎn)編號(hào)字段
* @param label 節(jié)點(diǎn)名字段
* @param clazz 集合元素類型
* @param args 需要攜帶的參數(shù)
* @return 轉(zhuǎn)換后的樹形結(jié)構(gòu) TreeSelect
*/
public static <E> List<TreeSelect> toTree(@NotNull Collection<E> collection, @NotEmpty String id, @NotEmpty String label,
@NotNull Class<?> clazz, String... args) {
return toTree(collection, id, null, label, clazz, args);
}
/**
* 集合轉(zhuǎn)樹結(jié)構(gòu)(自定義樹結(jié)構(gòu)的字段)
*
* @param collection 目標(biāo)集合
* @param id 節(jié)點(diǎn)編號(hào)字段
* @param parent 父節(jié)點(diǎn)編號(hào)字段
* @param label 節(jié)點(diǎn)名字段
* @param clazz 集合元素類型
* @param args 需要攜帶的參數(shù)
* @return 轉(zhuǎn)換后的樹形結(jié)構(gòu) TreeSelect
*/
public static <E> List<TreeSelect> toTree(@NotNull Collection<E> collection, String id, String parent, String label,
@NotNull Class<?> clazz, String... args) {
try {
if (collection == null || collection.isEmpty()) {
return null;
}
//可以默認(rèn)名稱
if (StringUtils.isEmpty(id)) {
id = ID;
}
if (StringUtils.isEmpty(parent)) {
parent = PARENT;
}
if (StringUtils.isEmpty(label)) {
label = LABEL;
}
//是對(duì)象
return collectionObj(collection, id, parent, label, clazz, args);
} catch (Exception e) {
log.error("多層下拉樹異常:", e);
return null;
}
}
/**
* 集合對(duì)象的封裝
*/
private static <E> List<TreeSelect> collectionObj(@NotNull Collection<E> collection, String id, String parent, String label,
@NotNull Class<?> clazz, String... args) throws NoSuchFieldException, IllegalAccessException {
// 初始化根節(jié)點(diǎn)集合
List<TreeSelect> list = new ArrayList<>();
// 獲取 id 字段, 從當(dāng)前對(duì)象或其父類
Field idField;
try {
idField = clazz.getDeclaredField(id);
} catch (NoSuchFieldException e1) {
idField = clazz.getSuperclass().getDeclaredField(id);
}
// 獲取 parentId 字段, 從當(dāng)前對(duì)象或其父類
Field parentField;
try {
parentField = clazz.getDeclaredField(parent);
} catch (NoSuchFieldException e1) {
parentField = clazz.getSuperclass().getDeclaredField(parent);
}
// 獲取 label 字段, 從當(dāng)前對(duì)象或其父類
Field labelField;
try {
labelField = clazz.getDeclaredField(label);
} catch (NoSuchFieldException e1) {
labelField = clazz.getSuperclass().getDeclaredField(label);
}
idField.setAccessible(true);
parentField.setAccessible(true);
labelField.setAccessible(true);
// 找出所有的根節(jié)點(diǎn)
for (E e : collection) {
Object parentId = parentField.get(e);
if (isParentNode(parentId, idField, collection)) {
TreeSelect select = new TreeSelect();
select.setId(String.valueOf(idField.get(e)));
select.setLabel(String.valueOf(labelField.get(e)));
list.add(select);
dynamicData(select, e, clazz, args);
}
}
// 依次添加子節(jié)點(diǎn)
for (TreeSelect select : list) {
addChild(select, collection, idField, parentField, labelField, clazz, args);
}
idField.setAccessible(false);
parentField.setAccessible(false);
labelField.setAccessible(false);
return list;
}
/**
* 添加跟隨下拉的字段
*
* @param treeSelect 當(dāng)前節(jié)點(diǎn)
* @param e
* @param clazz
* @param args 需要跟隨的字段
* @throws IllegalAccessException
* @throws NoSuchFieldException
*/
private static <E> void dynamicData(@NotNull TreeSelect treeSelect, @NotNull Object e, @NotNull Class<E> clazz, String... args) throws IllegalAccessException, NoSuchFieldException {
if (args.length > 0) {
Map<String, Object> dataMap = new HashMap<>();
for (String arg : args) {
Field field;
try {
field = clazz.getDeclaredField(arg);
} catch (NoSuchFieldException e1) {
field = clazz.getSuperclass().getDeclaredField(arg);
}
field.setAccessible(true);
dataMap.put(arg, field.get(e));
field.setAccessible(false);
}
treeSelect.setDataMap(dataMap);
}
}
/**
* 為目標(biāo)節(jié)點(diǎn)添加孩子節(jié)點(diǎn)
*
* @param node 目標(biāo)節(jié)點(diǎn)
* @param collection 目標(biāo)集合
* @param idField ID 字段
* @param parentField 父節(jié)點(diǎn)字段
* @param labelField 字節(jié)點(diǎn)字段
*/
private static <E> void addChild(@NotNull TreeSelect node, @NotNull Collection<E> collection,
@NotNull Field idField, @NotNull Field parentField, @NotNull Field labelField,
@NotNull Class<?> clazz, String... args) throws IllegalAccessException, NoSuchFieldException {
//父節(jié)點(diǎn)的id
String id = node.getId();
//子節(jié)點(diǎn)集合
List<TreeSelect> children = new ArrayList<>();
for (E e : collection) {
String parentId = String.valueOf(parentField.get(e));
if (id.equals(parentId)) {
// 將當(dāng)前節(jié)點(diǎn)添加到目標(biāo)節(jié)點(diǎn)的孩子節(jié)點(diǎn)
TreeSelect treeSelect = new TreeSelect();
treeSelect.setId(String.valueOf(idField.get(e)));
treeSelect.setLabel(String.valueOf(labelField.get(e)));
dynamicData(treeSelect, e, clazz, args);
children.add(treeSelect);
// 遞歸添加子節(jié)點(diǎn)
addChild(treeSelect, collection, idField, parentField, labelField, clazz, args);
}
}
node.setChildren(children);
}
/**
* 判斷是否是根節(jié)點(diǎn), 判斷方式為:
* 1、父節(jié)點(diǎn)編號(hào)為空或?yàn)?0, 則認(rèn)為是根節(jié)點(diǎn)
* 2、父節(jié)點(diǎn)在集合中不存在父節(jié)點(diǎn)
*
* @param parentId 父節(jié)點(diǎn)編號(hào)
* @return 是否是根節(jié)點(diǎn)
*/
private static <E> boolean isParentNode(Object parentId, Field idField, @NotNull Collection<E> collection) throws IllegalAccessException {
if (parentId == null) {
return true;
} else if (parentId instanceof String && (StringUtils.isEmpty(String.valueOf(parentId)) || parentId.equals("0"))) {
return true;
} else if (parentId instanceof Long && Long.valueOf(0).equals(parentId)) {
return true;
} else {
for (E e : collection) {
Object o = idField.get(e);
if (Objects.equals(o, parentId)) {
return false;
}
}
return true;
}
}
}
構(gòu)建List<Map>轉(zhuǎn)下拉或下拉樹的工具類
/**
* 下拉和級(jí)聯(lián)下拉通用生成工具類
*
* @Author gongl
* @Create 2022-01-12
*/
public class MapToTreeSelectUtils {
private static final Logger log = LoggerFactory.getLogger(MapToTreeSelectUtils.class);
/**
* 數(shù)據(jù)庫默認(rèn)父類id名稱
*/
public static final String DB_PARENT = "parent_id";
/**
* 集合轉(zhuǎn)樹結(jié)構(gòu)(自定義樹結(jié)構(gòu)的字段)
*
* @param collection 目標(biāo)集合
* @param id 節(jié)點(diǎn)編號(hào)字段
* @param parent 父節(jié)點(diǎn)編號(hào)字段
* @param label 節(jié)點(diǎn)名字段
* @param args 需要攜帶的參數(shù)
* @return 轉(zhuǎn)換后的樹形結(jié)構(gòu) TreeSelect
*/
public static List<TreeSelect> mapToTree(String id, String parent, String label,
@NotNull List<Map<String, Object>> collection, String... args) {
try {
if (collection == null || collection.isEmpty()) {
return new ArrayList<>();
}
//可以默認(rèn)名稱
if (StringUtils.isEmpty(id)) {
id = TreeSelectUtils.ID;
}
if (StringUtils.isEmpty(parent)) {
parent = DB_PARENT;
}
if (StringUtils.isEmpty(label)) {
label = TreeSelectUtils.LABEL;
}
return collectionMap(id, parent, label, collection, args);
} catch (Exception e) {
log.error("多層下拉樹異常:", e);
return null;
}
}
/**
* 集合map的封裝
*/
private static List<TreeSelect> collectionMap(String id, String parent, String label,
@NotNull List<Map<String, Object>> collection, String... args) throws IllegalAccessException, NoSuchFieldException {
List<TreeSelect> list = new ArrayList<>();
// 找出所有的根節(jié)點(diǎn)
for (Map<String, Object> next : collection) {
Object parentId = next.get(parent);
if (isParentNodeMap(parentId, id, collection)) {
TreeSelect select = new TreeSelect();
select.setId(String.valueOf(next.get(id)));
select.setLabel(String.valueOf(next.get(label)));
list.add(select);
dynamicData(select, next, args);
}
}
// 依次添加子節(jié)點(diǎn)
for (TreeSelect select : list) {
addChildMap(select, id, parent, label, collection, args);
}
return list;
}
/**
* 添加跟隨下拉的字段
*
* @param treeSelect 當(dāng)前節(jié)點(diǎn)
* @param e
* @param args 需要跟隨的字段
* @throws IllegalAccessException
* @throws NoSuchFieldException
*/
private static void dynamicData(@NotNull TreeSelect treeSelect, @NotNull Map<String, Object> e, String... args) throws IllegalAccessException, NoSuchFieldException {
if (args.length > 0) {
Map<String, Object> dataMap = new HashMap<>();
for (String arg : args) {
dataMap.put(arg, e.get(arg));
}
treeSelect.setDataMap(dataMap);
}
}
/**
* 為目標(biāo)節(jié)點(diǎn)添加孩子節(jié)點(diǎn)
*
* @param node 目標(biāo)節(jié)點(diǎn)
* @param collection 目標(biāo)集合
* @param id ID 字段
* @param parent 父節(jié)點(diǎn)字段
* @param label 字節(jié)點(diǎn)字段
*/
private static void addChildMap(@NotNull TreeSelect node, String id, String parent, String label,
@NotNull List<Map<String, Object>> collection,
String... args) throws IllegalAccessException, NoSuchFieldException {
//父節(jié)點(diǎn)的id
String nodeId = node.getId();
//子節(jié)點(diǎn)集合
List<TreeSelect> children = new ArrayList<>();
for (Map<String, Object> e : collection) {
String parentId = String.valueOf(e.get(parent));
if (nodeId.equals(parentId)) {
// 將當(dāng)前節(jié)點(diǎn)添加到目標(biāo)節(jié)點(diǎn)的孩子節(jié)點(diǎn)
TreeSelect treeSelect = new TreeSelect();
treeSelect.setId(String.valueOf(e.get(id)));
treeSelect.setLabel(String.valueOf(e.get(label)));
dynamicData(treeSelect, e, args);
children.add(treeSelect);
node.setChildren(children);
// 遞歸添加子節(jié)點(diǎn)
addChildMap(treeSelect, id, parent, label, collection, args);
}
}
}
/**
* 判斷是否是根節(jié)點(diǎn), 判斷方式為:
* 1、父節(jié)點(diǎn)編號(hào)為空或?yàn)?0, 則認(rèn)為是根節(jié)點(diǎn)
* 2、父節(jié)點(diǎn)在集合中不存在父節(jié)點(diǎn)
*
* @param parentId 父節(jié)點(diǎn)編號(hào)
* @return 是否是根節(jié)點(diǎn)
*/
private static boolean isParentNodeMap(Object parentId, String id, @NotNull List<Map<String, Object>> collection) {
if (parentId == null) {
return true;
} else if (parentId instanceof String && (StringUtils.isEmpty(String.valueOf(parentId)) || parentId.equals("0"))) {
return true;
} else if (parentId instanceof Long && Long.valueOf(0).equals(parentId)) {
return true;
} else {
for (Map<String, Object> e : collection) {
Object o = e.get(id);
if (Objects.equals(o, parentId)) {
return false;
}
}
return true;
}
}
}
到此這篇關(guān)于Java實(shí)現(xiàn)級(jí)聯(lián)下拉結(jié)構(gòu)的示例代碼的文章就介紹到這了,更多相關(guān)Java級(jí)聯(lián)下拉內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java學(xué)生信息管理系統(tǒng)設(shè)計(jì)(數(shù)據(jù)庫版)
這篇文章主要為大家詳細(xì)介紹了數(shù)據(jù)庫版的Java學(xué)生信息管理系統(tǒng)設(shè)計(jì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11
SpringBoot+Ajax+redis實(shí)現(xiàn)隱藏重要接口地址的方法
這篇文章主要介紹了SpringBoot+Ajax+redis實(shí)現(xiàn)隱藏重要接口地址,本篇文章主要講訴使用SpringBoot項(xiàng)目配合Ajax和redis實(shí)現(xiàn)隱藏重要接口地址,這里我以隱藏秒殺地址為例,需要的朋友可以參考下2024-03-03
Dwr3.0純注解(純Java Code配置)配置與應(yīng)用淺析一之零配置文件化
Dwr對(duì)我來說最重要的功能點(diǎn)就是反向Ajax調(diào)用,通俗來將就是后端可以直接調(diào)用前端的JS方法(只要在所能訪問的范圍內(nèi)),這也就是Dwr的真正來由,當(dāng)然它也有最基本的前端直接調(diào)用后端的特性,省去了我們經(jīng)常的一般Ajax調(diào)用2016-04-04
Java object wait notify notifyAll代碼解析
這篇文章主要介紹了Java object wait notify notifyAll代碼解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11

