Java递归解决多级列表的字段替换问题

Java递归解决多级列表的字段替换问题

一、前言

最近有个需求,需要做一个联级列表,数据是调用第三方获取的。前端同学想让我帮他把数据处理一下,换一下字段。

页面是这个样子:
在这里插入图片描述
修改之前的数据:

{
    "error": 0,
    "body": {
        "list": [
            {
                "deptLevel": "3",
                "deptCode": "484560642",
                "deptName": "业财运营部",
                "parentDeptCode": "57364999",
                "subDeptList": [
                            {
                        "deptLevel": "4",
                        "deptCode": "582020709",
                        "deptName": "数据运营组",
                        "parentDeptCode": "558333864",
                        "subDeptList": [
                            {
                                "deptLevel": "5",
                                "deptCode": "676189295",
                                "deptName": "线下运营组",
                                "parentDeptCode": "582020709"
                            },
                            {
                                "deptLevel": "5",
                                "deptCode": "676148284",
                                "deptName": "电商组",
                                "parentDeptCode": "582020709"
                            },
                            {
                                "deptLevel": "5",
                                "deptCode": "702186646",
                                "deptName": "品牌组",
                                "parentDeptCode": "582020709"
                            }
                        ]
                    },
                ]
            },

修改之后:

{
    "error": 0,
    "errorCode": "0",
    "message": "请求成功",
    "body": [
        {
            "label": "业务部",
            "value": "748",
            "children": [
                {
                    "label": "A作战部",
                    "value": "A作战部",
                    "children": [
                        {
                            "label": "A作战分部",
                            "value": "A作战分部"
                        },
                        {
                            "label": "B作战分部",
                            "value": "B作战分部"
                        },
                        {
                            "label": "C作战分部",
                            "value": "C作战分部"
                        },
                        {
                            "label": "广州作战分部",
                            "value": "广州作战分部",
                            "children": [
                                {
                                    "label": "广州谈判组",
                                    "value": "广州谈判组"
                                },
                                {
                                    "label": "广州执行组",
                                    "value": "广州执行组"
                                },
                                {
                                    "label": "粤西北执行组",
                                    "value": "粤西北执行组"
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}

二、 类

第三方返回的类:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * @date 2022/10/24 17:48
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DepartBo {
    private String deptLevel;
    private String deptCode;
    private String deptName;
    private String parentDeptCode;
    private List<DepartBo> subDeptList;
}

前端需要的类:

import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * @description 返回给前端的作战单元列表 组织树
 * @date 2022/10/31 13:39
 */
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LabelVO {
    @ApiModelProperty("名称")
    private String label;

    @ApiModelProperty("值")
    private String value;

    @ApiModelProperty("孩子")
    private List<LabelVO> children;
}

三、我的代码

/**
     * 递归,将部门树的字段替换成前端需要的字段
     * @param bo
     * @return
     */
    private LabelVO replaceLabel(DepartBo bo) {
        List<LabelVO> children = null;
        if (CollectionUtils.isNotEmpty(bo.getSubDeptList())) {
            children = new ArrayList<>();
            for (DepartBo departBo : bo.getSubDeptList()) {
                children.add(this.replaceLabel(departBo));
            }
        }
        return LabelVO.builder().label(bo.getDeptName()).value(bo.getDeptName()).children(children).build();
    }

    @Override
    public List<LabelVO> combatUnit() {
        List<LabelVO> result = new ArrayList<>();
       		//从第三方接口获取的数据
            List<DepartmentBo> list = feignDeptInterface.queryDepartments().getList();
            if (CollectionUtils.isNotEmpty(list)) {
                //3.然后再调用部门书列表接口 传入deptCode部门编号
                for (DepartmentBo departmentBo : list) {
                    List<DepartBo> departBoList =
                            feignDeptInterface.queryDeptTreeList().getList();
                    List<LabelVO> labelVOList = new ArrayList<>();
                    for (DepartBo departBo : departBoList) {
                        labelVOList.add(this.replaceLabel(departBo));
                    }
                    result.add(LabelVO.builder().label(departmentBo.getDeptName()).value(departmentBo.getDeptName()).children(labelVOList).build());
                }
            }
        }
        return result;
    }
<think>好的,我现在需要根据用户的要求,使用Java和MyBatis-Plus来实现视频下面的回复和评论数据的查询。首先,我得回顾用户之前的问题和我的回答。之前用户问的是评论和回复的区别,我从产品功能、数据结构、使用场景等方面做了分析,并给出了数据库表的设计对比,包括评论表(comment)和回复表(reply)的结构差异。现在用户希望基于这三张表(可能包括视频表、评论表、回复表),用Java和MyBatis-Plus来实现查询功能。 首先,我需要明确用户提到的“三张表”具体是什么结构。根据之前的回答,评论表关联video_id,回复表关联comment_id或parent_id,可能还有视频表video。可能需要先确认这三张表的具体字段,但用户可能指的是视频表、评论表和回复表。假设视频表是video,包含video_id等字段;评论表comment有comment_id、video_id、content、user_id、created_at等;回复表reply有reply_id、comment_id、parent_id(用于嵌套回复)、target_user_id、content、user_id、created_at等。 接下来,用户需要的是如何用Java和MyBatis-Plus来查询视频下的评论及其回复。这里可能需要分步实现: 1. **实体类映射**:根据数据库表结构创建对应的Java实体类,如Video、Comment、Reply,并使用MyBatis-Plus的注解进行映射,比如@TableName、@TableId等。 2. **Mapper接口**:为每个实体类创建Mapper接口,继承BaseMapper,以便使用MyBatis-Plus的通用CRUD方法。 3. **查询逻辑**: - 查询某个视频下的所有评论:根据video_id查询comment表。 - 查询每条评论下的回复:根据comment_id查询reply表,可能需要处理嵌套回复的结构,即树形结构。 4. **处理嵌套回复**:回复可能有多个层级,需要构建树形结构。例如,每个评论下的回复可能还有子回复,可以通过递归或循环来处理。 5. **DTO设计**:可能需要创建数据传输对象(DTO)来组合评论及其回复,便于前端展示。例如,CommentDTO包含评论信息和该评论下的回复列表。 6. **服务层和控制器层**:编写Service层处理业务逻辑,调用Mapper进行查询,并组装数据;Controller层处理HTTP请求,返回结果。 在实现过程中,可能会遇到如何高效查询评论及其回复的问题。如果回复表采用parent_id来构建树形结构,可能需要递归查询,或者使用MyBatis的collection标签进行嵌套查询。但MyBatis-Plus本身对复杂嵌套查询的支持可能需要自定义XML映射文件。 另外,考虑性能问题,如果一个视频的评论和回复数量很大,一次性查询所有数据可能会导致性能问题。可能需要分页查询评论,再按需加载回复,或者使用联表查询优化。 现在,用户可能希望得到具体的代码示例,包括实体类、Mapper、Service、Controller的实现,以及如何构建树形结构的回复。同时,需要确保使用MyBatis-Plus的特性,如lambda查询、分页插件等。 需要注意的地方: - 确保实体类的字段与数据库表对应,使用正确的注解。 - 在查询回复时,如何处理多层嵌套,可能需要递归方法或使用数据库的递归查询(如使用WITH RECURSIVE在SQL中,但不同数据库支持不同)。 - 返回的数据结构要清晰,方便前端展示,比如每个评论对象包含一个回复列表,每个回复可能包含子回复列表。 可能的实现步骤: 1. 创建实体类Comment和Reply,对应数据库表。 2. 创建Mapper接口,继承BaseMapper。 3. 在Service层中,先根据video_id查询所有评论,然后为每个评论查询其所有回复,并构建树形结构。 4. 使用DTO将评论和回复组合,返回给前端。 其中,构建回复的树形结构可能需要一个辅助方法,将平铺的回复列表转换为树形结构。例如,先查询某个评论下的所有回复,然后通过parent_id来组织层级。 另外,MyBatis-Plus的条件构造器可以方便地构建查询条件,比如QueryWrapper<Comment> query = new QueryWrapper<>(); query.eq("video_id", videoId); 来查询指定视频的评论。 对于嵌套回复的处理,可能在Service层中,查询到某个评论的所有回复后,通过遍历和递归构建树形结构。例如,先找到所有parent_id为null的回复(即直接回复评论的),然后递归查找每个回复的子回复。 最后,将结果封装成DTO返回,可能需要使用到递归或者树形结构的构建算法,如将列表转换为树形结构的方法。 总结一下,用户需要的是一个基于MyBatis-Plus实现的、能够查询视频下评论及其嵌套回复的Java代码示例,涉及实体类、Mapper、Service、Controller以及可能的DTO和树形结构处理。</think>我将基于标准的视频平台场景,使用MyBatis-Plus + Spring Boot实现评论回复查询。以下是完整实现方案: --- ### **一、数据库表结构(MySQL示例)** ```sql -- 视频表 CREATE TABLE video ( video_id BIGINT PRIMARY KEY, title VARCHAR(255) ); -- 评论表 CREATE TABLE comment ( comment_id BIGINT PRIMARY KEY, video_id BIGINT NOT NULL, user_id BIGINT NOT NULL, content TEXT, like_count INT DEFAULT 0, created_at DATETIME ); -- 回复表(支持多级嵌套) CREATE TABLE reply ( reply_id BIGINT PRIMARY KEY, comment_id BIGINT NOT NULL, -- 所属主评论ID parent_id BIGINT DEFAULT 0, -- 父回复ID(0表示直接回复评论) target_user_id BIGINT, -- 被回复用户ID user_id BIGINT NOT NULL, -- 回复者ID content TEXT, created_at DATETIME ); ``` --- ### **二、领域模型与DTO设计** #### 1. 实体类 ```java // Comment.java @Data @TableName("comment") public class Comment { @TableId(type = IdType.AUTO) private Long commentId; private Long videoId; private Long userId; private String content; private Integer likeCount; private LocalDateTime createdAt; } // Reply.java @Data @TableName("reply") public class Reply { @TableId(type = IdType.AUTO) private Long replyId; private Long commentId; private Long parentId; // 0表示直接回复评论 private Long targetUserId; private Long userId; private String content; private LocalDateTime createdAt; } ``` #### 2. 树形结构DTO ```java // CommentDTO.java @Data public class CommentDTO { private Comment comment; private List<ReplyNode> replyTree; // 嵌套回复树 } // ReplyNode.java @Data public class ReplyNode { private Reply reply; private List<ReplyNode> children; // 子回复 } ``` --- ### **三、Mapper层实现** ```java // CommentMapper.java public interface CommentMapper extends BaseMapper<Comment> { // 基础查询已由MyBatis-Plus自动实现 } // ReplyMapper.java public interface ReplyMapper extends BaseMapper<Reply> { // 查询某评论下的所有回复(平铺结构) @Select("SELECT * FROM reply WHERE comment_id = #{commentId}") List<Reply> selectByCommentId(@Param("commentId") Long commentId); } ``` --- ### **四、Service层核心逻辑** ```java @Service @RequiredArgsConstructor public class CommentService { private final CommentMapper commentMapper; private final ReplyMapper replyMapper; // 获取视频评论及嵌套回复 public List<CommentDTO> getVideoComments(Long videoId) { // 1. 查询主评论 List<Comment> comments = commentMapper.selectList( new QueryWrapper<Comment>() .eq("video_id", videoId) .orderByDesc("like_count", "created_at") ); // 2. 构建DTO结构 return comments.stream().map(comment -> { CommentDTO dto = new CommentDTO(); dto.setComment(comment); // 3. 查询该评论下的所有回复 List<Reply> replies = replyMapper.selectByCommentId(comment.getCommentId()); // 4. 构建回复树形结构 dto.setReplyTree(buildReplyTree(replies)); return dto; }).collect(Collectors.toList()); } // 将平铺回复列表转为树形结构(关键算法) private List<ReplyNode> buildReplyTree(List<Reply> replies) { Map<Long, ReplyNode> nodeMap = new HashMap<>(); List<ReplyNode> rootNodes = new ArrayList<>(); // 第一遍:创建所有节点 for (Reply reply : replies) { ReplyNode node = new ReplyNode(); node.setReply(reply); node.setChildren(new ArrayList<>()); nodeMap.put(reply.getReplyId(), node); } // 第二遍:建立父子关系 for (Reply reply : replies) { ReplyNode node = nodeMap.get(reply.getReplyId()); if (reply.getParentId() == 0) { // 根节点 rootNodes.add(node); } else { // 子节点 ReplyNode parent = nodeMap.get(reply.getParentId()); if (parent != null) { parent.getChildren().add(node); } } } return rootNodes; } } ``` --- ### **五、Controller层接口** ```java @RestController @RequestMapping("/comments") @RequiredArgsConstructor public class CommentController { private final CommentService commentService; @GetMapping("/video/{videoId}") public ResponseEntity<List<CommentDTO>> getCommentsByVideo( @PathVariable Long videoId) { return ResponseEntity.ok(commentService.getVideoComments(videoId)); } } ``` --- ### **六、性能优化策略** 1. **批量查询优化**: ```java // 使用commentId集合批量查询回复 List<Long> commentIds = comments.stream() .map(Comment::getCommentId) .collect(Collectors.toList()); Map<Long, List<Reply>> replyMap = replyMapper.selectList( new QueryWrapper<Reply>().in("comment_id", commentIds) ).stream().collect(Collectors.groupingBy(Reply::getCommentId)); ``` 2. **分页查询**: ```java // 添加分页参数 Page<Comment> page = new Page<>(pageNum, pageSize); commentMapper.selectPage(page, new QueryWrapper<Comment>().eq("video_id", videoId)); ``` 3. **缓存设计**: ```java @Cacheable(value = "videoComments", key = "#videoId") public List<CommentDTO> getVideoComments(Long videoId) { // ...原有逻辑 } ``` --- ### **七、示例查询结果结构** ```json [ { "comment": { "commentId": 123, "content": "这个视频太棒了", "likeCount": 100 }, "replyTree": [ { "reply": { "replyId": 456, "content": "确实很精彩" }, "children": [ { "reply": { "replyId": 789, "content": "@用户A 同感!" }, "children": [] } ] } ] } ] ``` --- ### **八、扩展建议** 1. **延迟加载**:对回复树深度超过3层的分支做折叠加载 2. **敏感词过滤**:在Service层添加内容过滤逻辑 3. **@用户处理**:解析内容中的@用户信息并替换为链接 4. **通知系统集成**:在回复插入时触发消息通知 该实现方案完整展示了从数据存储到接口响应的全流程,兼顾了功能实现与性能考量。实际部署时可根据数据量级选择启用缓存策略或分页机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱喝皮蛋瘦肉粥的小饶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值