【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
一、如何创建树状数据结构?
1、创建数据库表 City
DROP TABLE IF EXISTS `city`;
CREATE TABLE `city` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(255) DEFAULT NULL COMMENT '城市名',
`name_en` varchar(255) DEFAULT NULL COMMENT '城市英文名',
`parent_id` int(11) DEFAULT NULL COMMENT '父节点ID',
`del` int(1) NOT NULL DEFAULT '0' COMMENT '假删除 0-未删除 1-已删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
INSERT INTO `city` VALUES ('1', '江西省', 'JiangXi', '0', '0');
INSERT INTO `city` VALUES ('2', '赣州市', 'GanZhou', '1', '0');
INSERT INTO `city` VALUES ('3', '信丰县', 'XinFeng', '2', '0');
INSERT INTO `city` VALUES ('4', '南昌市', 'NanChang', '1', '0');
INSERT INTO `city` VALUES ('5', '兴国县', 'XinGuo', '2', '0');
2、创建相应的实体类 City
@Entity
@Table(name = "city")
@Data
public class City implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String nameEn;
private Integer parentId;
@Column(insertable = false)
private Integer del;
}
3、创建相应的 CityRepository
- 其中继承 JpaSpecificationExecutor<City> 是为了添加查询筛选条件
public interface CityRepository extends JpaRepository<City, Integer>, JpaSpecificationExecutor<City> {
}
4、创建相应的 CityService
public interface CityService {
/**
* 返回树状结构数据
* @return
*/
List<CityTree> buildTree();
}
- 其中用到的
CityTree
展示类
@Data
@EqualsAndHashCode
public class CityTree extends TreeNode {
private String name;
private String nameEn;
public CityTree(){
}
}
- 继承所用到的
TreeNode
类
@Data
public class TreeNode implements Serializable {
private static final long serialVersionUID = 8772115911922451037L;
protected Object id;
protected Object parentId;
protected List<TreeNode> children = new ArrayList<TreeNode>();
public void add(TreeNode node) {
children.add(node);
}
}
5、创建相应的 CityServiceImpl 实现类
@Service
public class CityServiceImpl implements CityService {
@Autowired
private CityRepository cityRepository;
@Override
public List<CityTree> buildTree() {
//添加筛选条件
Specification<City> specification = (Specification<City>) (root, criteriaQuery, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
predicates.add(criteriaBuilder.equal(root.get("del").as(Integer.class), 0));
Predicate[] pre = new Predicate[predicates.size()];
return criteriaQuery.where(predicates.toArray(pre)).getRestriction();
};
List<City> cityList = cityRepository.findAll(specification);
// cityList 为查询到的结果集, 0 代表的是根节点
return CityTreeUtil.buildCityTree(cityList, 0);
}
}
- 其中用到的
CityTreeUtil
工具类
@UtilityClass
public class CityTreeUtil {
/**
* @param cityList
* @param root
* @return
*/
public List<CityTree> buildCityTree(List<City> cityList, int root) {
List<CityTree> trees = new ArrayList<>();
CityTree node;
for (City city : cityList) {
node = new CityTree();
BeanUtils.copyProperties(city, node);
node.setId(city.getId());
node.setParentId(city.getParentId());
trees.add(node);
}
return TreeUtil.buildByLoop(trees, root);
}
}
- 其中用到的
TreeUtil
工具类
@UtilityClass
public class TreeUtil {
/**
* 两层循环实现建树
* @param treeNodes 传入的树节点列表
* @return
*/
public <T extends TreeNode> List<T> buildByLoop(List<T> treeNodes, Object root) {
List<T> trees = new ArrayList<>();
for (T treeNode : treeNodes) {
if (root.equals(treeNode.getParentId())) {
trees.add(treeNode);
}
for (T it : treeNodes) {
if (it.getParentId().equals(treeNode.getId())) {
if (treeNode.getChildren() == null) {
treeNode.setChildren(new ArrayList<>());
}
treeNode.add(it);
}
}
}
return trees;
}
/**
* 使用递归方法建树
* @param treeNodes
* @return
*/
public <T extends TreeNode> List<T> buildByRecursive(List<T> treeNodes, Object root) {
List<T> trees = new ArrayList<T>();
for (T treeNode : treeNodes) {
if (root.equals(treeNode.getParentId())) {
trees.add(findChildren(treeNode, treeNodes));
}
}
return trees;
}
/**
* 递归查找子节点
*
* @param treeNodes
* @return
*/
public <T extends TreeNode> T findChildren(T treeNode, List<T> treeNodes) {
for (T it : treeNodes) {
if (it.getParentId().equals(treeNode.getId())) {
if (treeNode.getChildren() == null) {
treeNode.setChildren(new ArrayList<>());
}
treeNode.add(findChildren(it, treeNodes));
}
}
return treeNode;
}
/**
* 查找TreeNode集合中 所有没有子节点的元素的id
* @param roleTree
* @return
*/
public Set<Object> filterChild(List<TreeNode> roleTree) {
Set<Object> grantMenu = new TreeSet<>();
roleTree.forEach(treeNode -> {
grantMenu.addAll(recursion(treeNode, grantMenu));
});
return grantMenu;
}
public Set<Object> recursion(TreeNode root, Set<Object> result) {
List<TreeNode> treeNodes = root.getChildren();
// TODO 没有子节点的直接加入数组
if (treeNodes == null || treeNodes.size() <= 0) {
result.add(root.getId());
//如果该节点没有子节点,将其加入解集,并结束递归
return result;
}
// TODO 有子节点则遍历后在查找
for (TreeNode treeNode : treeNodes) {
recursion(treeNode, result);
}
//否则的话,对其每一个子节点执行递归函数
return result;
}
}
6、创建相应的 Controller
@RestController
@RequestMapping("/city")
public class CityController {
@Autowired
private CityService cityService;
@GetMapping("/tree")
public Result buildTree(){
List<CityTree> cityTrees = cityService.buildTree();
return Result.success(cityTrees);
}
}
7、结果
{
"code": 200,
"msg": "success",
"data": [
{
"id": 1,
"parentId": 0,
"children": [
{
"id": 2,
"parentId": 1,
"children": [
{
"id": 3,
"parentId": 2,
"children": [],
"name": "信丰县",
"nameEn": "XinFeng"
},
{
"id": 5,
"parentId": 2,
"children": [],
"name": "兴国县",
"nameEn": "XinGuo"
}
],
"name": "赣州市",
"nameEn": "GanZhou"
},
{
"id": 4,
"parentId": 1,
"children": [],
"name": "南昌市",
"nameEn": "NanChang"
}
],
"name": "江西省",
"nameEn": "JiangXi"
}
]
}
来源:oschina
链接:https://my.oschina.net/u/4207078/blog/3146159