diff --git a/pom.xml b/pom.xml index 3952c49..bede74a 100644 --- a/pom.xml +++ b/pom.xml @@ -43,7 +43,12 @@ com.azure.spring spring-cloud-azure-starter - + + + com.github.xiaoymin + knife4j-spring-boot-starter + 3.0.3 + com.azure.spring spring-cloud-azure-starter-data-cosmos @@ -61,6 +66,13 @@ true + + + io.jsonwebtoken + jjwt + 0.9.1 + + org.springframework.boot spring-boot-starter-test diff --git a/src/main/java/cn/teammodel/common/PK.java b/src/main/java/cn/teammodel/common/PK.java index b269ee8..be88a68 100644 --- a/src/main/java/cn/teammodel/common/PK.java +++ b/src/main/java/cn/teammodel/common/PK.java @@ -8,6 +8,6 @@ import com.azure.cosmos.models.PartitionKey; * @create 2023-11-22 15:31 */ public interface PK { - PartitionKey PK_SCHOOL = new PartitionKey("School"); + PartitionKey PK_EVALUATION = new PartitionKey("Evaluation"); } diff --git a/src/main/java/cn/teammodel/config/exception/ServiceException.java b/src/main/java/cn/teammodel/config/exception/ServiceException.java index 1ac597c..d41050d 100644 --- a/src/main/java/cn/teammodel/config/exception/ServiceException.java +++ b/src/main/java/cn/teammodel/config/exception/ServiceException.java @@ -1,5 +1,7 @@ package cn.teammodel.config.exception; +import cn.teammodel.common.ErrorCode; + /** * 业务异常 * @@ -27,20 +29,21 @@ public final class ServiceException extends RuntimeException /** * 空构造方法,避免反序列化问题 */ - public ServiceException() - { - } + public ServiceException() {} public ServiceException(String message) { this.message = message; } - public ServiceException(String message, Integer code) - { + public ServiceException(Integer code, String message) { this.message = message; this.code = code; } + public ServiceException(ErrorCode errorCode) { + this.code = errorCode.getCode(); + this.message = errorCode.getMessage(); + } public String getDetailMessage() { diff --git a/src/main/java/cn/teammodel/config/knife/Knife4jConfig.java b/src/main/java/cn/teammodel/config/knife/Knife4jConfig.java new file mode 100644 index 0000000..d875269 --- /dev/null +++ b/src/main/java/cn/teammodel/config/knife/Knife4jConfig.java @@ -0,0 +1,35 @@ +package cn.teammodel.config.knife; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +/** + * Knife4j 接口文档配置
+ * https://doc.xiaominfo.com/knife4j/documentation/get_start.html + */ +@Configuration +@EnableSwagger2 +//@Profile({"dev", "test"}) +public class Knife4jConfig { + + @Bean + public Docket defaultApi2() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(new ApiInfoBuilder() + .title("五育评价接口文档") + .description("五育评价接口描述") + .version("1.0.1") + .build()) + .select() + // 指定 Controller 扫描包路径 + .apis(RequestHandlerSelectors.basePackage("cn.teammodel.controller")) + .paths(PathSelectors.any()) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/cn/teammodel/controller/EvaluationController.java b/src/main/java/cn/teammodel/controller/EvaluationController.java index af5a405..0b23be7 100644 --- a/src/main/java/cn/teammodel/controller/EvaluationController.java +++ b/src/main/java/cn/teammodel/controller/EvaluationController.java @@ -1,30 +1,54 @@ package cn.teammodel.controller; import cn.teammodel.common.R; +import cn.teammodel.model.dto.DeleteNodeDto; import cn.teammodel.model.dto.GetEvaluateTreeDto; -import cn.teammodel.model.entity.EvaluationTreeNode; +import cn.teammodel.model.dto.InsertNodeDto; +import cn.teammodel.model.dto.UpdateNodeDto; +import cn.teammodel.model.entity.Evaluation; import cn.teammodel.service.EvaluationService; +import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; -import java.util.List; /** * @author winter * @create 2023-11-22 15:10 */ @RestController -@RequestMapping("/public/evaluate") +@RequestMapping("/appraise") public class EvaluationController { @Resource private EvaluationService evaluationService; @PostMapping("getTrees") - public R> getEvaluateTree(@RequestBody GetEvaluateTreeDto getEvaluateTreeDto) { - List tree = evaluationService.getTree(getEvaluateTreeDto); - return R.success(tree); + @ApiOperation(value = "获取评价树", notes = "获取评价树") + public R getEvaluateTree(@RequestBody GetEvaluateTreeDto getEvaluateTreeDto) { + Evaluation evaluation = evaluationService.getTree(getEvaluateTreeDto); + return R.success(evaluation); + } + + @PostMapping("insertNode") + @ApiOperation(value = "新增评价树的节点") + public R insertNode(@RequestBody InsertNodeDto insertNodeDto) { + Evaluation evaluation = evaluationService.insertNode(insertNodeDto); + return R.success(evaluation); + } + @PostMapping("updateNode") + @ApiOperation(value = "更新评价树的节点", notes = "传递更新后的节点,而不是局部更新的值") + public R updateTree(@RequestBody UpdateNodeDto updateNodeDto) { + Evaluation evaluation = evaluationService.updateNode(updateNodeDto); + return R.success(evaluation); + } + @PostMapping("deleteNode") + @ApiOperation(value = "删除评价树的节点") + public R deleteNode(@RequestBody DeleteNodeDto deleteNodeDto) { + // todo: 注意删除子节点 + Evaluation evaluation = evaluationService.deleteNode(deleteNodeDto); + return R.success(evaluation); } } diff --git a/src/main/java/cn/teammodel/model/dto/DeleteNodeDto.java b/src/main/java/cn/teammodel/model/dto/DeleteNodeDto.java new file mode 100644 index 0000000..e78301c --- /dev/null +++ b/src/main/java/cn/teammodel/model/dto/DeleteNodeDto.java @@ -0,0 +1,16 @@ +package cn.teammodel.model.dto; + +import lombok.Data; + +/** + * @author winter + * @create 2023-11-22 16:16 + */ +@Data +public class DeleteNodeDto { + // 检索需要,但是有 bug + String schoolId; + String periodId; + // todo: 判断空 + String id; +} diff --git a/src/main/java/cn/teammodel/model/dto/InsertNodeDto.java b/src/main/java/cn/teammodel/model/dto/InsertNodeDto.java new file mode 100644 index 0000000..98d3ece --- /dev/null +++ b/src/main/java/cn/teammodel/model/dto/InsertNodeDto.java @@ -0,0 +1,21 @@ +package cn.teammodel.model.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author winter + * @create 2023-11-22 16:16 + */ +@Data +public class InsertNodeDto { + // 检索需要,但是有 bug + String schoolId; + String periodId; + @ApiModelProperty(value = "父亲节点,不传则为根节点") + String pid; + String name; + String logo; + Integer order; + boolean isPraise; +} diff --git a/src/main/java/cn/teammodel/model/dto/UpdateNodeDto.java b/src/main/java/cn/teammodel/model/dto/UpdateNodeDto.java new file mode 100644 index 0000000..084a540 --- /dev/null +++ b/src/main/java/cn/teammodel/model/dto/UpdateNodeDto.java @@ -0,0 +1,19 @@ +package cn.teammodel.model.dto; + +import lombok.Data; + +/** + * @author winter + * @create 2023-11-22 16:16 + */ +@Data +public class UpdateNodeDto { + // 检索需要,但是有 bug + String schoolId; + String periodId; + String id; + String name; + String logo; + Integer order; + boolean isPraise; +} diff --git a/src/main/java/cn/teammodel/model/entity/EvaluationTreeNode.java b/src/main/java/cn/teammodel/model/entity/EvaluationTreeNode.java index 7539d96..6eaf02f 100644 --- a/src/main/java/cn/teammodel/model/entity/EvaluationTreeNode.java +++ b/src/main/java/cn/teammodel/model/entity/EvaluationTreeNode.java @@ -1,6 +1,6 @@ package cn.teammodel.model.entity; -import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import java.util.List; @@ -15,7 +15,7 @@ public class EvaluationTreeNode { /** * 排序 */ - String order; + Integer order; /** * 分值 */ @@ -23,7 +23,8 @@ public class EvaluationTreeNode { /** * 是否表扬? 默认 true */ - boolean isPraise = true; - @JsonIgnore + @JsonProperty("isPraise") + boolean isPraise; + List children; } diff --git a/src/main/java/cn/teammodel/security/SecurityConfiguration.java b/src/main/java/cn/teammodel/security/SecurityConfiguration.java index 5e9a411..016e298 100644 --- a/src/main/java/cn/teammodel/security/SecurityConfiguration.java +++ b/src/main/java/cn/teammodel/security/SecurityConfiguration.java @@ -34,7 +34,17 @@ public class SecurityConfiguration { .and() .authorizeRequests(authorizeRequests -> authorizeRequests - .antMatchers("/public/**").permitAll() + .antMatchers("/public/**", + "/swagger-ui/", + "/swagger-resources/**", + "/**/v2/api-docs", + "/**/v3/api-docs", + "/**/*.html", + "/**/*.js", + "/**/*.css", + "/**/*.png", + "/**/*.map", + "/favicon.ico").permitAll() .anyRequest().authenticated() ) .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt) // 启用 OIDC jwt filter diff --git a/src/main/java/cn/teammodel/security/utils/SecurityUtils.java b/src/main/java/cn/teammodel/security/utils/SecurityUtils.java index f41caf5..b3dcf5f 100644 --- a/src/main/java/cn/teammodel/security/utils/SecurityUtils.java +++ b/src/main/java/cn/teammodel/security/utils/SecurityUtils.java @@ -26,7 +26,7 @@ public class SecurityUtils } catch (Exception e) { - throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED.value()); + throw new ServiceException( HttpStatus.UNAUTHORIZED.value(), "获取用户ID异常"); } } @@ -42,7 +42,7 @@ public class SecurityUtils } catch (Exception e) { - throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED.value()); + throw new ServiceException(HttpStatus.UNAUTHORIZED.value(), "获取用户账户异常"); } } @@ -57,7 +57,7 @@ public class SecurityUtils } catch (Exception e) { - throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED.value()); + throw new ServiceException(HttpStatus.UNAUTHORIZED.value(), "获取用户信息异常"); } } diff --git a/src/main/java/cn/teammodel/service/EvaluationService.java b/src/main/java/cn/teammodel/service/EvaluationService.java index 8769380..4fb1bcd 100644 --- a/src/main/java/cn/teammodel/service/EvaluationService.java +++ b/src/main/java/cn/teammodel/service/EvaluationService.java @@ -1,6 +1,10 @@ package cn.teammodel.service; +import cn.teammodel.model.dto.DeleteNodeDto; import cn.teammodel.model.dto.GetEvaluateTreeDto; +import cn.teammodel.model.dto.InsertNodeDto; +import cn.teammodel.model.dto.UpdateNodeDto; +import cn.teammodel.model.entity.Evaluation; import cn.teammodel.model.entity.EvaluationTreeNode; import java.util.List; @@ -10,12 +14,12 @@ import java.util.List; * @create 2023-11-20 17:46 */ public interface EvaluationService { - List getTree(GetEvaluateTreeDto getEvaluateTreeDto); + Evaluation getTree(GetEvaluateTreeDto getEvaluateTreeDto); /** * 递归构建树 */ - List buildTree(List nodes); + Evaluation buildTree(Evaluation evaluation); /** * 递归扁平化树 @@ -27,4 +31,19 @@ public interface EvaluationService { * @description: */ void flattenTree(List trees, List nodes); + + /** + * 新增评价树节点 + */ + Evaluation insertNode(InsertNodeDto insertNodeDto); + + /** + * 更新评价树节点 + */ + Evaluation updateNode(UpdateNodeDto updateNodeDto); + + /** + * 删除评价树节点,同时删除其子节点 + */ + Evaluation deleteNode(DeleteNodeDto deleteNodeDto); } diff --git a/src/main/java/cn/teammodel/service/impl/EvaluationServiceImpl.java b/src/main/java/cn/teammodel/service/impl/EvaluationServiceImpl.java index 2f96eca..dfa21bc 100644 --- a/src/main/java/cn/teammodel/service/impl/EvaluationServiceImpl.java +++ b/src/main/java/cn/teammodel/service/impl/EvaluationServiceImpl.java @@ -1,13 +1,21 @@ package cn.teammodel.service.impl; +import cn.hutool.core.lang.UUID; +import cn.teammodel.common.ErrorCode; import cn.teammodel.common.PK; +import cn.teammodel.config.exception.ServiceException; import cn.teammodel.dao.EvaluationRepository; +import cn.teammodel.model.dto.DeleteNodeDto; import cn.teammodel.model.dto.GetEvaluateTreeDto; +import cn.teammodel.model.dto.InsertNodeDto; +import cn.teammodel.model.dto.UpdateNodeDto; import cn.teammodel.model.entity.Evaluation; import cn.teammodel.model.entity.EvaluationTreeNode; import cn.teammodel.service.EvaluationService; +import com.azure.spring.data.cosmos.core.CosmosTemplate; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -20,25 +28,30 @@ import java.util.List; */ @Service public class EvaluationServiceImpl implements EvaluationService { + @Resource + CosmosTemplate cosmosTemplate; @Resource private EvaluationRepository evaluationRepository; @Override - public List getTree(GetEvaluateTreeDto getEvaluateTreeDto) { + public Evaluation getTree(GetEvaluateTreeDto getEvaluateTreeDto) { String schoolId = getEvaluateTreeDto.getSchoolId(); String periodId = getEvaluateTreeDto.getPeriodId(); periodId = StringUtils.isEmpty(periodId) ? "default" : periodId; - Evaluation evaluation = evaluationRepository.findBySchoolIdAndPeriodId(schoolId, periodId, PK.PK_SCHOOL); - List nodes = evaluation.getNodes(); - List trees = this.buildTree(nodes); - evaluation.setNodes(trees); - return trees; + Evaluation evaluation = evaluationRepository.findBySchoolIdAndPeriodId(schoolId, periodId, PK.PK_EVALUATION); + return this.buildTree(evaluation); } @Override - public List buildTree(List nodes) { + public Evaluation buildTree(Evaluation evaluation) { + if (evaluation == null) { + return null; + } + + List nodes = evaluation.getNodes(); List parents = new ArrayList<>(); + // pid 为 null 或者 "" 则为 parents for (EvaluationTreeNode node : nodes) { if (StringUtils.isBlank(node.getPid())) { @@ -49,7 +62,8 @@ public class EvaluationServiceImpl implements EvaluationService { for (EvaluationTreeNode parent : parents) { buildChildren(parent, nodes); } - return parents; + evaluation.setNodes(parents); + return evaluation; } @Override @@ -67,6 +81,101 @@ public class EvaluationServiceImpl implements EvaluationService { } } + @Override + public Evaluation insertNode(InsertNodeDto insertNodeDto) { + Evaluation evaluation = findEvaluation(insertNodeDto.getSchoolId(), insertNodeDto.getPeriodId()); + + List originNodes = evaluation.getNodes(); + // 拷贝数据到新节点 + EvaluationTreeNode newNode = new EvaluationTreeNode(); + BeanUtils.copyProperties(insertNodeDto, newNode); + + String newNodePid = newNode.getPid(); + // 根节点直接添加 + if (StringUtils.isNotEmpty(newNodePid)) { + boolean invalid = originNodes.stream().noneMatch(item -> newNodePid.equals(item.getId())); + if (invalid) { + throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "父节点不存在"); + } + } + // todo: 为新节点赋值必须参数 (id, creator), 可不可以添加默认值 order ? + newNode.setId(UUID.randomUUID().toString()); + originNodes.add(newNode); + evaluation.setNodes(originNodes); + return buildTree(evaluationRepository.save(evaluation)); + } + + @Override + public Evaluation updateNode(UpdateNodeDto updateNodeDto) { + String updateNodeId = updateNodeDto.getId(); + + Evaluation evaluation = findEvaluation(updateNodeDto.getSchoolId(), updateNodeDto.getPeriodId()); + List originNodes = evaluation.getNodes(); + // 每个节点都有 id, 直接校验是否合法 + EvaluationTreeNode updateNode = originNodes.stream() + .filter(item -> updateNodeId.equals(item.getId())) + .findFirst() + .orElseThrow(() -> new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "更新节点不存在")); + // 更新字段,考虑直接 copy properties + updateNode.setName(updateNodeDto.getName()); + updateNode.setLogo(updateNodeDto.getLogo()); + updateNode.setOrder(updateNodeDto.getOrder()); + updateNode.setPraise(updateNodeDto.isPraise()); + // todo: 为新节点赋值必须参数 (id, creator), 可不可以添加默认值 order ? + + return buildTree(evaluationRepository.save(evaluation)); + } + + @Override + public Evaluation deleteNode(DeleteNodeDto deleteNodeDto) { + // 删除指定节点,可能是(一级,二级,三级),设计一个通用的 + Evaluation evaluation = findEvaluation(deleteNodeDto.getSchoolId(), deleteNodeDto.getPeriodId()); + List nodes = evaluation.getNodes(); + List nodesToDelete = new ArrayList<>(); + + // 迭代器安全删除 + for (EvaluationTreeNode node : nodes) { + if (node.getId().equals(deleteNodeDto.getId())) { + // 删除当前节点 + nodesToDelete.add(node); + // 递归删除其孩子节点 + this.collectNodesToDelete(node.getId(), nodes, nodesToDelete); + } + } + nodes.removeAll(nodesToDelete); + + return buildTree(evaluationRepository.save(evaluation)); + } + + /** + * 递归收集 id 的节点及 id 节点的孩子节点 (迭代器删除居然也报错) + */ + private void collectNodesToDelete(String id, List nodes, List nodesToDelete) { + for (EvaluationTreeNode node : nodes) { + if (id.equals(node.getPid())) { + // 收集 + nodesToDelete.add(node); + // 递归收集 + collectNodesToDelete(node.getId(), nodes, nodesToDelete); + } + } + + } + + /** + * 通用的获取 evaluation 的方法: 判断参数,判断数据是否为空 + */ + private Evaluation findEvaluation(String schoolId,String periodId) { + periodId = StringUtils.isEmpty(periodId) ? "default" : periodId; + + // 拿到要新增节点的原始数据 + Evaluation evaluation = evaluationRepository.findBySchoolIdAndPeriodId(schoolId, periodId, PK.PK_EVALUATION); + if (evaluation == null) { + throw new ServiceException(ErrorCode.PARAMS_ERROR.getCode(), "学校评价数据不存在"); + } + return evaluation; + } + /** * 递归的构建父亲节点的孩子,以及孩子的孩子 (理论支持无极树,但应该考虑是否增加递归深度) */ @@ -84,6 +193,10 @@ public class EvaluationServiceImpl implements EvaluationService { } + + /** + * 获取节点的孩子节点列表 + */ private List getChildren(EvaluationTreeNode parent, List nodes) { List children = new ArrayList<>(); for (EvaluationTreeNode node : nodes) { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 968fddf..f0a1cdd 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,4 +1,14 @@ spring: + mvc: + pathmatch: + matching-strategy: ant_path_matcher + + # 文件上传 + servlet: + multipart: + # 大小限制 + max-file-size: 10MB + cloud: azure: cosmos: diff --git a/src/main/resources/libs/jjwt-0.9.1.jar b/src/main/resources/libs/jjwt-0.9.1.jar new file mode 100644 index 0000000..79d6288 Binary files /dev/null and b/src/main/resources/libs/jjwt-0.9.1.jar differ diff --git a/src/test/java/cn/teammodel/TeamModelExtensionApplicationTests.java b/src/test/java/cn/teammodel/TeamModelExtensionApplicationTests.java index e0aa427..5d6a2d9 100644 --- a/src/test/java/cn/teammodel/TeamModelExtensionApplicationTests.java +++ b/src/test/java/cn/teammodel/TeamModelExtensionApplicationTests.java @@ -1,6 +1,5 @@ package cn.teammodel; -import cn.hutool.json.JSONUtil; import cn.teammodel.dao.EvaluationRepository; import cn.teammodel.dao.StudentRepository; import cn.teammodel.manager.DingAlertNotifier; @@ -9,16 +8,20 @@ import cn.teammodel.model.entity.EvaluationTreeNode; import cn.teammodel.service.EvaluationService; import cn.teammodel.service.impl.EvaluationServiceImpl; import com.azure.cosmos.models.PartitionKey; +import com.azure.spring.data.cosmos.core.CosmosTemplate; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; import java.util.UUID; @SpringBootTest class TeamModelExtensionApplicationTests { + @Resource + CosmosTemplate cosmosTemplate; @Autowired private DingAlertNotifier notifier; @@ -65,7 +68,7 @@ class TeamModelExtensionApplicationTests { nodes.add(node2); evaluation.setNodes(nodes); - Evaluation saved = evaluationRepository.save(evaluation); + Evaluation saved = cosmosTemplate.insert(evaluation, null); System.out.println(saved); } @@ -73,14 +76,14 @@ class TeamModelExtensionApplicationTests { public void testSelect() { Evaluation saved = evaluationRepository.findBySchoolId("hbcn", new PartitionKey("evaluation")); EvaluationService service = new EvaluationServiceImpl(); - System.out.println(JSONUtil.parse(service.buildTree(saved.getNodes())).toStringPretty()); + //System.out.println(JSONUtil.parse(service.buildTree(saved.getNodes())).toStringPretty()); } @Test public void testUpdate() { //EvaluationTree saved = evaluationTreeRepository.findBySchoolId("hbcn", new PartitionKey("evaluation")); Evaluation saved = evaluationRepository.findBySchoolId("hbcn", new PartitionKey("evaluation")); EvaluationService service = new EvaluationServiceImpl(); - System.out.println(JSONUtil.parse(service.buildTree(saved.getNodes())).toStringPretty()); + //System.out.println(JSONUtil.parse(service.buildTree(saved.getNodes())).toStringPretty()); evaluationRepository.save(saved); } diff --git a/src/test/java/cn/teammodel/TestWithoutSpring.java b/src/test/java/cn/teammodel/TestWithoutSpring.java index 3546d66..c3e0096 100644 --- a/src/test/java/cn/teammodel/TestWithoutSpring.java +++ b/src/test/java/cn/teammodel/TestWithoutSpring.java @@ -1,6 +1,5 @@ package cn.teammodel; -import cn.hutool.json.JSONUtil; import cn.teammodel.model.entity.Evaluation; import cn.teammodel.model.entity.EvaluationTreeNode; import cn.teammodel.service.impl.EvaluationServiceImpl; @@ -127,11 +126,11 @@ public class TestWithoutSpring { nodes.add(node2); evaluation.setNodes(nodes); - List tree = service.buildTree(nodes); - System.out.println(JSONUtil.parse(service.buildTree(tree)).toStringPretty()); - - List nodeList = new ArrayList<>(); - service.flattenTree(tree, nodeList); - System.out.println(JSONUtil.parse(nodeList).toStringPretty()); + //List tree = service.buildTree(nodes); + //System.out.println(JSONUtil.parse(service.buildTree(tree)).toStringPretty()); + // + //List nodeList = new ArrayList<>(); + //service.flattenTree(tree, nodeList); + //System.out.println(JSONUtil.parse(nodeList).toStringPretty()); } }