From dbde5021a6c84059e6da3a353f10e29c39d563c1 Mon Sep 17 00:00:00 2001 From: caiyuchao Date: Tue, 15 Jul 2025 16:22:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=A1=B9=E7=9B=AE=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=AF=84=E8=AE=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../license/enums/ErrorCodeConstants.java | 7 + .../admin/comment/CommentController.java | 105 ++++++++++ .../admin/comment/vo/CommentListReqVO.java | 32 +++ .../admin/comment/vo/CommentRespVO.java | 39 ++++ .../admin/comment/vo/CommentSaveReqVO.java | 27 +++ .../admin/comment/vo/CommentTreeRespVO.java | 61 ++++++ .../dal/dataobject/comment/CommentDO.java | 53 +++++ .../dal/mysql/comment/CommentMapper.java | 40 ++++ .../service/comment/CommentService.java | 57 ++++++ .../service/comment/CommentServiceImpl.java | 183 ++++++++++++++++++ .../mapper/comment/CommentMapper.xml | 28 +++ 11 files changed, 632 insertions(+) create mode 100644 agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/CommentController.java create mode 100644 agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentListReqVO.java create mode 100644 agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentRespVO.java create mode 100644 agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentSaveReqVO.java create mode 100644 agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentTreeRespVO.java create mode 100644 agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/dal/dataobject/comment/CommentDO.java create mode 100644 agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/dal/mysql/comment/CommentMapper.java create mode 100644 agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/service/comment/CommentService.java create mode 100644 agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/service/comment/CommentServiceImpl.java create mode 100644 agt-module-license/agt-module-license-server/src/main/resources/mapper/comment/CommentMapper.xml diff --git a/agt-module-license/agt-module-license-api/src/main/java/org/agt/module/license/enums/ErrorCodeConstants.java b/agt-module-license/agt-module-license-api/src/main/java/org/agt/module/license/enums/ErrorCodeConstants.java index c57bf3c..04ce74e 100644 --- a/agt-module-license/agt-module-license-api/src/main/java/org/agt/module/license/enums/ErrorCodeConstants.java +++ b/agt-module-license/agt-module-license-api/src/main/java/org/agt/module/license/enums/ErrorCodeConstants.java @@ -16,4 +16,11 @@ public interface ErrorCodeConstants { ErrorCode PROJECT_CODE_DUPLICATE = new ErrorCode(1_100_001_003, "项目编号`{}`已存在"); ErrorCode LICENSE_NOT_EXISTS = new ErrorCode(1_100_002_001, "License不存在"); ErrorCode LICENSE_SN_DUPLICATE = new ErrorCode(1_100_001_002, "License SN`{}`已存在"); + + ErrorCode COMMENT_NOT_EXISTS = new ErrorCode(1_100_003_001, "评论不存在"); + ErrorCode COMMENT_EXITS_CHILDREN = new ErrorCode(1_100_003_002, "存在子评论,无法删除"); + ErrorCode COMMENT_PARENT_NOT_EXITS = new ErrorCode(1_100_003_003,"父级评论不存在"); + ErrorCode COMMENT_PARENT_ERROR = new ErrorCode(1_100_003_004, "不能设置自己为父评论"); + ErrorCode COMMENT_CONTENT_DUPLICATE = new ErrorCode(1_100_003_005, "已经存在该内容的评论"); + ErrorCode COMMENT_PARENT_IS_CHILD = new ErrorCode(1_100_003_006, "不能设置自己的子Comment为父Comment"); } diff --git a/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/CommentController.java b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/CommentController.java new file mode 100644 index 0000000..d040cec --- /dev/null +++ b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/CommentController.java @@ -0,0 +1,105 @@ +package org.agt.module.license.controller.admin.comment; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.agt.framework.apilog.core.annotation.ApiAccessLog; +import org.agt.framework.common.pojo.CommonResult; +import org.agt.framework.common.util.object.BeanUtils; +import org.agt.framework.excel.core.util.ExcelUtils; +import org.agt.module.license.controller.admin.comment.vo.CommentListReqVO; +import org.agt.module.license.controller.admin.comment.vo.CommentRespVO; +import org.agt.module.license.controller.admin.comment.vo.CommentSaveReqVO; +import org.agt.module.license.controller.admin.comment.vo.CommentTreeRespVO; +import org.agt.module.license.dal.dataobject.comment.CommentDO; +import org.agt.module.license.service.comment.CommentService; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.List; + +import static org.agt.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static org.agt.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 评论") +@RestController +@RequestMapping("/license/comment") +@Validated +public class CommentController { + + @Resource + private CommentService commentService; + + @PostMapping("/create") + @Operation(summary = "创建评论") +// @PreAuthorize("@ss.hasPermission('license:comment:create')") + public CommonResult createComment(@Valid @RequestBody CommentSaveReqVO createReqVO) { + return success(commentService.createComment(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新评论") +// @PreAuthorize("@ss.hasPermission('license:comment:update')") + public CommonResult updateComment(@Valid @RequestBody CommentSaveReqVO updateReqVO) { + commentService.updateComment(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除评论") + @Parameter(name = "id", description = "编号", required = true) +// @PreAuthorize("@ss.hasPermission('license:comment:delete')") + public CommonResult deleteComment(@RequestParam("id") Long id) { + commentService.deleteComment(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得评论") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('license:comment:query')") + public CommonResult getComment(@RequestParam("id") Long id) { + CommentDO comment = commentService.getComment(id); + return success(BeanUtils.toBean(comment, CommentRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得评论列表") + @PreAuthorize("@ss.hasPermission('license:comment:query')") + public CommonResult> getCommentList(@Valid CommentListReqVO listReqVO) { + List list = commentService.getCommentList(listReqVO); + return success(BeanUtils.toBean(list, CommentRespVO.class)); + } + + @GetMapping("/tree") + @Operation(summary = "获得评论树形列表") + public CommonResult> getCommentTree(@RequestParam("projectId") Long projectId, @RequestParam(value = "sort", required = false) Boolean sort) { + List list = commentService.getCommentTree(projectId, sort); + return success(list); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出评论 Excel") + @PreAuthorize("@ss.hasPermission('license:comment:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportCommentExcel(@Valid CommentListReqVO listReqVO, + HttpServletResponse response) throws IOException { + List list = commentService.getCommentList(listReqVO); + // 导出 Excel + ExcelUtils.write(response, "评论.xls", "数据", CommentRespVO.class, + BeanUtils.toBean(list, CommentRespVO.class)); + } + +} \ No newline at end of file diff --git a/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentListReqVO.java b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentListReqVO.java new file mode 100644 index 0000000..017747a --- /dev/null +++ b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentListReqVO.java @@ -0,0 +1,32 @@ +package org.agt.module.license.controller.admin.comment.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import org.agt.framework.common.pojo.PageParam; +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; + +import static org.agt.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 评论列表 Request VO") +@Data +public class CommentListReqVO { + + @Schema(description = "项目ID", example = "18334") + private Long projectId; + + @Schema(description = "用户ID", example = "30248") + private Long userId; + + @Schema(description = "父ID", example = "20143") + private Long parentId; + + @Schema(description = "内容") + private String content; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentRespVO.java b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentRespVO.java new file mode 100644 index 0000000..5a63b3c --- /dev/null +++ b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentRespVO.java @@ -0,0 +1,39 @@ +package org.agt.module.license.controller.admin.comment.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; +import com.alibaba.excel.annotation.*; + +@Schema(description = "管理后台 - 评论 Response VO") +@Data +@ExcelIgnoreUnannotated +public class CommentRespVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "4294") + @ExcelProperty("主键") + private Long id; + + @Schema(description = "项目ID", example = "18334") + @ExcelProperty("项目ID") + private Long projectId; + + @Schema(description = "用户ID", example = "30248") + @ExcelProperty("用户ID") + private Long userId; + + @Schema(description = "父ID", example = "20143") + @ExcelProperty("父ID") + private Long parentId; + + @Schema(description = "内容") + @ExcelProperty("内容") + private String content; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentSaveReqVO.java b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentSaveReqVO.java new file mode 100644 index 0000000..627582b --- /dev/null +++ b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentSaveReqVO.java @@ -0,0 +1,27 @@ +package org.agt.module.license.controller.admin.comment.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import jakarta.validation.constraints.*; + +@Schema(description = "管理后台 - 评论新增/修改 Request VO") +@Data +public class CommentSaveReqVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "4294") + private Long id; + + @Schema(description = "项目ID", example = "18334") + private Long projectId; + + @Schema(description = "用户ID", example = "30248") + private Long userId; + + @Schema(description = "父ID", example = "20143") + private Long parentId; + + @Schema(description = "内容") + private String content; + +} \ No newline at end of file diff --git a/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentTreeRespVO.java b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentTreeRespVO.java new file mode 100644 index 0000000..833100a --- /dev/null +++ b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/controller/admin/comment/vo/CommentTreeRespVO.java @@ -0,0 +1,61 @@ +package org.agt.module.license.controller.admin.comment.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 评论 树形Response VO") +@Data +@ExcelIgnoreUnannotated +public class CommentTreeRespVO { + + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "4294") + @ExcelProperty("主键") + private Long id; + + @Schema(description = "项目ID", example = "18334") + @ExcelProperty("项目ID") + private Long projectId; + + @Schema(description = "用户ID", example = "30248") + @ExcelProperty("用户ID") + private Long userId; + + @Schema(description = "父ID", example = "20143") + @ExcelProperty("父ID") + private Long parentId; + + @Schema(description = "内容") + @ExcelProperty("内容") + private String content; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("更新时间") + private LocalDateTime updateTime; + + @Schema(description = "评论用户") + private String author; + + @Schema(description = "评论用户头像") + private String avatar; + + @Schema(description = "回复用户ID", example = "30248") + private Long replyUserId; + + @Schema(description = "回复用户") + private String replyUser; + + @Schema(description = "深度") + private Integer depth; + + @Schema(description = "子列表") + private List children; +} \ No newline at end of file diff --git a/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/dal/dataobject/comment/CommentDO.java b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/dal/dataobject/comment/CommentDO.java new file mode 100644 index 0000000..b228378 --- /dev/null +++ b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/dal/dataobject/comment/CommentDO.java @@ -0,0 +1,53 @@ +package org.agt.module.license.dal.dataobject.comment; + +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.agt.framework.mybatis.core.dataobject.BaseDO; + +/** + * 评论 DO + * + * @author 管理员 + */ +@TableName("lic_comment") +@KeySequence("lic_comment_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CommentDO extends BaseDO { + + public static final Long PARENT_ID_ROOT = 0L; + + /** + * 主键 + */ + @TableId + private Long id; + /** + * 项目ID + */ + private Long projectId; + /** + * 用户ID + */ + private Long userId; + /** + * 父ID + */ + private Long parentId; + /** + * 内容 + */ + private String content; + +} \ No newline at end of file diff --git a/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/dal/mysql/comment/CommentMapper.java b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/dal/mysql/comment/CommentMapper.java new file mode 100644 index 0000000..7f5d977 --- /dev/null +++ b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/dal/mysql/comment/CommentMapper.java @@ -0,0 +1,40 @@ +package org.agt.module.license.dal.mysql.comment; + +import org.agt.framework.mybatis.core.mapper.BaseMapperX; +import org.agt.framework.mybatis.core.query.LambdaQueryWrapperX; +import org.agt.module.license.controller.admin.comment.vo.CommentListReqVO; +import org.agt.module.license.controller.admin.comment.vo.CommentTreeRespVO; +import org.agt.module.license.dal.dataobject.comment.CommentDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 评论 Mapper + * + * @author 管理员 + */ +@Mapper +public interface CommentMapper extends BaseMapperX { + + default List selectList(CommentListReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(CommentDO::getProjectId, reqVO.getProjectId()) + .eqIfPresent(CommentDO::getUserId, reqVO.getUserId()) + .eqIfPresent(CommentDO::getParentId, reqVO.getParentId()) + .eqIfPresent(CommentDO::getContent, reqVO.getContent()) + .betweenIfPresent(CommentDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(CommentDO::getId)); + } + + default CommentDO selectByParentIdAndContent(Long parentId, String content) { + return selectOne(CommentDO::getParentId, parentId, CommentDO::getContent, content); + } + + default Long selectCountByParentId(Long parentId) { + return selectCount(CommentDO::getParentId, parentId); + } + + List getCommentList(@Param("projectId") Long projectId); +} \ No newline at end of file diff --git a/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/service/comment/CommentService.java b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/service/comment/CommentService.java new file mode 100644 index 0000000..fc5f5ad --- /dev/null +++ b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/service/comment/CommentService.java @@ -0,0 +1,57 @@ +package org.agt.module.license.service.comment; + +import jakarta.validation.Valid; +import org.agt.module.license.controller.admin.comment.vo.CommentListReqVO; +import org.agt.module.license.controller.admin.comment.vo.CommentSaveReqVO; +import org.agt.module.license.controller.admin.comment.vo.CommentTreeRespVO; +import org.agt.module.license.dal.dataobject.comment.CommentDO; + +import java.util.List; + +/** + * 评论 Service 接口 + * + * @author 管理员 + */ +public interface CommentService { + + /** + * 创建评论 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createComment(@Valid CommentSaveReqVO createReqVO); + + /** + * 更新评论 + * + * @param updateReqVO 更新信息 + */ + void updateComment(@Valid CommentSaveReqVO updateReqVO); + + /** + * 删除评论 + * + * @param id 编号 + */ + void deleteComment(Long id); + + /** + * 获得评论 + * + * @param id 编号 + * @return 评论 + */ + CommentDO getComment(Long id); + + /** + * 获得评论列表 + * + * @param listReqVO 查询条件 + * @return 评论列表 + */ + List getCommentList(CommentListReqVO listReqVO); + + List getCommentTree(Long projectId, Boolean sort); +} \ No newline at end of file diff --git a/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/service/comment/CommentServiceImpl.java b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/service/comment/CommentServiceImpl.java new file mode 100644 index 0000000..e78b6de --- /dev/null +++ b/agt-module-license/agt-module-license-server/src/main/java/org/agt/module/license/service/comment/CommentServiceImpl.java @@ -0,0 +1,183 @@ +package org.agt.module.license.service.comment; + +import jakarta.annotation.Resource; +import org.agt.framework.common.util.object.BeanUtils; +import org.agt.framework.web.core.util.WebFrameworkUtils; +import org.agt.module.license.controller.admin.comment.vo.CommentListReqVO; +import org.agt.module.license.controller.admin.comment.vo.CommentSaveReqVO; +import org.agt.module.license.controller.admin.comment.vo.CommentTreeRespVO; +import org.agt.module.license.dal.dataobject.comment.CommentDO; +import org.agt.module.license.dal.mysql.comment.CommentMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.agt.framework.common.exception.util.ServiceExceptionUtil.exception; +import static org.agt.module.license.enums.ErrorCodeConstants.COMMENT_CONTENT_DUPLICATE; +import static org.agt.module.license.enums.ErrorCodeConstants.COMMENT_EXITS_CHILDREN; +import static org.agt.module.license.enums.ErrorCodeConstants.COMMENT_NOT_EXISTS; +import static org.agt.module.license.enums.ErrorCodeConstants.COMMENT_PARENT_ERROR; +import static org.agt.module.license.enums.ErrorCodeConstants.COMMENT_PARENT_IS_CHILD; +import static org.agt.module.license.enums.ErrorCodeConstants.COMMENT_PARENT_NOT_EXITS; + +/** + * 评论 Service 实现类 + * + * @author 管理员 + */ +@Service +@Validated +public class CommentServiceImpl implements CommentService { + + @Resource + private CommentMapper commentMapper; + + @Override + public Long createComment(CommentSaveReqVO createReqVO) { + createReqVO.setUserId(WebFrameworkUtils.getLoginUserId()); + if (createReqVO.getParentId() == null) { + createReqVO.setParentId(0L); + } + // 校验父ID的有效性 + validateParentComment(null, createReqVO.getParentId()); + // 校验内容的唯一性 + validateCommentContentUnique(null, createReqVO.getParentId(), createReqVO.getContent()); + + // 插入 + CommentDO comment = BeanUtils.toBean(createReqVO, CommentDO.class); + commentMapper.insert(comment); + // 返回 + return comment.getId(); + } + + @Override + public void updateComment(CommentSaveReqVO updateReqVO) { + // 校验存在 + validateCommentExists(updateReqVO.getId()); + // 校验父ID的有效性 + validateParentComment(updateReqVO.getId(), updateReqVO.getParentId()); + // 校验内容的唯一性 + validateCommentContentUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getContent()); + + // 更新 + CommentDO updateObj = BeanUtils.toBean(updateReqVO, CommentDO.class); + commentMapper.updateById(updateObj); + } + + @Override + public void deleteComment(Long id) { + // 校验存在 + validateCommentExists(id); + // 校验是否有子评论 + if (commentMapper.selectCountByParentId(id) > 0) { + throw exception(COMMENT_EXITS_CHILDREN); + } + // 删除 + commentMapper.deleteById(id); + } + + private void validateCommentExists(Long id) { + if (commentMapper.selectById(id) == null) { + throw exception(COMMENT_NOT_EXISTS); + } + } + + private void validateParentComment(Long id, Long parentId) { + if (parentId == null || CommentDO.PARENT_ID_ROOT.equals(parentId)) { + return; + } + // 1. 不能设置自己为父评论 + if (Objects.equals(id, parentId)) { + throw exception(COMMENT_PARENT_ERROR); + } + // 2. 父评论不存在 + CommentDO parentComment = commentMapper.selectById(parentId); + if (parentComment == null) { + throw exception(COMMENT_PARENT_NOT_EXITS); + } + // 3. 递归校验父评论,如果父评论是自己的子评论,则报错,避免形成环路 + if (id == null) { // id 为空,说明新增,不需要考虑环路 + return; + } + for (int i = 0; i < Short.MAX_VALUE; i++) { + // 3.1 校验环路 + parentId = parentComment.getParentId(); + if (Objects.equals(id, parentId)) { + throw exception(COMMENT_PARENT_IS_CHILD); + } + // 3.2 继续递归下一级父评论 + if (parentId == null || CommentDO.PARENT_ID_ROOT.equals(parentId)) { + break; + } + parentComment = commentMapper.selectById(parentId); + if (parentComment == null) { + break; + } + } + } + + private void validateCommentContentUnique(Long id, Long parentId, String content) { + CommentDO comment = commentMapper.selectByParentIdAndContent(parentId, content); + if (comment == null) { + return; + } + // 如果 id 为空,说明不用比较是否为相同 id 的评论 + if (id == null) { + throw exception(COMMENT_CONTENT_DUPLICATE); + } + if (!Objects.equals(comment.getId(), id)) { + throw exception(COMMENT_CONTENT_DUPLICATE); + } + } + + @Override + public CommentDO getComment(Long id) { + return commentMapper.selectById(id); + } + + @Override + public List getCommentList(CommentListReqVO listReqVO) { + return commentMapper.selectList(listReqVO); + } + + @Override + public List getCommentTree(Long projectId, Boolean sort) { + List comments = commentMapper.getCommentList(projectId); + List commentTree = comments.stream().filter(c -> c.getParentId() == 0) + .peek(c -> { + c.setDepth(1); + c.setChildren(getChildren(c, comments, 1)); + }) + .sorted(sort != null && sort ? Comparator.comparing(CommentTreeRespVO::getUpdateTime): Comparator.comparing(CommentTreeRespVO::getUpdateTime).reversed()) + .toList(); + return commentTree.stream().filter(c -> c.getParentId() == 0) + .peek(c -> { + List childrenMerge = c.getChildren(); + addChildrenMerge(c, comments, childrenMerge); + childrenMerge = childrenMerge.stream() + .sorted(sort != null && sort ? Comparator.comparing(CommentTreeRespVO::getUpdateTime): Comparator.comparing(CommentTreeRespVO::getUpdateTime).reversed()) + .collect(Collectors.toList()); + c.setChildren(childrenMerge); + }).toList(); + } + + public static List getChildren(CommentTreeRespVO root, List all, int i) { + return all.stream().filter(c -> Objects.equals(c.getParentId(), root.getId())) + .peek(c -> { + c.setDepth(i+1); + c.setChildren(getChildren(c, all, i+1)); + }).collect(Collectors.toList()); + } + + public static void addChildrenMerge(CommentTreeRespVO root, List all, List children) { + all.stream().filter(c -> Objects.equals(c.getParentId(), root.getId())) + .forEach(c -> { + children.addAll(c.getChildren()); + addChildrenMerge(c, all, children); + }); + } +} \ No newline at end of file diff --git a/agt-module-license/agt-module-license-server/src/main/resources/mapper/comment/CommentMapper.xml b/agt-module-license/agt-module-license-server/src/main/resources/mapper/comment/CommentMapper.xml new file mode 100644 index 0000000..81dda6f --- /dev/null +++ b/agt-module-license/agt-module-license-server/src/main/resources/mapper/comment/CommentMapper.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file