feat:更新点赞评论功能

This commit is contained in:
2025-07-01 20:01:18 +08:00
parent 2a31d63a41
commit f690c1478a
17 changed files with 277 additions and 72 deletions

View File

@@ -0,0 +1,16 @@
package com.cxx.food.constant;
public enum BizType {
RECIPE("recipe"),
MOMENT("moment");
private final String code;
private BizType(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}

View File

@@ -91,6 +91,25 @@ public class FoodController {
return foodService.queryRecord(startDate, endDate); return foodService.queryRecord(startDate, endDate);
} }
@Operation(summary = "新增评论")
@PostMapping("/recipe/{id}/comment")
public Boolean addComment(@PathVariable("id") long id,
@RequestParam String content) {
return foodService.addComment(id, content);
}
@Operation(summary = "增加点赞")
@PostMapping("/recipe/{id}/like")
public Boolean addLike(@PathVariable("id") long id) {
return foodService.addLike(id);
}
@Operation(summary = "取消点赞")
@DeleteMapping("/recipe/{id}/like")
public Boolean deleteLike(@PathVariable("id") long id) {
return foodService.deleteLike(id);
}
@Operation(summary = "查询美食类别") @Operation(summary = "查询美食类别")
@GetMapping("/category") @GetMapping("/category")
public List<String> queryCategory() { public List<String> queryCategory() {

View File

@@ -40,4 +40,12 @@ public class RecipeDto {
@Schema(description = "备注") @Schema(description = "备注")
private String remark; private String remark;
@Schema(description = "点赞用户")
@JsonView(ReadView.class)
private List<Long> likeList;
@Schema(description = "评论内容")
@JsonView(ReadView.class)
private List<CommentDto> commentList;
} }

View File

@@ -23,4 +23,10 @@ public class SummaryDto {
@Schema(description = "美食记录") @Schema(description = "美食记录")
private List<RecordDto> recordList; private List<RecordDto> recordList;
@Schema(description = "点赞总数")
private Integer likeCount;
@Schema(description = "评论总数")
private Integer commentCount;
} }

View File

