feat(消息): 添加消息点赞功能

- 在MessageController中添加点赞接口
- 在MessageRepository中添加点赞数更新方法
- 在IMessageService和MessageService中实现点赞逻辑
- 初始化测试数据时设置点赞数默认值为0
- 完善相关文档注释
This commit is contained in:
qingfeng1121
2025-10-23 18:18:27 +08:00
parent f53e251d46
commit 46be613f28
11 changed files with 5740 additions and 129 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -90,7 +90,12 @@ public class MessageController {
logger.info("接收创建消息的请求: {}", message != null ? message.getNickname() : "null"); logger.info("接收创建消息的请求: {}", message != null ? message.getNickname() : "null");
return messageService.saveMessage(message); return messageService.saveMessage(message);
} }
// 点赞数增加
@PostMapping("/{id}/like")
public ResponseMessage<Message> likeMessage(@PathVariable Integer id) {
logger.info("接收点赞消息的请求: {}", id);
return messageService.likeMessage(id);
}
/** /**
* 根据ID删除消息 * 根据ID删除消息
*/ */

View File

@@ -10,70 +10,73 @@ import org.springframework.stereotype.Repository;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@Repository // 表明这是一个数据访问层组件,用于持久层操作 @Repository // 表明这是一个数据访问层组件,用于持久层操作
public interface ArticleRepository extends JpaRepository<Article, Integer> { public interface ArticleRepository extends JpaRepository<Article, Integer> {
/** /**
* 根据文章ID查询文章信息的方法 * 根据文章ID查询文章信息的方法
* 使用JPQLJava Persistence Query Language进行查询 * 使用JPQLJava Persistence Query Language进行查询
* *
* @param id 文章的唯一标识符,作为查询条件 * @param id 文章的唯一标识符,作为查询条件
* @return 返回一个Optional<Article>对象可能包含文章信息也可能为空如果未找到对应ID的文章 * @return 返回一个Optional<Article>对象可能包含文章信息也可能为空如果未找到对应ID的文章
*/ */
@Query("SELECT a FROM Article a WHERE a.articleid = :id") @Query("SELECT a FROM Article a WHERE a.articleid = :id")
Optional<Article> findById(@Param("id") Integer id); Optional<Article> findById(@Param("id") Integer id);
/** /**
* 根据标题查询文章列表 * 根据标题查询文章列表
*
* @param title 文章标题的一部分,用于模糊查询 * @param title 文章标题的一部分,用于模糊查询
* @return 返回符合查询条件的文章列表 * @return 返回符合查询条件的文章列表
*/ */
@Query("SELECT a FROM Article a WHERE a.title LIKE %:title%") @Query("SELECT a FROM Article a WHERE a.title LIKE %:title%")
List<Article> findByTitle(@Param("title") String title); List<Article> findByTitle(@Param("title") String title);
/**
* 根据文章ID查询已发布的文章 /**
* 使用JPQL查询语句只查询状态为1已发布且指定ID的文章 * 根据文章ID查询已发布的文章
* * 使用JPQL查询语句只查询状态为1已发布且指定ID的文章
* @return 返回符合查询条件的文章列表 *
*/ * @return 返回符合查询条件的文章列表
*/
@Query("SELECT a FROM Article a WHERE a.status = 1") @Query("SELECT a FROM Article a WHERE a.status = 1")
List<Article> findPublishedByAuthor(); List<Article> findPublishedByAuthor();
/** /**
* 根据分类ID查询已发布的文章列表 * 根据分类ID查询已发布的文章列表
* 使用JPQL查询语句筛选状态为已发布(status=1)且指定分类(typeid)的文章 * 使用JPQL查询语句筛选状态为已发布(status=1)且指定分类(typeid)的文章
* *
* @param attributeid 分类ID通过@Param注解映射到查询语句中的:attributeid参数 * @param attributeid 分类ID通过@Param注解映射到查询语句中的:attributeid参数
* @return 返回符合条件Article对象的列表 * @return 返回符合条件Article对象的列表
*/ */
@Query("SELECT a FROM Article a WHERE a.status = 1 AND a.attributeid = :attributeid") @Query("SELECT a FROM Article a WHERE a.status = 1 AND a.attributeid = :attributeid")
List<Article> findPublishedByAttribute(@Param("attributeid") Integer attributeid); List<Article> findPublishedByAttribute(@Param("attributeid") Integer attributeid);
/**
* 根据属性ID查询最新的文章列表 /**
* 使用JPQL查询语句筛选状态为已发布(status=1)且指定属性(attributeid)的文章,按创建时间降序排序 * 根据属性ID查询最新的文章列表
* * 使用JPQL查询语句筛选状态为已发布(status=1)且指定属性(attributeid)的文章,按创建时间降序排序
* @param attributeid 属性ID通过@Param注解映射到查询语句中的:attributeid参数 *
* @return 返回符合条件Article对象的列表按创建时间降序排列 * @param attributeid 属性ID通过@Param注解映射到查询语句中的:attributeid参数
*/ * @return 返回符合条件Article对象的列表按创建时间降序排列
*/
@Query("SELECT a FROM Article a WHERE a.status = 1 AND a.attributeid = :attributeid ORDER BY a.createdAt DESC") @Query("SELECT a FROM Article a WHERE a.status = 1 AND a.attributeid = :attributeid ORDER BY a.createdAt DESC")
List<Article> findLatestByAttribute(@Param("attributeid") Integer attributeid); List<Article> findLatestByAttribute(@Param("attributeid") Integer attributeid);
/** /**
* 使用@Modifying注解标记这是一个修改操作通常用于UPDATE或DELETE语句 * 使用@Modifying注解标记这是一个修改操作通常用于UPDATE或DELETE语句
* 使用@Query注解定义自定义的JPQL查询语句 * 使用@Query注解定义自定义的JPQL查询语句
* 该查询用于将指定文章的浏览量(viewCount)增加1 * 该查询用于将指定文章的浏览量(viewCount)增加1
* *
* @param articleid 文章的唯一标识符,通过@Param注解将方法参数与查询参数绑定 * @param articleid 文章的唯一标识符,通过@Param注解将方法参数与查询参数绑定
*/ */
@Modifying @Modifying
@Query("UPDATE Article a SET a.viewCount = a.viewCount + 1 WHERE a.articleid = :articleid") @Query("UPDATE Article a SET a.viewCount = a.viewCount + 1 WHERE a.articleid = :articleid")
void incrementViewCount(@Param("articleid") Integer articleid); void incrementViewCount(@Param("articleid") Integer articleid);
/**
/** * 根据浏览量降序查询状态为1的所有文章
* 根据浏览量降序查询状态为1的所有文章 * 该查询使用JPQL语句从Article实体中选取数据
* 该查询使用JPQL语句从Article实体中选取数据 *
* * @return 返回一个Article对象的列表按浏览量(viewCount)降序排列
* @return 返回一个Article对象的列表按浏览量(viewCount)降序排列 */
*/
@Query("SELECT a FROM Article a WHERE a.status = 1 ORDER BY a.viewCount DESC") @Query("SELECT a FROM Article a WHERE a.status = 1 ORDER BY a.viewCount DESC")
List<Article> findMostViewed(); List<Article> findMostViewed();
} }

