1.新增评论回复
1.EasyCode生成代码
2.SaveShareCommentReplyReq.java
package com. sunxiansheng. circle. api. req ;
import lombok. Getter ;
import lombok. Setter ;
import java. io. Serializable ;
import java. util. List ;
@Getter
@Setter
public class SaveShareCommentReplyReq implements Serializable {
private static final long serialVersionUID = 1L ;
private Long momentId;
private Integer replyType;
private Long targetId;
private String content;
private List < String > picUrlList;
}
3.ShareCommentReplyController.java
package com. sunxiansheng. circle. server. controller ;
import com. alibaba. fastjson. JSON ;
import com. baomidou. mybatisplus. core. conditions. query. LambdaQueryWrapper ;
import com. baomidou. mybatisplus. core. toolkit. Wrappers ;
import com. google. common. base. Preconditions ;
import com. sunxiansheng. circle. api. common. Result ;
import com. sunxiansheng. circle. api. req. SaveShareCommentReplyReq ;
import com. sunxiansheng. circle. server. entity. po. ShareCommentReply ;
import com. sunxiansheng. circle. server. entity. po. ShareMoment ;
import com. sunxiansheng. circle. server. mapper. ShareMomentMapper ;
import com. sunxiansheng. circle. server. service. ShareCommentReplyService ;
import com. sunxiansheng. circle. server. entity. page. PageResult ;
import com. sunxiansheng. circle. server. service. ShareMomentService ;
import com. sunxiansheng. circle. server. util. LoginUtil ;
import com. sunxiansheng. practice. api. enums. IsDeleteFlagEnum ;
import lombok. extern. slf4j. Slf4j ;
import org. springframework. web. bind. annotation. * ;
import javax. annotation. Resource ;
import java. util. List ;
import java. util. Objects ;
@RestController
@RequestMapping ( "/share/comment" )
@Slf4j
public class ShareCommentReplyController {
@Resource
private ShareCommentReplyService shareCommentReplyService;
@Resource
private ShareMomentService shareMomentService;
@PostMapping ( value = "/save" )
public Result < Boolean > save ( @RequestBody SaveShareCommentReplyReq req) {
try {
if ( log. isInfoEnabled ( ) ) {
log. info ( "发布内容入参{}" , JSON . toJSONString ( req) ) ;
}
Preconditions . checkArgument ( Objects . nonNull ( req) , "参数不能为空!" ) ;
Preconditions . checkArgument ( Objects . nonNull ( req. getReplyType ( ) ) , "类型不能为空!" ) ;
Preconditions . checkArgument ( Objects . nonNull ( req. getMomentId ( ) ) , "内容ID不能为空!" ) ;
ShareMoment moment = shareMomentService. queryById ( req. getMomentId ( ) ) ;
Preconditions . checkArgument ( ( Objects . nonNull ( moment) && moment. getIsDeleted ( ) != IsDeleteFlagEnum . DELETED . getCode ( ) ) , "非法内容!" ) ;
Preconditions . checkArgument ( ( Objects . nonNull ( req. getContent ( ) ) || Objects . nonNull ( req. getPicUrlList ( ) ) ) , "内容不能为空!" ) ;
Boolean result = shareCommentReplyService. saveComment ( req) ;
if ( log. isInfoEnabled ( ) ) {
log. info ( "发布内容{}" , JSON . toJSONString ( result) ) ;
}
return Result . ok ( result) ;
} catch ( IllegalArgumentException e) {
log. error ( "参数异常!错误原因{}" , e. getMessage ( ) , e) ;
return Result . fail ( e. getMessage ( ) ) ;
} catch ( Exception e) {
log. error ( "发布内容异常!错误原因{}" , e. getMessage ( ) , e) ;
return Result . fail ( "发布内容异常!" ) ;
}
}
}
4.ShareCommentReplyService.java
Boolean saveComment ( SaveShareCommentReplyReq req) ;
5.ShareCommentReplyServiceImpl.java
@Override
@Transactional ( rollbackFor = Exception . class )
public Boolean saveComment ( SaveShareCommentReplyReq req) {
Long momentId = req. getMomentId ( ) ;
Integer replyType = req. getReplyType ( ) ;
Long targetId = req. getTargetId ( ) ;
String content = req. getContent ( ) ;
List < String > picUrlList = req. getPicUrlList ( ) ;
ShareCommentReply shareCommentReply = new ShareCommentReply ( ) ;
shareCommentReply. setMomentId ( Math . toIntExact ( momentId) ) ;
shareCommentReply. setReplyType ( replyType) ;
String loginId = LoginUtil . getLoginId ( ) ;
ShareMoment shareMoment = shareMomentMapper. queryById ( momentId) ;
String shareMomentAuthor = shareMoment. getCreatedBy ( ) ;
Integer isAuthor = Objects . nonNull ( shareMomentAuthor) && Objects . equals ( loginId, shareMomentAuthor) ? 1 : 0 ;
if ( replyType == 1 ) {
shareCommentReply. setToId ( targetId) ;
shareCommentReply. setToUser ( loginId) ;
shareCommentReply. setToUserAuthor ( isAuthor) ;
shareCommentReply. setParentId ( - 1L ) ;
} else {
shareCommentReply. setReplyId ( targetId) ;
shareCommentReply. setReplyUser ( loginId) ;
shareCommentReply. setReplayAuthor ( isAuthor) ;
shareCommentReply. setParentId ( targetId) ;
}
shareCommentReply. setContent ( content) ;
if ( ! CollectionUtils . isEmpty ( picUrlList) ) {
shareCommentReply. setPicUrls ( JSON . toJSONString ( picUrlList) ) ;
}
shareCommentReply. setCreatedBy ( loginId) ;
shareCommentReply. setCreatedTime ( new Date ( ) ) ;
shareCommentReply. setIsDeleted ( 0 ) ;
shareMomentMapper. incrReplyCount ( momentId, 1 ) ;
int insert = shareCommentReplyMapper. insert ( shareCommentReply) ;
return insert > 0 ;
}
6.ShareMomentMapper.java 增加动态回复数
void incrReplyCount ( @Param ( "momentId" ) Long momentId, @Param ( "count" ) int count) ;
7.ShareMomentMapper.xml
< update id= "incrReplyCount" >
update share_moment
set reply_count = reply_count + #{ count}
where id = #{ momentId}
and is_deleted = 0
< / update>
8.测试
1.评论
2.评论记录增加
3.动态的回复数加一
4.回复 targetId 指向评论id
5.评论记录加一,并且parentId为被回复的评论的id
6.动态的回复数加一
2.查询树型评论回复
1.GetShareCommentReq.java
package com. sunxiansheng. circle. api. req ;
import lombok. Getter ;
import lombok. Setter ;
import java. io. Serializable ;
@Getter
@Setter
public class GetShareCommentReq implements Serializable {
private Long id;
}
2.ShareCommentReplyVO.java
package com. sunxiansheng. circle. api. vo ;
import lombok. Getter ;
import lombok. Setter ;
import javax. swing. tree. TreeNode ;
import java. io. Serializable ;
import java. util. List ;
@Getter
@Setter
public class ShareCommentReplyVO implements Serializable {
private static final long serialVersionUID = 1L ;
private Long id;
private Long momentId;
private Integer replyType;
private String content;
private List < String > picUrlList;
private String fromId;
private String toId;
private Long parentId;
private String userName;
private String avatar;
private long createdTime;
private List < ShareCommentReplyVO > children;
}
3.ShareCommentReplyController.java
@PostMapping ( value = "/list" )
public Result < List < ShareCommentReplyVO > > list ( @RequestBody GetShareCommentReq req) {
try {
if ( log. isInfoEnabled ( ) ) {
log. info ( "获取鸡圈评论内容入参{}" , JSON . toJSONString ( req) ) ;
}
Preconditions . checkArgument ( Objects . nonNull ( req) , "参数不能为空!" ) ;
Preconditions . checkArgument ( Objects . nonNull ( req. getId ( ) ) , "内容ID不能为空!" ) ;
List < ShareCommentReplyVO > result = shareCommentReplyService. listComment ( req) ;
if ( log. isInfoEnabled ( ) ) {
log. info ( "获取鸡圈评论内容{}" , JSON . toJSONString ( result) ) ;
}
return Result . ok ( result) ;
} catch ( IllegalArgumentException e) {
log. error ( "参数异常!错误原因{}" , e. getMessage ( ) , e) ;
return Result . fail ( e. getMessage ( ) ) ;
} catch ( Exception e) {
log. error ( "获取鸡圈评论内容异常!错误原因{}" , e. getMessage ( ) , e) ;
return Result . fail ( "获取鸡圈评论内容异常!" ) ;
}
}
4.ShareCommentReplyService.java
List < ShareCommentReplyVO > listComment ( GetShareCommentReq req) ;
5.ShareCommentReplyServiceImpl.java(树工具具体使用)
@Override
public List < ShareCommentReplyVO > listComment ( GetShareCommentReq req) {
Long momentId = req. getId ( ) ;
ShareCommentReply shareCommentReply = new ShareCommentReply ( ) ;
shareCommentReply. setIsDeleted ( 0 ) ;
shareCommentReply. setMomentId ( Math . toIntExact ( momentId) ) ;
List < ShareCommentReply > shareCommentReplies = shareCommentReplyMapper. queryAllByLimit ( shareCommentReply) ;
List < ShareCommentReplyVO > list = shareCommentReplies. stream ( ) . map (
shareCommentReplyItem -> {
ShareCommentReplyVO shareCommentReplyVO = new ShareCommentReplyVO ( ) ;
shareCommentReplyVO. setId ( shareCommentReplyItem. getId ( ) ) ;
shareCommentReplyVO. setMomentId ( Long . valueOf ( shareCommentReplyItem. getMomentId ( ) ) ) ;
shareCommentReplyVO. setReplyType ( shareCommentReplyItem. getReplyType ( ) ) ;
shareCommentReplyVO. setContent ( shareCommentReplyItem. getContent ( ) ) ;
String picUrls = shareCommentReplyItem. getPicUrls ( ) ;
if ( StringUtils . isNotEmpty ( picUrls) ) {
shareCommentReplyVO. setPicUrlList ( JSON . parseArray ( picUrls, String . class ) ) ;
}
String createdBy = shareCommentReplyItem. getCreatedBy ( ) ;
if ( shareCommentReplyItem. getReplyType ( ) == 2 ) {
shareCommentReplyVO. setFromId ( createdBy) ;
shareCommentReplyVO. setToId ( shareCommentReplyItem. getToUser ( ) ) ;
}
shareCommentReplyVO. setParentId ( shareCommentReplyItem. getParentId ( ) ) ;
shareCommentReplyVO. setUserName ( createdBy) ;
shareCommentReplyVO. setCreatedTime ( shareCommentReplyItem. getCreatedTime ( ) . getTime ( ) ) ;
if ( StringUtils . isNotEmpty ( createdBy) ) {
UserInfo userInfo = userRpc. getUserInfo ( createdBy) ;
shareCommentReplyVO. setAvatar ( userInfo. getAvatar ( ) ) ;
}
return shareCommentReplyVO;
}
) . collect ( Collectors . toList ( ) ) ;
TreeBuilderConfig < ShareCommentReplyVO , Long > treeBuilderConfig = new TreeBuilderConfig. Builder < ShareCommentReplyVO , Long > ( )
. withChildrenSetter ( ShareCommentReplyVO :: setChildren )
. withRootId ( - 1L )
. withIdExtractor ( ShareCommentReplyVO :: getId )
. withParentIdExtractor ( ShareCommentReplyVO :: getParentId )
. withRecursive ( true )
. withComparator ( ( a, b) -> {
return a. getId ( ) < b. getId ( ) ? - 1 : a. getId ( ) > b. getId ( ) ? 1 : 0 ;
} ) . build ( ) ;
List < ShareCommentReplyVO > shareCommentReplyVOS = CategoryTreeBuilder . buildTree ( list, treeBuilderConfig) ;
return shareCommentReplyVOS;
}
6.测试
1.apipost
2.由于还没使用网关,所以与用户信息有关的查不出来
7.自定义的树工具(支持构建树和查询子节点id)
1.CategoryTreeBuilder.java
package com. sunxiansheng. circle. server. util. bettertreeutils ;
import java. util. * ;
import java. util. function. Function ;
import java. util. stream. Collectors ;
public class CategoryTreeBuilder < T , ID> {
private final TreeBuilderConfig < T , ID> config;
public CategoryTreeBuilder ( TreeBuilderConfig < T , ID> config) {
this . config = config;
if ( config. isBuildForTree ( ) && config. getChildrenSetter ( ) == null ) {
throw new IllegalArgumentException ( "childrenSetter must be provided for building tree" ) ;
}
}
public static < T , ID> List < T > buildTree ( List < T > entities, TreeBuilderConfig < T , ID> config) {
return new CategoryTreeBuilder < > ( config) . buildTree ( entities) ;
}
private List < T > buildTree ( List < T > entities) {
if ( entities == null || entities. isEmpty ( ) ) {
return Collections . emptyList ( ) ;
}
Map < ID, List < T > > parentIdMap = entities. stream ( )
. collect ( Collectors . groupingBy ( config. getParentIdExtractor ( ) ) ) ;
List < T > roots = parentIdMap. get ( config. getRootId ( ) ) ;
if ( roots == null ) {
roots = Collections . emptyList ( ) ;
}
roots. forEach ( root -> {
List < T > children = setChildren ( root, parentIdMap) ;
if ( children != null ) {
config. getChildrenSetter ( ) . accept ( root, children) ;
}
} ) ;
if ( config. getComparator ( ) != null ) {
roots. sort ( config. getComparator ( ) ) ;
}
return roots;
}
private List < T > setChildren ( T parent, Map < ID, List < T > > parentIdMap) {
ID parentId = config. getIdExtractor ( ) . apply ( parent) ;
List < T > children = parentIdMap. get ( parentId) ;
if ( children == null || children. isEmpty ( ) ) {
return null ;
}
if ( config. isRecursive ( ) ) {
children. forEach ( child -> {
List < T > subChildren = setChildren ( child, parentIdMap) ;
if ( subChildren != null ) {
config. getChildrenSetter ( ) . accept ( child, subChildren) ;
}
} ) ;
}
if ( config. getComparator ( ) != null ) {
children. sort ( config. getComparator ( ) ) ;
}
return children;
}
public static < T , ID> List < ID> getChildrenIds ( List < T > entities, ID parentId) {
TreeBuilderConfig < T , ID> defaultConfig = new TreeBuilderConfig. Builder < T , ID> ( ) . build ( ) ;
return getChildrenIds ( entities, parentId, defaultConfig) ;
}
public static < T , ID> List < ID> getChildrenIds ( List < T > entities, ID parentId, TreeBuilderConfig < T , ID> config) {
List < ID> result = new ArrayList < > ( ) ;
getAllChildrenIdsHelper ( entities, parentId, config, result) ;
return result;
}
private static < T , ID> void getAllChildrenIdsHelper ( List < T > entities, ID parentId, TreeBuilderConfig < T , ID> config, List < ID> result) {
Function < T , ID> idExtractor = config. getIdExtractor ( ) != null ? config. getIdExtractor ( ) : TreeBuilderConfig . getDefaultIdExtractor ( ) ;
Function < T , ID> parentIdExtractor = config. getParentIdExtractor ( ) != null ? config. getParentIdExtractor ( ) : TreeBuilderConfig . getDefaultParentIdExtractor ( ) ;
List < ID> directChildrenIds = entities. stream ( )
. filter ( entity -> parentIdExtractor. apply ( entity) . equals ( parentId) )
. map ( idExtractor)
. collect ( Collectors . toList ( ) ) ;
if ( ! directChildrenIds. isEmpty ( ) ) {
result. addAll ( directChildrenIds) ;
for ( ID childId : directChildrenIds) {
getAllChildrenIdsHelper ( entities, childId, config, result) ;
}
}
}
public static < T , ID> List < ID> getNodeAndChildrenIds ( List < T > entities, ID nodeId) {
TreeBuilderConfig < T , ID> defaultConfig = new TreeBuilderConfig. Builder < T , ID> ( ) . build ( ) ;
return getNodeAndChildrenIds ( entities, nodeId, defaultConfig) ;
}
public static < T , ID> List < ID> getNodeAndChildrenIds ( List < T > entities, ID nodeId, TreeBuilderConfig < T , ID> config) {
List < ID> result = new ArrayList < > ( ) ;
result. add ( nodeId) ;
getAllChildrenIdsHelper ( entities, nodeId, config, result) ;
return result;
}
}
2.TreeBuilderConfig.java
package com. sunxiansheng. circle. server. util. bettertreeutils ;
import java. lang. reflect. Method ;
import java. util. Comparator ;
import java. util. List ;
import java. util. function. BiConsumer ;
import java. util. function. Function ;
public class TreeBuilderConfig < T , ID> {
private final Function < T , ID> idExtractor;
private final Function < T , ID> parentIdExtractor;
private final BiConsumer < T , List < T > > childrenSetter;
private final Comparator < T > comparator;
private final ID rootId;
private final boolean recursive;
private final boolean buildForTree;
private TreeBuilderConfig ( Builder < T , ID> builder) {
this . idExtractor = builder. idExtractor;
this . parentIdExtractor = builder. parentIdExtractor;
this . childrenSetter = builder. childrenSetter;
this . comparator = builder. comparator;
this . rootId = builder. rootId;
this . recursive = builder. recursive;
this . buildForTree = builder. buildForTree;
if ( this . buildForTree && this . childrenSetter == null ) {
throw new IllegalArgumentException ( "childrenSetter must be provided for building tree" ) ;
}
}
public Function < T , ID> getIdExtractor ( ) {
return idExtractor;
}
public Function < T , ID> getParentIdExtractor ( ) {
return parentIdExtractor;
}
public BiConsumer < T , List < T > > getChildrenSetter ( ) {
return childrenSetter;
}
public Comparator < T > getComparator ( ) {
return comparator;
}
public ID getRootId ( ) {
return rootId;
}
public boolean isRecursive ( ) {
return recursive;
}
public boolean isBuildForTree ( ) {
return buildForTree;
}
public static class Builder < T , ID> {
private Function < T , ID> idExtractor = getDefaultIdExtractor ( ) ;
private Function < T , ID> parentIdExtractor = getDefaultParentIdExtractor ( ) ;
private BiConsumer < T , List < T > > childrenSetter;
private Comparator < T > comparator;
private ID rootId = ( ID ) Long . valueOf ( - 1 ) ;
private boolean recursive = true ;
private boolean buildForTree = false ;
public Builder < T , ID> withIdExtractor ( Function < T , ID> idExtractor) {
this . idExtractor = idExtractor;
return this ;
}
public Builder < T , ID> withParentIdExtractor ( Function < T , ID> parentIdExtractor) {
this . parentIdExtractor = parentIdExtractor;
return this ;
}
public Builder < T , ID> withChildrenSetter ( BiConsumer < T , List < T > > childrenSetter) {
this . childrenSetter = childrenSetter;
this . buildForTree = true ;
return this ;
}
public Builder < T , ID> withComparator ( Comparator < T > comparator) {
this . comparator = comparator;
return this ;
}
public Builder < T , ID> withRootId ( ID rootId) {
this . rootId = rootId;
return this ;
}
public Builder < T , ID> withRecursive ( boolean recursive) {
this . recursive = recursive;
return this ;
}
public TreeBuilderConfig < T , ID> build ( ) {
return new TreeBuilderConfig < > ( this ) ;
}
}
@SuppressWarnings ( "unchecked" )
public static < T , ID> Function < T , ID> getDefaultIdExtractor ( ) {
return entity -> {
try {
Method getIdMethod = entity. getClass ( ) . getMethod ( "getId" ) ;
return ( ID ) getIdMethod. invoke ( entity) ;
} catch ( Exception e) {
throw new RuntimeException ( "Failed to get ID from entity: " + entity. getClass ( ) . getName ( ) , e) ;
}
} ;
}
@SuppressWarnings ( "unchecked" )
public static < T , ID> Function < T , ID> getDefaultParentIdExtractor ( ) {
return entity -> {
try {
Method getParentIdMethod = entity. getClass ( ) . getMethod ( "getParentId" ) ;
return ( ID ) getParentIdMethod. invoke ( entity) ;
} catch ( Exception e) {
throw new RuntimeException ( "Failed to get Parent ID from entity: " + entity. getClass ( ) . getName ( ) , e) ;
}
} ;
}
}
3.删除评论回复
1.RemoveShareCommentReq.java
package com. sunxiansheng. circle. api. req ;
import lombok. Getter ;
import lombok. Setter ;
import java. io. Serializable ;
@Getter
@Setter
public class RemoveShareCommentReq implements Serializable {
private Long id;
private Integer replyType;
}
2.ShareCommentReplyController.java
@PostMapping ( value = "/remove" )
public Result < Boolean > remove ( @RequestBody RemoveShareCommentReq req) {
try {
if ( log. isInfoEnabled ( ) ) {
log. info ( "删除鸡圈评论内容入参{}" , JSON . toJSONString ( req) ) ;
}
Preconditions . checkArgument ( Objects . nonNull ( req) , "参数不能为空!" ) ;
Preconditions . checkArgument ( Objects . nonNull ( req. getReplyType ( ) ) , "类型不能为空!" ) ;
Preconditions . checkArgument ( Objects . nonNull ( req. getId ( ) ) , "内容ID不能为空!" ) ;
Boolean result = shareCommentReplyService. removeComment ( req) ;
if ( log. isInfoEnabled ( ) ) {
log. info ( "删除鸡圈评论内容{}" , JSON . toJSONString ( result) ) ;
}
return Result . ok ( result) ;
} catch ( IllegalArgumentException e) {
log. error ( "参数异常!错误原因{}" , e. getMessage ( ) , e) ;
return Result . fail ( e. getMessage ( ) ) ;
} catch ( Exception e) {
log. error ( "删除鸡圈评论内容异常!错误原因{}" , e. getMessage ( ) , e) ;
return Result . fail ( "删除鸡圈评论内容异常!" ) ;
}
}
3.ShareCommentReplyService.java
Boolean removeComment ( RemoveShareCommentReq req) ;
4.ShareCommentReplyServiceImpl.java(根据id查询所有子id具体使用)
@Override
@Transactional ( rollbackFor = Exception . class )
public Boolean removeComment ( RemoveShareCommentReq req) {
Long id = req. getId ( ) ;
Integer replyType = req. getReplyType ( ) ;
ShareCommentReply queryById = this . shareCommentReplyMapper. queryById ( id) ;
Integer momentId = queryById. getMomentId ( ) ;
ShareCommentReply shareCommentReply = new ShareCommentReply ( ) ;
shareCommentReply. setIsDeleted ( 0 ) ;
shareCommentReply. setMomentId ( Math . toIntExact ( momentId) ) ;
List < ShareCommentReply > shareCommentReplies = shareCommentReplyMapper. queryAllByLimit ( shareCommentReply) ;
List < Long > childrenIds = CategoryTreeBuilder . getNodeAndChildrenIds ( shareCommentReplies, id) ;
this . shareCommentReplyMapper. updateBatchByIds ( childrenIds) ;
int count = childrenIds. size ( ) ;
this . shareMomentMapper. incrReplyCount ( Long . valueOf ( momentId) , - count) ;
return true ;
}
5.ShareCommentReplyMapper.java
void updateBatchByIds ( @Param ( "ids" ) List < Long > ids) ;
6.ShareCommentReplyMapper.xml
< update id = " updateBatchByIds" >
update share_comment_reply
set is_deleted = 1
where id in
< foreach collection = " ids" open = " (" separator = " ," close = " )" item = " item" >
#{item}
</ foreach>
</ update>
7.测试
1.apipost
2.评论表删除成功
3.回复数量删除成功