feat(comment): 新增评论功能模块
- 新增评论发布接口,支持内容和图片评论 - 新增评论和评论点赞数据表结构及对应DO、Mapper - 新增评论相关DTO、VO及校验规则 - 新增评论服务接口及实现,集成RocketMQ异步发送 - 新增全局异常处理器,统一处理参数校验和业务异常 - 配置网关路由,支持/comment/**路径转发至评论服务 - 新增RocketMQ配置类,启用MQ自动配置 - 添加评论发布HTTP测试用例
This commit is contained in:
66
.idea/MyBatisCodeHelperDatasource.xml
generated
66
.idea/MyBatisCodeHelperDatasource.xml
generated
@@ -11,11 +11,11 @@
|
|||||||
<option name="generateServiceInterface" value="true" />
|
<option name="generateServiceInterface" value="true" />
|
||||||
<option name="insertMethodEnabled" value="false" />
|
<option name="insertMethodEnabled" value="false" />
|
||||||
<option name="insertSelectiveMethodEnabled" value="false" />
|
<option name="insertSelectiveMethodEnabled" value="false" />
|
||||||
<option name="javaMapperPackage" value="com.hanserwei.hannote.note.biz.domain.mapper" />
|
<option name="javaMapperPackage" value="com.hanserwei.hannote.comment.biz.domain.mapper" />
|
||||||
<option name="javaMapperPath" value="$PROJECT_DIR$/han-note-note/han-note-note-biz/src/main/java" />
|
<option name="javaMapperPath" value="$PROJECT_DIR$/han-note-comment/han-note-comment-biz/src/main/java" />
|
||||||
<option name="javaModelPackage" value="com.hanserwei.hannote.note.biz.domain.dataobject" />
|
<option name="javaModelPackage" value="com.hanserwei.hannote.comment.biz.domain.dataobject" />
|
||||||
<option name="javaModelPath" value="$PROJECT_DIR$/han-note-note/han-note-note-biz/src/main/java" />
|
<option name="javaModelPath" value="$PROJECT_DIR$/han-note-comment/han-note-comment-biz/src/main/java" />
|
||||||
<option name="lastDatabaseCrudChooseModuleName" value="han-note-note-biz" />
|
<option name="lastDatabaseCrudChooseModuleName" value="han-note-comment-biz" />
|
||||||
<option name="lombokAllArgConstructor" value="true" />
|
<option name="lombokAllArgConstructor" value="true" />
|
||||||
<option name="lombokDataAnnotation" value="true" />
|
<option name="lombokDataAnnotation" value="true" />
|
||||||
<option name="lombokNoArgsConstructor" value="true" />
|
<option name="lombokNoArgsConstructor" value="true" />
|
||||||
@@ -46,6 +46,22 @@
|
|||||||
</UserPackageAndPathInfoByModule>
|
</UserPackageAndPathInfoByModule>
|
||||||
</value>
|
</value>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry key="han-note-comment-biz">
|
||||||
|
<value>
|
||||||
|
<UserPackageAndPathInfoByModule>
|
||||||
|
<option name="javaMapperPackage" value="com.hanserwei.hannote.comment.biz.domain.mapper" />
|
||||||
|
<option name="javaMapperPath" value="$PROJECT_DIR$/han-note-comment/han-note-comment-biz/src/main/java" />
|
||||||
|
<option name="javaModelPacakge" value="com.hanserwei.hannote.comment.biz.domain.dataobject" />
|
||||||
|
<option name="javaModelPath" value="$PROJECT_DIR$/han-note-comment/han-note-comment-biz/src/main/java" />
|
||||||
|
<option name="javaServiceInterfacePackage" value="com.hanserwei.hannote.comment.biz.service" />
|
||||||
|
<option name="javaServiceInterfacePath" value="$PROJECT_DIR$/han-note-comment/han-note-comment-biz/src/main/java" />
|
||||||
|
<option name="javaServicePackage" value="com.hanserwei.hannote.comment.biz.service.impl" />
|
||||||
|
<option name="javaServicePath" value="$PROJECT_DIR$/han-note-comment/han-note-comment-biz/src/main/java" />
|
||||||
|
<option name="xmlPackage" value="mapperxml" />
|
||||||
|
<option name="xmlPath" value="$PROJECT_DIR$/han-note-comment/han-note-comment-biz/src/main/resources" />
|
||||||
|
</UserPackageAndPathInfoByModule>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
<entry key="han-note-count-biz">
|
<entry key="han-note-count-biz">
|
||||||
<value>
|
<value>
|
||||||
<UserPackageAndPathInfoByModule>
|
<UserPackageAndPathInfoByModule>
|
||||||
@@ -122,6 +138,44 @@
|
|||||||
</TableGenerateConfig>
|
</TableGenerateConfig>
|
||||||
</value>
|
</value>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry key="han_note:t_comment">
|
||||||
|
<value>
|
||||||
|
<TableGenerateConfig>
|
||||||
|
<option name="deleteByPrimayKeyEnabled" value="false" />
|
||||||
|
<option name="generatedKey" value="id" />
|
||||||
|
<option name="insertMethodEnabled" value="false" />
|
||||||
|
<option name="insertSelectiveMethodEnabled" value="false" />
|
||||||
|
<option name="javaModelName" value="CommentDO" />
|
||||||
|
<option name="moduleName" value="han-note-comment-biz" />
|
||||||
|
<option name="mybatisplusIdType" value="AUTO" />
|
||||||
|
<option name="selectByPrimaryKeyEnabled" value="false" />
|
||||||
|
<option name="sequenceColumn" value="" />
|
||||||
|
<option name="sequenceId" value="" />
|
||||||
|
<option name="updateByPrimaryKeySelectiveEnabled" value="false" />
|
||||||
|
<option name="updateByPrimaykeyEnabled" value="false" />
|
||||||
|
<option name="useActualColumnName" value="false" />
|
||||||
|
</TableGenerateConfig>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
<entry key="han_note:t_comment_like">
|
||||||
|
<value>
|
||||||
|
<TableGenerateConfig>
|
||||||
|
<option name="deleteByPrimayKeyEnabled" value="false" />
|
||||||
|
<option name="generatedKey" value="id" />
|
||||||
|
<option name="insertMethodEnabled" value="false" />
|
||||||
|
<option name="insertSelectiveMethodEnabled" value="false" />
|
||||||
|
<option name="javaModelName" value="CommentLikeDO" />
|
||||||
|
<option name="moduleName" value="han-note-comment-biz" />
|
||||||
|
<option name="mybatisplusIdType" value="AUTO" />
|
||||||
|
<option name="selectByPrimaryKeyEnabled" value="false" />
|
||||||
|
<option name="sequenceColumn" value="" />
|
||||||
|
<option name="sequenceId" value="" />
|
||||||
|
<option name="updateByPrimaryKeySelectiveEnabled" value="false" />
|
||||||
|
<option name="updateByPrimaykeyEnabled" value="false" />
|
||||||
|
<option name="useActualColumnName" value="false" />
|
||||||
|
</TableGenerateConfig>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
<entry key="han_note:t_fans">
|
<entry key="han_note:t_fans">
|
||||||
<value>
|
<value>
|
||||||
<TableGenerateConfig>
|
<TableGenerateConfig>
|
||||||
@@ -375,7 +429,7 @@
|
|||||||
<option name="updateByPrimaykeyEnabled" value="false" />
|
<option name="updateByPrimaykeyEnabled" value="false" />
|
||||||
<option name="userMybatisPlus" value="true" />
|
<option name="userMybatisPlus" value="true" />
|
||||||
<option name="xmlMapperPackage" value="mapperxml" />
|
<option name="xmlMapperPackage" value="mapperxml" />
|
||||||
<option name="xmlMapperPath" value="$PROJECT_DIR$/han-note-note/han-note-note-biz/src/main/resources" />
|
<option name="xmlMapperPath" value="$PROJECT_DIR$/han-note-comment/han-note-comment-biz/src/main/resources" />
|
||||||
</ProjectProfile>
|
</ProjectProfile>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@@ -78,6 +78,13 @@
|
|||||||
<groupId>com.alibaba.cloud</groupId>
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Rocket MQ -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.rocketmq</groupId>
|
||||||
|
<artifactId>rocketmq-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.config;
|
||||||
|
|
||||||
|
import org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@Import(RocketMQAutoConfiguration.class)
|
||||||
|
public class RocketMQConfig {
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.constants;
|
||||||
|
|
||||||
|
public interface MQConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Topic: 评论发布
|
||||||
|
*/
|
||||||
|
String TOPIC_PUBLISH_COMMENT = "PublishCommentTopic";
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.controller;
|
||||||
|
|
||||||
|
import com.hanserwei.framework.biz.operationlog.aspect.ApiOperationLog;
|
||||||
|
import com.hanserwei.framework.common.response.Response;
|
||||||
|
import com.hanserwei.hannote.comment.biz.model.vo.PublishCommentReqVO;
|
||||||
|
import com.hanserwei.hannote.comment.biz.service.CommentService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/comment")
|
||||||
|
@Slf4j
|
||||||
|
public class CommentController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CommentService commentService;
|
||||||
|
|
||||||
|
@PostMapping("/publish")
|
||||||
|
@ApiOperationLog(description = "发布评论")
|
||||||
|
public Response<?> publishComment(@Validated @RequestBody PublishCommentReqVO publishCommentReqVO) {
|
||||||
|
return commentService.publishComment(publishCommentReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.domain.dataobject;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论表
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@TableName(value = "t_comment")
|
||||||
|
public class CommentDO {
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联的笔记ID
|
||||||
|
*/
|
||||||
|
@TableField(value = "note_id")
|
||||||
|
private Long noteId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布者用户ID
|
||||||
|
*/
|
||||||
|
@TableField(value = "user_id")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论内容UUID
|
||||||
|
*/
|
||||||
|
@TableField(value = "content_uuid")
|
||||||
|
private String contentUuid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内容是否为空(0:不为空 1:为空)
|
||||||
|
*/
|
||||||
|
@TableField(value = "is_content_empty")
|
||||||
|
private Boolean isContentEmpty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论附加图片URL
|
||||||
|
*/
|
||||||
|
@TableField(value = "image_url")
|
||||||
|
private String imageUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 级别(1:一级评论 2:二级评论)
|
||||||
|
*/
|
||||||
|
@TableField(value = "`level`")
|
||||||
|
private Integer level;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论被回复次数,仅一级评论需要
|
||||||
|
*/
|
||||||
|
@TableField(value = "reply_total")
|
||||||
|
private Long replyTotal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论被点赞次数
|
||||||
|
*/
|
||||||
|
@TableField(value = "like_total")
|
||||||
|
private Long likeTotal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父ID (若是对笔记的评论,则此字段存储笔记ID; 若是二级评论,则此字段存储一级评论的ID)
|
||||||
|
*/
|
||||||
|
@TableField(value = "parent_id")
|
||||||
|
private Long parentId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回复哪个的评论 (0表示是对笔记的评论,若是对他人评论的回复,则存储回复评论的ID)
|
||||||
|
*/
|
||||||
|
@TableField(value = "reply_comment_id")
|
||||||
|
private Long replyCommentId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回复的哪个用户, 存储用户ID
|
||||||
|
*/
|
||||||
|
@TableField(value = "reply_user_id")
|
||||||
|
private Long replyUserId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否置顶(0:不置顶 1:置顶)
|
||||||
|
*/
|
||||||
|
@TableField(value = "is_top")
|
||||||
|
private Boolean isTop;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "create_time")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "update_time")
|
||||||
|
private LocalDateTime updateTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.domain.dataobject;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论点赞表
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@TableName(value = "t_comment_like")
|
||||||
|
public class CommentLikeDO {
|
||||||
|
/**
|
||||||
|
* 主键ID
|
||||||
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户ID
|
||||||
|
*/
|
||||||
|
@TableField(value = "user_id")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论ID
|
||||||
|
*/
|
||||||
|
@TableField(value = "comment_id")
|
||||||
|
private Long commentId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@TableField(value = "create_time")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.domain.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface CommentDOMapper extends BaseMapper<CommentDO> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.domain.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentLikeDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface CommentLikeDOMapper extends BaseMapper<CommentLikeDO> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.enums;
|
||||||
|
|
||||||
|
import com.hanserwei.framework.common.exception.BaseExceptionInterface;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum ResponseCodeEnum implements BaseExceptionInterface {
|
||||||
|
|
||||||
|
// ----------- 通用异常状态码 -----------
|
||||||
|
SYSTEM_ERROR("COMMENT-10000", "出错啦,后台小哥正在努力修复中..."),
|
||||||
|
PARAM_NOT_VALID("COMMENT-10001", "参数错误"),
|
||||||
|
|
||||||
|
// ----------- 业务异常状态码 -----------
|
||||||
|
;
|
||||||
|
|
||||||
|
// 异常码
|
||||||
|
private final String errorCode;
|
||||||
|
// 错误信息
|
||||||
|
private final String errorMsg;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.exception;
|
||||||
|
|
||||||
|
import com.hanserwei.framework.common.exception.ApiException;
|
||||||
|
import com.hanserwei.framework.common.response.Response;
|
||||||
|
import com.hanserwei.hannote.comment.biz.enums.ResponseCodeEnum;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@SuppressWarnings("LoggingSimilarMessage")
|
||||||
|
@ControllerAdvice
|
||||||
|
@Slf4j
|
||||||
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 捕获自定义业务异常
|
||||||
|
*
|
||||||
|
* @return Response.fail(e)
|
||||||
|
*/
|
||||||
|
@ExceptionHandler({ApiException.class})
|
||||||
|
@ResponseBody
|
||||||
|
public Response<Object> handleApiException(HttpServletRequest request, ApiException e) {
|
||||||
|
log.warn("{} request fail, errorCode: {}, errorMessage: {}", request.getRequestURI(), e.getErrorCode(), e.getErrorMsg());
|
||||||
|
return Response.fail(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 捕获参数校验异常
|
||||||
|
*
|
||||||
|
* @return Response.fail(errorCode, errorMessage)
|
||||||
|
*/
|
||||||
|
@ExceptionHandler({MethodArgumentNotValidException.class})
|
||||||
|
@ResponseBody
|
||||||
|
public Response<Object> handleMethodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e) {
|
||||||
|
// 参数错误异常码
|
||||||
|
String errorCode = ResponseCodeEnum.PARAM_NOT_VALID.getErrorCode();
|
||||||
|
|
||||||
|
// 获取 BindingResult
|
||||||
|
BindingResult bindingResult = e.getBindingResult();
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
// 获取校验不通过的字段,并组合错误信息,格式为: email 邮箱格式不正确, 当前值: '123124qq.com';
|
||||||
|
Optional.of(bindingResult.getFieldErrors()).ifPresent(errors -> {
|
||||||
|
errors.forEach(error ->
|
||||||
|
sb.append(error.getField())
|
||||||
|
.append(" ")
|
||||||
|
.append(error.getDefaultMessage())
|
||||||
|
.append(", 当前值: '")
|
||||||
|
.append(error.getRejectedValue())
|
||||||
|
.append("'; ")
|
||||||
|
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 错误信息
|
||||||
|
String errorMessage = sb.toString();
|
||||||
|
|
||||||
|
log.warn("{} request error, errorCode: {}, errorMessage: {}", request.getRequestURI(), errorCode, errorMessage);
|
||||||
|
|
||||||
|
return Response.fail(errorCode, errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 捕获 guava 参数校验异常
|
||||||
|
*
|
||||||
|
* @return Response.fail(ResponseCodeEnum.PARAM_NOT_VALID)
|
||||||
|
*/
|
||||||
|
@ExceptionHandler({IllegalArgumentException.class})
|
||||||
|
@ResponseBody
|
||||||
|
public Response<Object> handleIllegalArgumentException(HttpServletRequest request, IllegalArgumentException e) {
|
||||||
|
// 参数错误异常码
|
||||||
|
String errorCode = ResponseCodeEnum.PARAM_NOT_VALID.getErrorCode();
|
||||||
|
|
||||||
|
// 错误信息
|
||||||
|
String errorMessage = e.getMessage();
|
||||||
|
|
||||||
|
log.warn("{} request error, errorCode: {}, errorMessage: {}", request.getRequestURI(), errorCode, errorMessage);
|
||||||
|
|
||||||
|
return Response.fail(errorCode, errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 其他类型异常
|
||||||
|
*
|
||||||
|
* @param request 请求
|
||||||
|
* @param e 异常
|
||||||
|
* @return Response.fail(ResponseCodeEnum.SYSTEM_ERROR)
|
||||||
|
*/
|
||||||
|
@ExceptionHandler({Exception.class})
|
||||||
|
@ResponseBody
|
||||||
|
public Response<Object> handleOtherException(HttpServletRequest request, Exception e) {
|
||||||
|
log.error("{} request error, ", request.getRequestURI(), e);
|
||||||
|
return Response.fail(ResponseCodeEnum.SYSTEM_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.model.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class PublishCommentMqDTO {
|
||||||
|
|
||||||
|
private Long noteId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论内容
|
||||||
|
*/
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论图片链接
|
||||||
|
*/
|
||||||
|
private String imageUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回复的哪个评论(评论 ID)
|
||||||
|
*/
|
||||||
|
private Long replyCommentId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布时间
|
||||||
|
*/
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布者 ID
|
||||||
|
*/
|
||||||
|
private Long creatorId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.model.vo;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class PublishCommentReqVO {
|
||||||
|
|
||||||
|
@NotNull(message = "笔记 ID 不能为空")
|
||||||
|
private Long noteId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论内容
|
||||||
|
*/
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论图片链接
|
||||||
|
*/
|
||||||
|
private String imageUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回复的哪个评论(评论 ID)
|
||||||
|
*/
|
||||||
|
private Long replyCommentId;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentLikeDO;
|
||||||
|
|
||||||
|
public interface CommentLikeService extends IService<CommentLikeDO> {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.hanserwei.framework.common.response.Response;
|
||||||
|
import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO;
|
||||||
|
import com.hanserwei.hannote.comment.biz.model.vo.PublishCommentReqVO;
|
||||||
|
|
||||||
|
public interface CommentService extends IService<CommentDO> {
|
||||||
|
/**
|
||||||
|
* 发布评论
|
||||||
|
*
|
||||||
|
* @param publishCommentReqVO 发布评论请求
|
||||||
|
* @return 响应
|
||||||
|
*/
|
||||||
|
Response<?> publishComment(PublishCommentReqVO publishCommentReqVO);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentLikeDO;
|
||||||
|
import com.hanserwei.hannote.comment.biz.domain.mapper.CommentLikeDOMapper;
|
||||||
|
import com.hanserwei.hannote.comment.biz.service.CommentLikeService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class CommentLikeServiceImpl extends ServiceImpl<CommentLikeDOMapper, CommentLikeDO> implements CommentLikeService {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package com.hanserwei.hannote.comment.biz.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.hanserwei.framework.biz.context.holder.LoginUserContextHolder;
|
||||||
|
import com.hanserwei.framework.common.response.Response;
|
||||||
|
import com.hanserwei.framework.common.utils.JsonUtils;
|
||||||
|
import com.hanserwei.hannote.comment.biz.constants.MQConstants;
|
||||||
|
import com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO;
|
||||||
|
import com.hanserwei.hannote.comment.biz.domain.mapper.CommentDOMapper;
|
||||||
|
import com.hanserwei.hannote.comment.biz.model.dto.PublishCommentMqDTO;
|
||||||
|
import com.hanserwei.hannote.comment.biz.model.vo.PublishCommentReqVO;
|
||||||
|
import com.hanserwei.hannote.comment.biz.service.CommentService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.rocketmq.client.producer.SendCallback;
|
||||||
|
import org.apache.rocketmq.client.producer.SendResult;
|
||||||
|
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||||
|
import org.springframework.messaging.Message;
|
||||||
|
import org.springframework.messaging.support.MessageBuilder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class CommentServiceImpl extends ServiceImpl<CommentDOMapper, CommentDO> implements CommentService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RocketMQTemplate rocketMQTemplate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response<?> publishComment(PublishCommentReqVO publishCommentReqVO) {
|
||||||
|
// 评论正文
|
||||||
|
String content = publishCommentReqVO.getContent();
|
||||||
|
// 附近图片
|
||||||
|
String imageUrl = publishCommentReqVO.getImageUrl();
|
||||||
|
|
||||||
|
// 评论内容和图片不能同时为空
|
||||||
|
Preconditions.checkArgument(StringUtils.isNotBlank(content) || StringUtils.isNotBlank(imageUrl),
|
||||||
|
"评论正文和图片不能同时为空");
|
||||||
|
|
||||||
|
// 发布者ID
|
||||||
|
Long creatorId = LoginUserContextHolder.getUserId();
|
||||||
|
|
||||||
|
// 发送消息
|
||||||
|
// 构造MQ消息体
|
||||||
|
PublishCommentMqDTO publishCommentMqDTO = PublishCommentMqDTO.builder()
|
||||||
|
.noteId(publishCommentReqVO.getNoteId())
|
||||||
|
.content(content)
|
||||||
|
.imageUrl(imageUrl)
|
||||||
|
.replyCommentId(publishCommentReqVO.getReplyCommentId())
|
||||||
|
.createTime(LocalDateTime.now())
|
||||||
|
.creatorId(creatorId)
|
||||||
|
.build();
|
||||||
|
// 构建消息对象,并将 DTO 转成 Json 字符串设置到消息体中
|
||||||
|
Message<String> message = MessageBuilder
|
||||||
|
.withPayload(JsonUtils.toJsonString(publishCommentMqDTO))
|
||||||
|
.build();
|
||||||
|
// 异步发送 MQ 消息,提升接口响应速度
|
||||||
|
rocketMQTemplate.asyncSend(MQConstants.TOPIC_PUBLISH_COMMENT, message, new SendCallback() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(SendResult sendResult) {
|
||||||
|
log.info("==> 【评论发布】MQ 发送成功,SendResult: {}", sendResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onException(Throwable throwable) {
|
||||||
|
log.error("==> 【评论发布】MQ 发送异常: ", throwable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Response.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.hanserwei.hannote.comment.biz.domain.mapper.CommentDOMapper">
|
||||||
|
<resultMap id="BaseResultMap" type="com.hanserwei.hannote.comment.biz.domain.dataobject.CommentDO">
|
||||||
|
<!--@mbg.generated-->
|
||||||
|
<!--@Table t_comment-->
|
||||||
|
<id column="id" jdbcType="BIGINT" property="id" />
|
||||||
|
<result column="note_id" jdbcType="BIGINT" property="noteId" />
|
||||||
|
<result column="user_id" jdbcType="BIGINT" property="userId" />
|
||||||
|
<result column="content_uuid" jdbcType="VARCHAR" property="contentUuid" />
|
||||||
|
<result column="is_content_empty" jdbcType="BIT" property="isContentEmpty" />
|
||||||
|
<result column="image_url" jdbcType="VARCHAR" property="imageUrl" />
|
||||||
|
<result column="level" jdbcType="TINYINT" property="level" />
|
||||||
|
<result column="reply_total" jdbcType="BIGINT" property="replyTotal" />
|
||||||
|
<result column="like_total" jdbcType="BIGINT" property="likeTotal" />
|
||||||
|
<result column="parent_id" jdbcType="BIGINT" property="parentId" />
|
||||||
|
<result column="reply_comment_id" jdbcType="BIGINT" property="replyCommentId" />
|
||||||
|
<result column="reply_user_id" jdbcType="BIGINT" property="replyUserId" />
|
||||||
|
<result column="is_top" jdbcType="TINYINT" property="isTop" />
|
||||||
|
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||||
|
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
|
||||||
|
</resultMap>
|
||||||
|
<sql id="Base_Column_List">
|
||||||
|
<!--@mbg.generated-->
|
||||||
|
id, note_id, user_id, content_uuid, is_content_empty, image_url, `level`, reply_total,
|
||||||
|
like_total, parent_id, reply_comment_id, reply_user_id, is_top, create_time, update_time
|
||||||
|
</sql>
|
||||||
|
</mapper>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.hanserwei.hannote.comment.biz.domain.mapper.CommentLikeDOMapper">
|
||||||
|
<resultMap id="BaseResultMap" type="com.hanserwei.hannote.comment.biz.domain.dataobject.CommentLikeDO">
|
||||||
|
<!--@mbg.generated-->
|
||||||
|
<!--@Table t_comment_like-->
|
||||||
|
<id column="id" jdbcType="BIGINT" property="id" />
|
||||||
|
<result column="user_id" jdbcType="BIGINT" property="userId" />
|
||||||
|
<result column="comment_id" jdbcType="BIGINT" property="commentId" />
|
||||||
|
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
|
||||||
|
</resultMap>
|
||||||
|
<sql id="Base_Column_List">
|
||||||
|
<!--@mbg.generated-->
|
||||||
|
id, user_id, comment_id, create_time
|
||||||
|
</sql>
|
||||||
|
</mapper>
|
||||||
@@ -28,6 +28,12 @@ spring:
|
|||||||
- Path=/relation/**
|
- Path=/relation/**
|
||||||
filters:
|
filters:
|
||||||
- StripPrefix=1
|
- StripPrefix=1
|
||||||
|
- id: comment
|
||||||
|
uri: lb://han-note-comment
|
||||||
|
predicates:
|
||||||
|
- Path=/comment/**
|
||||||
|
filters:
|
||||||
|
- StripPrefix=1
|
||||||
data:
|
data:
|
||||||
redis:
|
redis:
|
||||||
database: 5 # Redis 数据库索引(默认为 0)
|
database: 5 # Redis 数据库索引(默认为 0)
|
||||||
|
|||||||
@@ -290,3 +290,14 @@ Content-Type: application/json
|
|||||||
"keyword": "憨憨",
|
"keyword": "憨憨",
|
||||||
"pageNo": 1
|
"pageNo": 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
###
|
||||||
|
POST http://localhost:8000/comment/comment/publish
|
||||||
|
Content-Type: application/json
|
||||||
|
Authorization: Bearer {{token}}
|
||||||
|
|
||||||
|
{
|
||||||
|
"noteId": 1862481582414102549,
|
||||||
|
"content": "这是一个评论",
|
||||||
|
"imageUrl": "https://cdn.pixabay.com/photo/2025/10/05/15/06/autumn-9875155_1280.jpg"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user