View File

@@ -3,7 +3,9 @@ package com.qf.myafterprojecy.repository;
import com.qf.myafterprojecy.pojo.Message; import com.qf.myafterprojecy.pojo.Message;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import org.springframework.data.jpa.repository.Modifying;
import java.util.List; import java.util.List;
@@ -11,22 +13,57 @@ import java.util.List;
public interface MessageRepository extends JpaRepository<Message, Integer> { public interface MessageRepository extends JpaRepository<Message, Integer> {
// 根据文章ID查询消息 // 根据文章ID查询消息
/**
* 根据文章ID查询消息
* @param articleid 文章ID
* @return 文章下的消息列表
*/
List<Message> findByArticleid(Integer articleid); List<Message> findByArticleid(Integer articleid);
// 查询所有父消息(回复的根消息) // 查询所有父消息(回复的根消息)
/**
* 查询所有父消息(回复的根消息)
* @return 根回复消息列表
*/
List<Message> findByParentidIsNull(); List<Message> findByParentidIsNull();
// 根据父消息ID查询回复 // 根据父消息ID查询回复
/**
* 根据父消息ID查询回复
* @param parentid 父消息ID
* @return 回复消息列表
*/
List<Message> findByParentid(Integer parentid); List<Message> findByParentid(Integer parentid);
// 根据昵称模糊查询消息 // 根据昵称模糊查询消息
/**
* 根据昵称模糊查询消息
* @param nickname 昵称关键词
* @return 包含关键词的消息列表
*/
List<Message> findByNicknameContaining(String nickname); List<Message> findByNicknameContaining(String nickname);
// 查询指定文章下的所有父消息(根回复) /**
@Query("SELECT m FROM Message m WHERE m.articleid = ?1 AND m.parentid IS NULL ORDER BY m.createdAt DESC") * 查询指定文章下的所有父消息(根回复)
List<Message> findRootMessagesByArticleId(Integer articleId); * @param articleId 文章ID
* @return 根回复消息列表
*/
@Query("SELECT m FROM Message m WHERE m.articleid = :articleId AND m.parentid IS NULL ORDER BY m.createdAt DESC")
List<Message> findRootMessagesByArticleId(@Param("articleId") Integer articleId);
/**
* 点赞数增加
* @param messageId 消息ID
*/
@Modifying
@Query("UPDATE Message m SET m.likes = COALESCE(m.likes, 0) + 1 WHERE m.messageid = :messageId")
void incrementLikes(@Param("messageId") Integer messageId);
// 统计指定文章的评论数量 // 统计指定文章的评论数量
@Query("SELECT COUNT(m) FROM Message m WHERE m.articleid = ?1") /**
Long countByArticleId(Integer articleId); * 统计指定文章的评论数量
* @param articleId 文章ID
* @return 评论数量
*/
@Query("SELECT COUNT(m) FROM Message m WHERE m.articleid = :articleId")
Long countByArticleId(@Param("articleId") Integer articleId);
} }

View File