@@ -6,12 +6,15 @@ import com.cxx.framework.data.AbstractEntity;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@TableName("comment") @TableName("comment_record")
public class Comment extends AbstractEntity { public class CommentRecord extends AbstractEntity {
@TableField("moment_id") @TableField("type")
private Long momentId; private String type;
@TableField("subject_id")
private Long subjectId;
@TableField("content") @TableField("content")
private String content; private String content;

View File

@@ -8,11 +8,11 @@ import lombok.EqualsAndHashCode;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@TableName("moment_like") @TableName("like_record")
public class MomentLike extends AbstractEntity { public class LikeRecord extends AbstractEntity {
@TableField("moment_id") @TableField("type")
private Long momentId; private String type;
@TableField("is_delete") @TableField("subject_id")
private Integer isDelete; private Long subjectId;
} }

View File

@@ -1,9 +1,9 @@
package com.cxx.food.mapper; package com.cxx.food.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cxx.food.entity.Comment; import com.cxx.food.entity.CommentRecord;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface CommentMapper extends BaseMapper<Comment> { public interface CommentRecordMapper extends BaseMapper<CommentRecord> {
} }

View File

@@ -1,9 +1,9 @@
package com.cxx.food.mapper; package com.cxx.food.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cxx.food.entity.MomentLike; import com.cxx.food.entity.LikeRecord;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface MomentLikeMapper extends BaseMapper<MomentLike> { public interface LikeRecordMapper extends BaseMapper<LikeRecord> {
} }

View File

@@ -0,0 +1,8 @@
package com.cxx.food.service;
import com.cxx.food.constant.BizType;
public interface CommentService {
Boolean addComment(BizType type, Long subjectId, String content);
}

View File

@@ -20,6 +20,12 @@ public interface FoodService {
Boolean deleteRecord(Long id); Boolean deleteRecord(Long id);
Boolean addComment(Long recipeId, String content);
Boolean addLike(Long recipeId);
Boolean deleteLike(Long recipeId);
RecipeDto queryRecipe(Long id); RecipeDto queryRecipe(Long id);
List<SummaryDto> querySummary(FoodQueryVo foodQueryVo); List<SummaryDto> querySummary(FoodQueryVo foodQueryVo);

View File

@@ -0,0 +1,10 @@
package com.cxx.food.service;
import com.cxx.food.constant.BizType;
public interface LikeService {
Boolean addLike(BizType type, Long subjectId);
Boolean deleteLike(Long subjectId);
}

View File

@@ -0,0 +1,25 @@
package com.cxx.food.service.impl;
import com.cxx.food.constant.BizType;
import com.cxx.food.entity.CommentRecord;
import com.cxx.food.mapper.CommentRecordMapper;
import com.cxx.food.service.CommentService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class CommentServiceImpl implements CommentService {
@Resource
private CommentRecordMapper commentRecordMapper;
@Override
public Boolean addComment(BizType type, Long subjectId, String content) {
CommentRecord comment = new CommentRecord();
comment.setType(type.getCode());
comment.setContent(content);
comment.setSubjectId(subjectId);
return commentRecordMapper.insert(comment) == 1;
}
}

View File

@@ -2,21 +2,18 @@ package com.cxx.food.service.impl;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cxx.food.constant.BizType;
import com.cxx.food.dao.FoodDao; import com.cxx.food.dao.FoodDao;
import com.cxx.food.dto.*; import com.cxx.food.dto.*;
import com.cxx.food.entity.Material; import com.cxx.food.entity.*;
import com.cxx.food.entity.Recipe;
import com.cxx.food.entity.Record; import com.cxx.food.entity.Record;
import com.cxx.food.entity.Step; import com.cxx.food.mapper.*;
import com.cxx.food.mapper.MaterialMapper; import com.cxx.food.service.CommentService;
import com.cxx.food.mapper.RecipeMapper;
import com.cxx.food.mapper.RecordMapper;
import com.cxx.food.mapper.StepMapper;
import com.cxx.food.service.FoodService; import com.cxx.food.service.FoodService;
import com.cxx.food.service.LikeService;
import com.cxx.food.vo.FoodQueryVo; import com.cxx.food.vo.FoodQueryVo;
import com.cxx.framework.web.CustomException; import com.cxx.framework.web.CustomException;
import com.github.yitter.idgen.YitIdHelper; import com.github.yitter.idgen.YitIdHelper;
@@ -45,6 +42,15 @@ public class FoodServiceImpl implements FoodService {
@Resource @Resource
private RecordMapper recordMapper; private RecordMapper recordMapper;
@Resource
private CommentRecordMapper commentRecordMapper;
@Resource
private LikeService likeService;
@Resource
private CommentService commentService;
@Override @Override
@Transactional @Transactional
public Boolean addRecipe(RecipeDto recipeDto) { public Boolean addRecipe(RecipeDto recipeDto) {
@@ -135,6 +141,29 @@ public class FoodServiceImpl implements FoodService {
return Boolean.TRUE; return Boolean.TRUE;
} }
@Override
public Boolean addComment(Long recipeId, String content) {
if (recipeMapper.selectById(recipeId) == null) {
throw new CustomException("该菜谱不存在");
}
return commentService.addComment(BizType.RECIPE, recipeId, content);
}
@Override
public Boolean addLike(Long recipeId) {
if (recipeMapper.selectById(recipeId) == null) {
throw new CustomException("该菜谱不存在");
}
return likeService.addLike(BizType.RECIPE, recipeId);
}
@Override
public Boolean deleteLike(Long recipeId) {
return likeService.deleteLike(recipeId);
}
private void resetFoodRecipe(Long id, RecipeDto recipeDto) { private void resetFoodRecipe(Long id, RecipeDto recipeDto) {
materialMapper.delete(Wrappers.lambdaQuery(Material.class).eq(Material::getFoodId, id)); materialMapper.delete(Wrappers.lambdaQuery(Material.class).eq(Material::getFoodId, id));
stepMapper.delete(Wrappers.lambdaQuery(Step.class).eq(Step::getFoodId, id)); stepMapper.delete(Wrappers.lambdaQuery(Step.class).eq(Step::getFoodId, id));

View File

@@ -0,0 +1,49 @@
package com.cxx.food.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cxx.food.constant.BizType;
import com.cxx.food.entity.LikeRecord;
import com.cxx.food.mapper.LikeRecordMapper;
import com.cxx.food.service.LikeService;
import com.cxx.framework.web.CustomException;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class LikeServiceImpl implements LikeService {
@Resource
private LikeRecordMapper likeRecordMapper;
@Override
public Boolean addLike(BizType type, Long subjectId) {
LambdaQueryWrapper<LikeRecord> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(LikeRecord::getSubjectId, subjectId).eq(LikeRecord::getCreateBy, StpUtil.getLoginIdAsString());
LikeRecord like = likeRecordMapper.selectOne(queryWrapper);
if (like != null) {
throw new CustomException("已经点赞了");
}
LikeRecord newLike = new LikeRecord();
newLike.setType(type.getCode());
newLike.setSubjectId(subjectId);
return likeRecordMapper.insert(newLike) == 1;
}
@Override
public Boolean deleteLike(Long subjectId) {
LambdaQueryWrapper<LikeRecord> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(LikeRecord::getSubjectId, subjectId).eq(LikeRecord::getCreateBy, StpUtil.getLoginIdAsString());
LikeRecord like = likeRecordMapper.selectOne(queryWrapper);
if (like == null) {
throw new CustomException("该记录不存在");
}
return likeRecordMapper.deleteById(like) == 1;
}
}

View File

@@ -1,15 +1,14 @@
package com.cxx.food.service.impl; package com.cxx.food.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cxx.food.constant.BizType;
import com.cxx.food.dao.MomentDao; import com.cxx.food.dao.MomentDao;
import com.cxx.food.dto.MomentDto; import com.cxx.food.dto.MomentDto;
import com.cxx.food.entity.*; import com.cxx.food.entity.*;
import com.cxx.food.mapper.CommentMapper;
import com.cxx.food.mapper.MomentLikeMapper;
import com.cxx.food.mapper.MomentImageMapper; import com.cxx.food.mapper.MomentImageMapper;
import com.cxx.food.mapper.MomentMapper; import com.cxx.food.mapper.MomentMapper;
import com.cxx.food.service.CommentService;
import com.cxx.food.service.LikeService;
import com.cxx.food.service.MomentService; import com.cxx.food.service.MomentService;
import com.cxx.framework.web.CustomException; import com.cxx.framework.web.CustomException;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@@ -27,10 +26,10 @@ public class MomentServiceImpl implements MomentService {
private MomentMapper momentMapper; private MomentMapper momentMapper;
@Resource @Resource
private CommentMapper commentMapper; private LikeService likeService;
@Resource @Resource
private MomentLikeMapper momentLikeMapper; private CommentService commentService;
@Resource @Resource
private MomentImageMapper momentImageMapper; private MomentImageMapper momentImageMapper;
@@ -86,45 +85,21 @@ public class MomentServiceImpl implements MomentService {
throw new CustomException("该朋友圈不存在"); throw new CustomException("该朋友圈不存在");
} }
Comment comment = new Comment(); return commentService.addComment(BizType.MOMENT, momentId, content);
comment.setContent(content);
comment.setMomentId(momentId);
return commentMapper.insert(comment) == 1;
} }
@Override @Override
public Boolean addLike(Long momentId) { public Boolean addLike(Long momentId) {
LambdaQueryWrapper<MomentLike> queryWrapper = new LambdaQueryWrapper<>(); if (momentMapper.selectById(momentId) == null) {
queryWrapper.eq(MomentLike::getMomentId, momentId).eq(MomentLike::getCreateBy, StpUtil.getLoginIdAsString()); throw new CustomException("该朋友圈不存在");
MomentLike like = momentLikeMapper.selectOne(queryWrapper);
if (like != null) {
if (like.getIsDelete() == 0) {
throw new CustomException("已经点赞了");
} else {
like.setIsDelete(0);
return momentLikeMapper.updateById(like) == 1;
}
} }
MomentLike newLike = new MomentLike(); return likeService.addLike(BizType.MOMENT, momentId);
newLike.setMomentId(momentId);
newLike.setIsDelete(0);
return momentLikeMapper.insert(newLike) == 1;
} }
@Override @Override
public Boolean deleteLike(Long momentId) { public Boolean deleteLike(Long momentId) {
LambdaQueryWrapper<MomentLike> queryWrapper = new LambdaQueryWrapper<>(); return likeService.deleteLike(momentId);
queryWrapper.eq(MomentLike::getMomentId, momentId).eq(MomentLike::getCreateBy, StpUtil.getLoginIdAsString());
MomentLike like = momentLikeMapper.selectOne(queryWrapper);
if (like == null) {
throw new CustomException("该朋友圈不存在");
}
like.setIsDelete(1);
return momentLikeMapper.updateById(like) == 1;
} }
private void deleteMomentImage(Long id) { private void deleteMomentImage(Long id) {

View File

@@ -16,6 +16,12 @@
<collection property="recordList" ofType="com.cxx.food.dto.RecordDto" <collection property="recordList" ofType="com.cxx.food.dto.RecordDto"
column="id" select="queryRecordById"> column="id" select="queryRecordById">
</collection> </collection>
<collection property="likeList" ofType="long"
column="id" select="queryRecipeLike">
</collection>
<collection property="commentList" ofType="com.cxx.food.dto.CommentDto"
column="id" select="queryRecipeComment">
</collection>
</resultMap> </resultMap>
<resultMap id="foodMaterialResultMap" type="com.cxx.food.dto.MaterialDto"> <resultMap id="foodMaterialResultMap" type="com.cxx.food.dto.MaterialDto">
@@ -34,6 +40,8 @@
<resultMap id="foodRecordResultMap" type="com.cxx.food.dto.RecordDto"> <resultMap id="foodRecordResultMap" type="com.cxx.food.dto.RecordDto">
<id property="id" column="id"/> <id property="id" column="id"/>
<result property="name" column="person"/>
<result property="category" column="category"/>
<result property="person" column="person"/> <result property="person" column="person"/>
<result property="date" column="date"/> <result property="date" column="date"/>
<result property="imageUrl" column="imageUrl"/> <result property="imageUrl" column="imageUrl"/>
@@ -44,14 +52,43 @@
<result property="name" column="name"/> <result property="name" column="name"/>
<result property="category" column="category"/> <result property="category" column="category"/>
<result property="recommendRate" column="recommendRate"/> <result property="recommendRate" column="recommendRate"/>
<result property="likeCount" column="likeCount"/>
<result property="commentCount" column="commentCount"/>
<collection property="recordList" ofType="com.cxx.food.dto.RecordDto"> <collection property="recordList" ofType="com.cxx.food.dto.RecordDto">
<id property="id" column="workId"/> <id property="id" column="workId"/>
<result property="person" column="person"/> <result property="person" column="person"/>
<result property="date" column="recordDate"/> <result property="date" column="date"/>
<result property="imageUrl" column="workImageUrl"/> <result property="imageUrl" column="imageUrl"/>
</collection> </collection>
</resultMap> </resultMap>
<resultMap id="commentResultMap" type="com.cxx.food.dto.CommentDto">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="avatar" column="avatar"/>
<result property="content" column="content"/>
<result property="date" column="date"/>
</resultMap>
<select id="queryRecipeLike" resultType="long">
SELECT a.create_by AS id
FROM like_record AS a
WHERE subject_id = #{id}
AND type = 'recipe'
</select>
<select id="queryRecipeComment" resultMap="commentResultMap">
SELECT a.id AS id,
b.username AS username,
b.avatar AS avatar,
a.content AS content,
a.create_time AS date
FROM comment_record AS a
LEFT JOIN user AS b ON a.create_by = b.id
WHERE subject_id = #{id}
AND type = 'recipe'
</select>
<select id="queryMaterial" resultMap="foodMaterialResultMap"> <select id="queryMaterial" resultMap="foodMaterialResultMap">
SELECT id AS id, SELECT id AS id,
type AS type, type AS type,
@@ -125,17 +162,31 @@
a.category AS category, a.category AS category,
a.recommend_rate AS recommendRate, a.recommend_rate AS recommendRate,
b.person AS person, b.person AS person,
b.date AS recordDate, b.date AS date,
b.image_url AS workImageUrl b.image_url AS imageUrl,
COALESCE(c.like_count, 0) AS likeCount,
COALESCE(d.comment_count, 0) AS commentCount
FROM recipe a FROM recipe a
LEFT JOIN record b ON a.id = b.food_id LEFT JOIN record b ON a.id = b.food_id
LEFT JOIN (
SELECT subject_id, COUNT(id) AS like_count
FROM like_record
WHERE type = 'recipe'
GROUP BY subject_id
) c ON a.id = c.subject_id
LEFT JOIN (
SELECT subject_id, COUNT(id) AS comment_count
FROM comment_record
WHERE type = 'recipe'
GROUP BY subject_id
) d ON a.id = d.subject_id
<where> <where>
<if test="query.category != null and query.category != ''"> <if test="query.category != null and query.category != ''">
a.category = #{query.category} a.category = #{query.category}
</if> </if>
AND a.create_by = #{user} AND a.create_by = #{user}
</where> </where>
ORDER BY a.update_time DESC; ORDER BY a.update_time DESC
</select> </select>
<select id="queryStats" resultType="com.cxx.food.dto.StatsDto"> <select id="queryStats" resultType="com.cxx.food.dto.StatsDto">

View File

@@ -11,10 +11,10 @@
<collection property="imageList" ofType="java.lang.String" <collection property="imageList" ofType="java.lang.String"
column="id" select="queryMomentImage"/> column="id" select="queryMomentImage"/>
<collection property="likeList" ofType="long" <collection property="likeList" ofType="long"
column="id" select="queryLike"> column="id" select="queryMomentLike">
</collection> </collection>
<collection property="commentList" ofType="com.cxx.food.dto.CommentDto" <collection property="commentList" ofType="com.cxx.food.dto.CommentDto"
column="id" select="queryComment"> column="id" select="queryMomentComment">
</collection> </collection>
</resultMap> </resultMap>
@@ -26,22 +26,22 @@
<result property="date" column="date"/> <result property="date" column="date"/>
</resultMap> </resultMap>
<select id="queryLike" resultType="long"> <select id="queryMomentLike" resultType="long">
SELECT a.create_by AS id SELECT a.create_by AS id
FROM moment_like AS a FROM like_record AS a
WHERE moment_id = #{id} WHERE subject_id = #{id} AND type = 'moment'
AND a.is_delete = 0
</select> </select>
<select id="queryComment" resultMap="commentResultMap"> <select id="queryMomentComment" resultMap="commentResultMap">
SELECT a.id AS id, SELECT a.id AS id,
b.username AS username, b.username AS username,
b.avatar AS avatar, b.avatar AS avatar,
a.content AS content, a.content AS content,
a.create_time AS date a.create_time AS date
FROM comment AS a FROM comment_record AS a
LEFT JOIN user AS b ON a.create_by = b.id LEFT JOIN user AS b ON a.create_by = b.id
WHERE moment_id = #{id} WHERE subject_id = #{id}
AND type = 'moment'
</select> </select>
<select id="queryMomentList" resultMap="momentResultMap"> <select id="queryMomentList" resultMap="momentResultMap">