@@ -61,6 +61,7 @@ public class MessageDataChecker implements CommandLineRunner {
message1.setCreatedAt(new Date()); message1.setCreatedAt(new Date());
message1.setArticleid(1); message1.setArticleid(1);
message1.setParentid(null); // 根评论 message1.setParentid(null); // 根评论
message1.setLikes(0); // 设置点赞数初始值为0
messageRepository.save(message1); messageRepository.save(message1);
// 添加回复 // 添加回复
@@ -71,6 +72,7 @@ public class MessageDataChecker implements CommandLineRunner {
reply1.setCreatedAt(new Date()); reply1.setCreatedAt(new Date());
reply1.setArticleid(1); reply1.setArticleid(1);
reply1.setParentid(message1.getMessageid()); // 回复第一篇评论 reply1.setParentid(message1.getMessageid()); // 回复第一篇评论
reply1.setLikes(0); // 设置点赞数初始值为0
messageRepository.save(reply1); messageRepository.save(reply1);
// 添加第二篇文章的评论 // 添加第二篇文章的评论
@@ -81,6 +83,7 @@ public class MessageDataChecker implements CommandLineRunner {
message2.setCreatedAt(new Date()); message2.setCreatedAt(new Date());
message2.setArticleid(2); message2.setArticleid(2);
message2.setParentid(null); message2.setParentid(null);
message2.setLikes(0); // 设置点赞数初始值为0
messageRepository.save(message2); messageRepository.save(message2);
logger.info("成功添加了{}条测试消息数据", messageRepository.count()); logger.info("成功添加了{}条测试消息数据", messageRepository.count());

View File

@@ -23,7 +23,7 @@ public class ArticleService implements IArticleService {
@Autowired @Autowired
private ArticleRepository articleRepository; private ArticleRepository articleRepository;
@Autowired @Autowired
private CategoryAttributeRepository categoryAttributeRepository; private CategoryAttributeRepository categoryAttributeRepository;
@@ -33,7 +33,7 @@ public class ArticleService implements IArticleService {
try { try {
if (id == null || id.isEmpty()) { if (id == null || id.isEmpty()) {
return ResponseMessage.failure("文章ID不能为空"); return ResponseMessage.failure("文章ID不能为空");
} }
Article article = articleRepository.findById(Integer.parseInt(id)) Article article = articleRepository.findById(Integer.parseInt(id))
.orElseThrow(() -> new RuntimeException("文章不存在")); .orElseThrow(() -> new RuntimeException("文章不存在"));
@@ -46,6 +46,7 @@ public class ArticleService implements IArticleService {
return ResponseMessage.failure("获取文章失败"); return ResponseMessage.failure("获取文章失败");
} }
} }
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public ResponseMessage<List<Article>> getArticlesByTitle(String title) { public ResponseMessage<List<Article>> getArticlesByTitle(String title) {
@@ -59,8 +60,8 @@ public class ArticleService implements IArticleService {
log.error("根据标题查询文章列表失败: {}", e.getMessage()); log.error("根据标题查询文章列表失败: {}", e.getMessage());
return ResponseMessage.failure("根据标题查询文章列表失败"); return ResponseMessage.failure("根据标题查询文章列表失败");
} }
} }
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public ResponseMessage<List<Article>> getAllArticles() { public ResponseMessage<List<Article>> getAllArticles() {
@@ -142,7 +143,7 @@ public class ArticleService implements IArticleService {
return ResponseMessage.failure("获取分类文章失败"); return ResponseMessage.failure("获取分类文章失败");
} }
} }
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public ResponseMessage<List<Article>> getArticlesByAttribute(Integer attributeid) { public ResponseMessage<List<Article>> getArticlesByAttribute(Integer attributeid) {
@@ -150,12 +151,12 @@ public class ArticleService implements IArticleService {
if (attributeid == null || attributeid <= 0) { if (attributeid == null || attributeid <= 0) {
return ResponseMessage.failure("属性ID无效"); return ResponseMessage.failure("属性ID无效");
} }
// 验证属性是否存在 // 验证属性是否存在
if (!categoryAttributeRepository.existsById(attributeid)) { if (!categoryAttributeRepository.existsById(attributeid)) {
return ResponseMessage.failure("属性不存在"); return ResponseMessage.failure("属性不存在");
} }
List<Article> articles = articleRepository.findPublishedByAttribute(attributeid); List<Article> articles = articleRepository.findPublishedByAttribute(attributeid);
return ResponseMessage.success(articles); return ResponseMessage.success(articles);
} catch (DataAccessException e) { } catch (DataAccessException e) {
@@ -163,8 +164,10 @@ public class ArticleService implements IArticleService {
return ResponseMessage.failure("获取属性文章失败"); return ResponseMessage.failure("获取属性文章失败");
} }
} }
/** /**
* 增加文章浏览量 * 增加文章浏览量
*
* @param id 文章ID * @param id 文章ID
* @return 返回包含更新后文章信息的ResponseMessage对象 * @return 返回包含更新后文章信息的ResponseMessage对象
*/ */
@@ -174,10 +177,10 @@ public class ArticleService implements IArticleService {
try { try {
Article article = articleRepository.findById(id) Article article = articleRepository.findById(id)
.orElseThrow(() -> new RuntimeException("文章不存在")); .orElseThrow(() -> new RuntimeException("文章不存在"));
article.setViewCount(article.getViewCount() + 1); article.setViewCount(article.getViewCount() + 1);
Article updatedArticle = articleRepository.save(article); Article updatedArticle = articleRepository.save(article);
return ResponseMessage.success(updatedArticle); return ResponseMessage.success(updatedArticle);
} catch (Exception e) { } catch (Exception e) {
log.error("增加文章浏览量失败: {}", e.getMessage()); log.error("增加文章浏览量失败: {}", e.getMessage());
@@ -192,12 +195,12 @@ public class ArticleService implements IArticleService {
if (attributeid == null || attributeid <= 0) { if (attributeid == null || attributeid <= 0) {
return ResponseMessage.failure("属性ID无效"); return ResponseMessage.failure("属性ID无效");
} }
// 验证属性是否存在 // 验证属性是否存在
if (!categoryAttributeRepository.existsById(attributeid)) { if (!categoryAttributeRepository.existsById(attributeid)) {
return ResponseMessage.failure("属性不存在"); return ResponseMessage.failure("属性不存在");
} }
List<Article> articles = articleRepository.findLatestByAttribute(attributeid); List<Article> articles = articleRepository.findLatestByAttribute(attributeid);
return ResponseMessage.success(articles); return ResponseMessage.success(articles);
} catch (DataAccessException e) { } catch (DataAccessException e) {

View File

@@ -29,10 +29,10 @@ public class CategoryAttributeService implements ICategoryAttributeService {
if (id == null || id <= 0) { if (id == null || id <= 0) {
return ResponseMessage.failure("属性ID无效"); return ResponseMessage.failure("属性ID无效");
} }
Category_attribute attribute = categoryAttributeRepository.findById(id) Category_attribute attribute = categoryAttributeRepository.findById(id)
.orElseThrow(() -> new RuntimeException("分类属性不存在")); .orElseThrow(() -> new RuntimeException("分类属性不存在"));
return ResponseMessage.success(attribute); return ResponseMessage.success(attribute);
} catch (Exception e) { } catch (Exception e) {
log.error("获取分类属性失败: {}", e.getMessage()); log.error("获取分类属性失败: {}", e.getMessage());
@@ -47,7 +47,7 @@ public class CategoryAttributeService implements ICategoryAttributeService {
if (categoryId == null || categoryId <= 0) { if (categoryId == null || categoryId <= 0) {
return ResponseMessage.failure("分类ID无效"); return ResponseMessage.failure("分类ID无效");
} }
List<Category_attribute> attributes = categoryAttributeRepository.findByCategoryId(categoryId); List<Category_attribute> attributes = categoryAttributeRepository.findByCategoryId(categoryId);
return ResponseMessage.success(attributes); return ResponseMessage.success(attributes);
} catch (DataAccessException e) { } catch (DataAccessException e) {
@@ -65,14 +65,14 @@ public class CategoryAttributeService implements ICategoryAttributeService {
dto.getCategoryid(), dto.getAttributename())) { dto.getCategoryid(), dto.getAttributename())) {
return ResponseMessage.failure("该分类下已存在同名属性"); return ResponseMessage.failure("该分类下已存在同名属性");
} }
Category_attribute attribute = new Category_attribute(); Category_attribute attribute = new Category_attribute();
BeanUtils.copyProperties(dto, attribute); BeanUtils.copyProperties(dto, attribute);
Category_attribute savedAttribute = categoryAttributeRepository.save(attribute); Category_attribute savedAttribute = categoryAttributeRepository.save(attribute);
log.info("成功创建分类属性: {}, 分类ID: {}", log.info("成功创建分类属性: {}, 分类ID: {}",
savedAttribute.getAttributename(), savedAttribute.getCategoryid()); savedAttribute.getAttributename(), savedAttribute.getCategoryid());
return ResponseMessage.success(savedAttribute); return ResponseMessage.success(savedAttribute);
} catch (DataAccessException e) { } catch (DataAccessException e) {
log.error("保存分类属性失败: {}", e.getMessage()); log.error("保存分类属性失败: {}", e.getMessage());
@@ -87,24 +87,24 @@ public class CategoryAttributeService implements ICategoryAttributeService {
if (id == null || id <= 0) { if (id == null || id <= 0) {
return ResponseMessage.failure("属性ID无效"); return ResponseMessage.failure("属性ID无效");
} }
Category_attribute attribute = categoryAttributeRepository.findById(id) Category_attribute attribute = categoryAttributeRepository.findById(id)
.orElseThrow(() -> new RuntimeException("分类属性不存在")); .orElseThrow(() -> new RuntimeException("分类属性不存在"));
// 如果修改了属性名称,检查新名称是否已存在 // 如果修改了属性名称,检查新名称是否已存在
if (!attribute.getAttributename().equals(dto.getAttributename()) && if (!attribute.getAttributename().equals(dto.getAttributename()) &&
categoryAttributeRepository.existsByCategoryidAndAttributename( categoryAttributeRepository.existsByCategoryidAndAttributename(
dto.getCategoryid(), dto.getAttributename())) { dto.getCategoryid(), dto.getAttributename())) {
return ResponseMessage.failure("该分类下已存在同名属性"); return ResponseMessage.failure("该分类下已存在同名属性");
} }
BeanUtils.copyProperties(dto, attribute); BeanUtils.copyProperties(dto, attribute);
attribute.setAttributeid(id); // 确保ID不变 attribute.setAttributeid(id); // 确保ID不变
Category_attribute updatedAttribute = categoryAttributeRepository.save(attribute); Category_attribute updatedAttribute = categoryAttributeRepository.save(attribute);
log.info("成功更新分类属性: ID={}, 名称={}", log.info("成功更新分类属性: ID={}, 名称={}",
updatedAttribute.getAttributeid(), updatedAttribute.getAttributename()); updatedAttribute.getAttributeid(), updatedAttribute.getAttributename());
return ResponseMessage.success(updatedAttribute); return ResponseMessage.success(updatedAttribute);
} catch (Exception e) { } catch (Exception e) {
log.error("更新分类属性失败: {}", e.getMessage()); log.error("更新分类属性失败: {}", e.getMessage());
@@ -119,14 +119,14 @@ public class CategoryAttributeService implements ICategoryAttributeService {
if (id == null || id <= 0) { if (id == null || id <= 0) {
return ResponseMessage.failure("属性ID无效"); return ResponseMessage.failure("属性ID无效");
} }
if (!categoryAttributeRepository.existsById(id)) { if (!categoryAttributeRepository.existsById(id)) {
return ResponseMessage.failure("分类属性不存在"); return ResponseMessage.failure("分类属性不存在");
} }
categoryAttributeRepository.deleteById(id); categoryAttributeRepository.deleteById(id);
log.info("成功删除分类属性: ID={}", id); log.info("成功删除分类属性: ID={}", id);
return ResponseMessage.success(true); return ResponseMessage.success(true);
} catch (Exception e) { } catch (Exception e) {
log.error("删除分类属性失败: {}", e.getMessage()); log.error("删除分类属性失败: {}", e.getMessage());
@@ -141,10 +141,10 @@ public class CategoryAttributeService implements ICategoryAttributeService {
if (categoryId == null || categoryId <= 0 || attributeName == null || attributeName.isEmpty()) { if (categoryId == null || categoryId <= 0 || attributeName == null || attributeName.isEmpty()) {
return ResponseMessage.failure("参数无效"); return ResponseMessage.failure("参数无效");
} }
boolean exists = categoryAttributeRepository.existsByCategoryidAndAttributename( boolean exists = categoryAttributeRepository.existsByCategoryidAndAttributename(
categoryId, attributeName); categoryId, attributeName);
return ResponseMessage.success(exists); return ResponseMessage.success(exists);
} catch (DataAccessException e) { } catch (DataAccessException e) {
log.error("检查分类属性是否存在失败: {}", e.getMessage()); log.error("检查分类属性是否存在失败: {}", e.getMessage());

View File

@@ -59,12 +59,12 @@ public class CategoryService implements ICategoryService {
if (categoryRepository.existsByTypename(categoryDto.getTypename())) { if (categoryRepository.existsByTypename(categoryDto.getTypename())) {
return ResponseMessage.failure("分类名称已存在"); return ResponseMessage.failure("分类名称已存在");
} }
Category category = new Category(); Category category = new Category();
BeanUtils.copyProperties(categoryDto, category); BeanUtils.copyProperties(categoryDto, category);
category.setCreatedAt(LocalDateTime.now()); category.setCreatedAt(LocalDateTime.now());
category.setUpdatedAt(LocalDateTime.now()); category.setUpdatedAt(LocalDateTime.now());
Category savedCategory = categoryRepository.save(category); Category savedCategory = categoryRepository.save(category);
return ResponseMessage.success(savedCategory); return ResponseMessage.success(savedCategory);
} catch (DataAccessException e) { } catch (DataAccessException e) {
@@ -80,19 +80,19 @@ public class CategoryService implements ICategoryService {
if (id == null || id <= 0) { if (id == null || id <= 0) {
return ResponseMessage.failure("分类ID无效"); return ResponseMessage.failure("分类ID无效");
} }
Category category = categoryRepository.findById(id) Category category = categoryRepository.findById(id)
.orElseThrow(() -> new RuntimeException("分类不存在")); .orElseThrow(() -> new RuntimeException("分类不存在"));
// 如果修改了分类名称,检查新名称是否已存在 // 如果修改了分类名称,检查新名称是否已存在
if (!category.getTypename().equals(categoryDto.getTypename()) && if (!category.getTypename().equals(categoryDto.getTypename()) &&
categoryRepository.existsByTypename(categoryDto.getTypename())) { categoryRepository.existsByTypename(categoryDto.getTypename())) {
return ResponseMessage.failure("分类名称已存在"); return ResponseMessage.failure("分类名称已存在");
} }
BeanUtils.copyProperties(categoryDto, category); BeanUtils.copyProperties(categoryDto, category);
category.setUpdatedAt(LocalDateTime.now()); category.setUpdatedAt(LocalDateTime.now());
Category updatedCategory = categoryRepository.save(category); Category updatedCategory = categoryRepository.save(category);
return ResponseMessage.success(updatedCategory); return ResponseMessage.success(updatedCategory);
} catch (Exception e) { } catch (Exception e) {
@@ -108,11 +108,11 @@ public class CategoryService implements ICategoryService {
if (id == null || id <= 0) { if (id == null || id <= 0) {
return ResponseMessage.failure("分类ID无效"); return ResponseMessage.failure("分类ID无效");
} }
if (!categoryRepository.existsById(id)) { if (!categoryRepository.existsById(id)) {
return ResponseMessage.failure("分类不存在"); return ResponseMessage.failure("分类不存在");
} }
// 注意:实际项目中可能需要先检查是否有文章引用该分类 // 注意:实际项目中可能需要先检查是否有文章引用该分类
// 如果有,可能需要先处理文章或者禁止删除 // 如果有,可能需要先处理文章或者禁止删除
categoryRepository.deleteById(id); categoryRepository.deleteById(id);
@@ -130,7 +130,7 @@ public class CategoryService implements ICategoryService {
if (typename == null || typename.trim().isEmpty()) { if (typename == null || typename.trim().isEmpty()) {
return ResponseMessage.failure("分类名称不能为空"); return ResponseMessage.failure("分类名称不能为空");
} }
List<Category> categories = categoryRepository.findByTypenameContaining(typename); List<Category> categories = categoryRepository.findByTypenameContaining(typename);
return ResponseMessage.success(categories); return ResponseMessage.success(categories);
} catch (DataAccessException e) { } catch (DataAccessException e) {

View File

@@ -8,39 +8,72 @@ import java.util.List;
public interface IArticleService { public interface IArticleService {
ResponseMessage<Article> getArticleById(String id); ResponseMessage<Article> getArticleById(String id);
ResponseMessage<List<Article>> getAllArticles(); ResponseMessage<List<Article>> getAllArticles();
/** /**
* 根据标题查询文章列表 * 根据标题查询文章列表
*
* @param title 文章标题的一部分,用于模糊查询 * @param title 文章标题的一部分,用于模糊查询
* @return 返回符合查询条件的文章列表 * @return 返回符合查询条件的文章列表
*/ */
ResponseMessage<List<Article>> getArticlesByTitle(String title); ResponseMessage<List<Article>> getArticlesByTitle(String title);
/**
* 创建新文章
* 仅限AUTHOR角色用户访问
*
* @param articleDto 包含文章数据的DTO对象
* @return 返回包含新创建文章信息的ResponseMessage对象
*/
ResponseMessage<Article> saveArticle(ArticleDto articleDto); ResponseMessage<Article> saveArticle(ArticleDto articleDto);
/**
* 更新指定ID的文章
*
* @param id 文章ID
* @param articleDto 包含更新信息的ArticleDto对象
* @return 返回包含操作结果的ResponseMessage对象
*/
ResponseMessage<Article> updateArticle(Integer id, ArticleDto articleDto); ResponseMessage<Article> updateArticle(Integer id, ArticleDto articleDto);
/**
* 删除指定ID的文章
*
* @param id 文章ID
* @return 返回包含操作结果的ResponseMessage对象
*/
ResponseMessage<Article> deleteArticle(Integer id); ResponseMessage<Article> deleteArticle(Integer id);
/** /**
* 根据分类ID查询文章列表兼容旧接口 * 根据分类ID查询文章列表兼容旧接口
*
* @param typeid 分类ID * @param typeid 分类ID
* @return 返回符合查询条件的文章列表 * @return 返回符合查询条件的文章列表
*/ */
ResponseMessage<List<Article>> getArticlesByCategory(Integer typeid); ResponseMessage<List<Article>> getArticlesByCategory(Integer typeid);
/** /**
* 根据属性ID查询文章列表 * 根据属性ID查询文章列表
*
* @param attributeid 属性ID * @param attributeid 属性ID
* @return 返回符合查询条件的文章列表 * @return 返回符合查询条件的文章列表
*/ */
ResponseMessage<List<Article>> getArticlesByAttribute(Integer attributeid); ResponseMessage<List<Article>> getArticlesByAttribute(Integer attributeid);
/** /**
* 根据属性ID查询最新文章列表 * 根据属性ID查询最新文章列表
*
* @param attributeid 属性ID * @param attributeid 属性ID
* @return 返回符合查询条件的最新文章列表 * @return 返回符合查询条件的最新文章列表
*/ */
ResponseMessage<List<Article>> getLatestArticlesByAttribute(Integer attributeid); ResponseMessage<List<Article>> getLatestArticlesByAttribute(Integer attributeid);
ResponseMessage<List<Article>> getMostViewedArticles(); ResponseMessage<List<Article>> getMostViewedArticles();
/** /**
* 增加文章浏览量 * 增加文章浏览量
*
* @param id 文章ID * @param id 文章ID
* @return 返回包含更新后文章信息的ResponseMessage对象 * @return 返回包含更新后文章信息的ResponseMessage对象
*/ */

View File

@@ -7,62 +7,84 @@ import com.qf.myafterprojecy.pojo.dto.MessageDto;
import java.util.List; import java.util.List;
public interface IMessageService { public interface IMessageService {
/** /**
* 获取所有消息的方法 * 获取所有消息的方法
* @return 返回一个ResponseMessage对象其中包含一个可迭代的Message集合 *
* ResponseMessage是响应消息的包装类Iterable<Message>表示可迭代的消息集合 * @return 返回一个ResponseMessage对象其中包含一个可迭代的Message集合
*/ * ResponseMessage是响应消息的包装类Iterable<Message>表示可迭代的消息集合
*/
ResponseMessage<Iterable<Message>> getAllMessages(); ResponseMessage<Iterable<Message>> getAllMessages();
/**
* 根据消息ID获取消息的方法 /**
* @param id 消息的唯一标识符 * 根据消息ID获取消息的方法
* @return ResponseMessage<Message> 包含消息的响应对象其中Message为消息的具体内容 *
*/ * @param id 消息的唯一标识符
* @return ResponseMessage<Message> 包含消息的响应对象其中Message为消息的具体内容
*/
ResponseMessage<Message> getMessageById(Integer id); ResponseMessage<Message> getMessageById(Integer id);
/**
* 保存消息的方法 /**
* @param message 消息数据传输对象,包含需要保存消息信息 * 保存消息的方法
* @return ResponseMessage<Message> 返回一个响应消息对象,包含操作结果和保存后的消息信息 *
*/ * @param message 消息数据传输对象,包含需要保存的消息信息
* @return ResponseMessage<Message> 返回一个响应消息对象,包含操作结果和保存后的消息信息
*/
ResponseMessage<Message> saveMessage(MessageDto message); ResponseMessage<Message> saveMessage(MessageDto message);
/**
* 根据消息ID删除消息的方法 /**
* @param id 要删除的消息ID * 根据消息ID删除消息的方法
* @return ResponseMessage<Message> 包含操作结果的响应消息其中泛型Message表示被删除的消息内容 *
*/ * @param id 要删除的消息ID
* @return ResponseMessage<Message> 包含操作结果的响应消息其中泛型Message表示被删除的消息内容
*/
ResponseMessage<Message> deleteMessage(Integer id); ResponseMessage<Message> deleteMessage(Integer id);
/**
* 增加消息的点赞数
*
* @param id 消息ID
* @return 包含操作结果的响应消息其中泛型Message表示操作后的消息内容
*/
ResponseMessage<Message> likeMessage(Integer id);
// 新增方法 // 新增方法
/** /**
* 根据文章ID查询消息 * 根据文章ID查询消息
*
* @param articleId 文章ID * @param articleId 文章ID
* @return 消息列表 * @return 消息列表
*/ */
ResponseMessage<List<Message>> getMessagesByArticleId(Integer articleId); ResponseMessage<List<Message>> getMessagesByArticleId(Integer articleId);
/** /**
* 查询所有父消息(根回复) * 查询所有父消息(根回复)
*
* @return 父消息列表 * @return 父消息列表
*/ */
ResponseMessage<List<Message>> getRootMessages(); ResponseMessage<List<Message>> getRootMessages();
/** /**
* 根据父消息ID查询回复 * 根据父消息ID查询回复
*
* @param parentId 父消息ID * @param parentId 父消息ID
* @return 回复消息列表 * @return 回复消息列表
*/ */
ResponseMessage<List<Message>> getRepliesByParentId(Integer parentId); ResponseMessage<List<Message>> getRepliesByParentId(Integer parentId);
/** /**
* 根据昵称模糊查询消息 * 根据昵称模糊查询消息
*
* @param nickname 昵称 * @param nickname 昵称
* @return 匹配的消息列表 * @return 匹配的消息列表
*/ */
ResponseMessage<List<Message>> searchMessagesByNickname(String nickname); ResponseMessage<List<Message>> searchMessagesByNickname(String nickname);
//删除所有评论
// 删除所有评论
ResponseMessage<Void> deleteAllMessages(); ResponseMessage<Void> deleteAllMessages();
/** /**
* 获取指定文章的评论数量 * 获取指定文章的评论数量
*
* @param articleId 文章ID * @param articleId 文章ID
* @return 评论数量 * @return 评论数量
*/ */

View File

@@ -16,11 +16,13 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.springframework.transaction.annotation.Transactional;
@Service @Service
public class MessageService implements IMessageService { public class MessageService implements IMessageService {
private static final Logger logger = LoggerFactory.getLogger(MessageService.class); private static final Logger logger = LoggerFactory.getLogger(MessageService.class);
@Autowired @Autowired
private MessageRepository messageRepository; private MessageRepository messageRepository;
@@ -42,7 +44,7 @@ public class MessageService implements IMessageService {
logger.warn("获取消息时ID无效: {}", id); logger.warn("获取消息时ID无效: {}", id);
return ResponseMessage.failure("消息ID无效"); return ResponseMessage.failure("消息ID无效");
} }
try { try {
logger.info("根据ID查询消息: {}", id); logger.info("根据ID查询消息: {}", id);
Optional<Message> messageOptional = messageRepository.findById(id); Optional<Message> messageOptional = messageRepository.findById(id);
@@ -59,31 +61,33 @@ public class MessageService implements IMessageService {
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public ResponseMessage<Message> saveMessage(MessageDto messageDto) { public ResponseMessage<Message> saveMessage(MessageDto messageDto) {
// 参数校验 // 参数校验
if (messageDto == null) { if (messageDto == null) {
logger.warn("保存消息时参数为空"); logger.warn("保存消息时参数为空");
throw new IllegalArgumentException("MessageDto cannot be null"); throw new IllegalArgumentException("MessageDto cannot be null");
} }
// 业务逻辑校验 // 业务逻辑校验
if (StringUtils.isEmpty(messageDto.getContent())) { if (StringUtils.isEmpty(messageDto.getContent())) {
logger.warn("保存消息时内容为空"); logger.warn("保存消息时内容为空");
throw new IllegalArgumentException("Message content cannot be empty"); throw new IllegalArgumentException("Message content cannot be empty");
} }
if (StringUtils.isEmpty(messageDto.getNickname())) { if (StringUtils.isEmpty(messageDto.getNickname())) {
logger.warn("保存消息时昵称为空"); logger.warn("保存消息时昵称为空");
throw new IllegalArgumentException("Message nickname cannot be empty"); throw new IllegalArgumentException("Message nickname cannot be empty");
} }
// 调用Repository保存数据 // 调用Repository保存数据
try { try {
logger.info("保存消息: {}", messageDto.getNickname()); logger.info("保存消息: {}", messageDto.getNickname());
Message message = new Message(); Message message = new Message();
BeanUtils.copyProperties(messageDto, message); BeanUtils.copyProperties(messageDto, message);
message.setCreatedAt(new Date()); // 设置创建时间 message.setCreatedAt(new Date()); // 设置创建时间
message.setLikes(0); // 设置点赞数初始值为0
// 如果是回复确保parentid有效 // 如果是回复确保parentid有效
if (messageDto.getParentid() != null && messageDto.getParentid() > 0) { if (messageDto.getParentid() != null && messageDto.getParentid() > 0) {
if (!messageRepository.existsById(messageDto.getParentid())) { if (!messageRepository.existsById(messageDto.getParentid())) {
@@ -91,7 +95,7 @@ public class MessageService implements IMessageService {
return ResponseMessage.failure("回复的父消息不存在"); return ResponseMessage.failure("回复的父消息不存在");
} }
} }
Message savedMessage = messageRepository.save(message); Message savedMessage = messageRepository.save(message);
logger.info("消息保存成功: {}", savedMessage.getMessageid()); logger.info("消息保存成功: {}", savedMessage.getMessageid());
return ResponseMessage.success(savedMessage, "保存成功", true); return ResponseMessage.success(savedMessage, "保存成功", true);
@@ -102,12 +106,13 @@ public class MessageService implements IMessageService {
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public ResponseMessage<Message> deleteMessage(Integer id) { public ResponseMessage<Message> deleteMessage(Integer id) {
if (id == null || id <= 0) { if (id == null || id <= 0) {
logger.warn("删除消息时ID无效: {}", id); logger.warn("删除消息时ID无效: {}", id);
return ResponseMessage.failure("消息ID无效"); return ResponseMessage.failure("消息ID无效");
} }
try { try {
logger.info("删除消息: {}", id); logger.info("删除消息: {}", id);
if (messageRepository.existsById(id)) { if (messageRepository.existsById(id)) {
@@ -136,7 +141,7 @@ public class MessageService implements IMessageService {
logger.warn("根据文章ID查询消息时ID无效: {}", articleId); logger.warn("根据文章ID查询消息时ID无效: {}", articleId);
return ResponseMessage.failure("文章ID无效"); return ResponseMessage.failure("文章ID无效");
} }
try { try {
logger.info("根据文章ID查询消息: {}", articleId); logger.info("根据文章ID查询消息: {}", articleId);
List<Message> messages = messageRepository.findByArticleid(articleId); List<Message> messages = messageRepository.findByArticleid(articleId);
@@ -175,13 +180,32 @@ public class MessageService implements IMessageService {
} }
} }
// 点赞数增加
@Override
@Transactional(rollbackFor = Exception.class)
public ResponseMessage<Message> likeMessage(Integer id) {
if (id == null || id <= 0) {
logger.warn("点赞消息时ID无效: {}", id);
return ResponseMessage.failure("消息ID无效");
}
try {
logger.info("点赞消息: {}", id);
messageRepository.incrementLikes(id);
Message likedMessage = messageRepository.findById(id).orElse(null);
return ResponseMessage.success(likedMessage, "点赞成功", true);
} catch (DataAccessException e) {
logger.error("点赞消息失败: {}", id, e);
return ResponseMessage.failure("点赞消息失败:" + e.getMessage());
}
}
@Override @Override
public ResponseMessage<List<Message>> searchMessagesByNickname(String nickname) { public ResponseMessage<List<Message>> searchMessagesByNickname(String nickname) {
if (StringUtils.isEmpty(nickname)) { if (StringUtils.isEmpty(nickname)) {
logger.warn("根据昵称查询消息时昵称为空"); logger.warn("根据昵称查询消息时昵称为空");
return ResponseMessage.failure("昵称不能为空"); return ResponseMessage.failure("昵称不能为空");
} }
try { try {
logger.info("根据昵称查询消息: {}", nickname); logger.info("根据昵称查询消息: {}", nickname);
List<Message> messages = messageRepository.findByNicknameContaining(nickname); List<Message> messages = messageRepository.findByNicknameContaining(nickname);
@@ -191,8 +215,10 @@ public class MessageService implements IMessageService {
return ResponseMessage.failure("查询消息失败:" + e.getMessage()); return ResponseMessage.failure("查询消息失败:" + e.getMessage());
} }
} }
//删除所有评论
// 删除所有评论
@Override @Override
@Transactional(rollbackFor = Exception.class)
public ResponseMessage<Void> deleteAllMessages() { public ResponseMessage<Void> deleteAllMessages() {
try { try {
logger.info("删除所有消息"); logger.info("删除所有消息");
@@ -203,13 +229,14 @@ public class MessageService implements IMessageService {
return ResponseMessage.failure("删除消息失败:" + e.getMessage()); return ResponseMessage.failure("删除消息失败:" + e.getMessage());
} }
} }
@Override @Override
public ResponseMessage<Long> getMessageCountByArticleId(Integer articleId) { public ResponseMessage<Long> getMessageCountByArticleId(Integer articleId) {
if (articleId == null || articleId <= 0) { if (articleId == null || articleId <= 0) {
logger.warn("获取文章评论数量时ID无效: {}", articleId); logger.warn("获取文章评论数量时ID无效: {}", articleId);
return ResponseMessage.failure("文章ID无效"); return ResponseMessage.failure("文章ID无效");
} }
try { try {
logger.info("获取文章评论数量: {}", articleId); logger.info("获取文章评论数量: {}", articleId);
Long count = messageRepository.countByArticleId(articleId); Long count = messageRepository.countByArticleId(articleId);