refactor(service): 重构服务接口和实现类结构

将服务接口从service包移动到service.imp包
修复ArticleRepository中viewCount的COALESCE处理
添加getPublishedArticles方法获取已发布文章
优化incrementViewCount方法使用仓库直接更新
修正HelpController中README_API.md路径
This commit is contained in:
qingfeng1121
2025-10-26 20:18:35 +08:00
parent 46be613f28
commit 9132feb870
15 changed files with 87 additions and 54 deletions

View File

@@ -3,7 +3,8 @@ package com.qf.myafterprojecy.controller;
import com.qf.myafterprojecy.pojo.Article; import com.qf.myafterprojecy.pojo.Article;
import com.qf.myafterprojecy.pojo.ResponseMessage; import com.qf.myafterprojecy.pojo.ResponseMessage;
import com.qf.myafterprojecy.pojo.dto.ArticleDto; import com.qf.myafterprojecy.pojo.dto.ArticleDto;
import com.qf.myafterprojecy.service.IArticleService; import com.qf.myafterprojecy.service.imp.IArticleService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -33,7 +34,14 @@ public class ArticleController {
public ResponseMessage<Article> getArticle(@PathVariable String id) { public ResponseMessage<Article> getArticle(@PathVariable String id) {
return articleService.getArticleById(id); return articleService.getArticleById(id);
} }
/**
* 获取已发布的文章列表
* @return 返回包含已发布文章列表的ResponseMessage对象
*/
@GetMapping("/published")
public ResponseMessage<List<Article>> getPublishedArticles() {
return articleService.getPublishedArticles();
}
/** /**
* 获取所有文章列表 * 获取所有文章列表
* @return 返回包含文章列表的ResponseMessage对象 * @return 返回包含文章列表的ResponseMessage对象
@@ -62,16 +70,7 @@ public class ArticleController {
return articleService.getArticlesByAttribute(attributeId); return articleService.getArticlesByAttribute(attributeId);
} }
/** /**
* 根据分类ID获取该分类下的所有文章兼容旧接口
* @param categoryId 分类ID
* @return 返回包含文章列表的ResponseMessage对象
*/
@GetMapping("/category/{categoryId}")
public ResponseMessage<List<Article>> getArticlesByCategory(@PathVariable Integer categoryId) {
return articleService.getArticlesByCategory(categoryId);
}
/** /**
* 根据属性ID获取最新文章按创建时间降序 * 根据属性ID获取最新文章按创建时间降序
* @param attributeId 属性ID * @param attributeId 属性ID
@@ -81,14 +80,7 @@ public class ArticleController {
public ResponseMessage<List<Article>> getLatestArticlesByAttribute(@PathVariable Integer attributeId) { public ResponseMessage<List<Article>> getLatestArticlesByAttribute(@PathVariable Integer attributeId) {
return articleService.getLatestArticlesByAttribute(attributeId); return articleService.getLatestArticlesByAttribute(attributeId);
} }
/**
* 获取浏览量最高的文章列表
* @return 返回包含热门文章列表的ResponseMessage对象
*/
@GetMapping("/popular")
public ResponseMessage<List<Article>> getMostViewedArticles() {
return articleService.getMostViewedArticles();
}
/** /**
* 创建新文章 * 创建新文章
* 仅限AUTHOR角色用户访问 * 仅限AUTHOR角色用户访问

View File

@@ -3,7 +3,8 @@ package com.qf.myafterprojecy.controller;
import com.qf.myafterprojecy.pojo.Category_attribute; import com.qf.myafterprojecy.pojo.Category_attribute;
import com.qf.myafterprojecy.pojo.ResponseMessage; import com.qf.myafterprojecy.pojo.ResponseMessage;
import com.qf.myafterprojecy.pojo.dto.CategoryAttributeDto; import com.qf.myafterprojecy.pojo.dto.CategoryAttributeDto;
import com.qf.myafterprojecy.service.ICategoryAttributeService; import com.qf.myafterprojecy.service.imp.ICategoryAttributeService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -3,7 +3,8 @@ package com.qf.myafterprojecy.controller;
import com.qf.myafterprojecy.pojo.Category; import com.qf.myafterprojecy.pojo.Category;
import com.qf.myafterprojecy.pojo.ResponseMessage; import com.qf.myafterprojecy.pojo.ResponseMessage;
import com.qf.myafterprojecy.pojo.dto.CategoryDto; import com.qf.myafterprojecy.pojo.dto.CategoryDto;
import com.qf.myafterprojecy.service.ICategoryService; import com.qf.myafterprojecy.service.imp.ICategoryService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -30,31 +30,35 @@ public class HelpController {
@GetMapping @GetMapping
public ResponseMessage<String> getReadmeApi() { public ResponseMessage<String> getReadmeApi() {
try { try {
// 获取项目根目录 // 获取README_API.md文件的绝对路径
String rootPath = System.getProperty("user.dir"); String readmePath = "e:\\MyWebProject\\MyAfterProjecy\\README_API.md";
// 构建README_API.md文件路径 File readmeFile = new File(readmePath);
File readmeFile = new File(rootPath, "README_API.md");
// 检查文件是否存在 // 检查文件是否存在
if (!readmeFile.exists() || !readmeFile.isFile()) { if (readmeFile.exists() && readmeFile.isFile()) {
// 如果不存在,尝试使用类路径资源加载 // 读取文件内容
try { String markdownContent = new String(FileCopyUtils.copyToByteArray(new FileInputStream(readmeFile)), StandardCharsets.UTF_8);
ClassPathResource resource = new ClassPathResource("README_API.md"); // 将Markdown转换为HTML
String markdownContent = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()), StandardCharsets.UTF_8); String htmlContent = convertMarkdownToHtml(markdownContent);
// 将Markdown转换为HTML return ResponseMessage.success(htmlContent, "获取API文档成功");
String htmlContent = convertMarkdownToHtml(markdownContent);
return ResponseMessage.success(htmlContent, "获取API文档成功");
} catch (IOException e) {
return ResponseMessage.error("未找到README_API.md文件");
}
} }
// 读取文件内容 // 如果直接路径不存在,尝试从类路径加载
String markdownContent = new String(FileCopyUtils.copyToByteArray(new FileInputStream(readmeFile)), StandardCharsets.UTF_8); try {
// 将Markdown转换为HTML ClassPathResource resource = new ClassPathResource("README_API.md");
String htmlContent = convertMarkdownToHtml(markdownContent); String markdownContent = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()), StandardCharsets.UTF_8);
return ResponseMessage.success(htmlContent, "获取API文档成功"); // 将Markdown转换为HTML
} catch (IOException e) { String htmlContent = convertMarkdownToHtml(markdownContent);
return ResponseMessage.success(htmlContent, "获取API文档成功");
} catch (IOException e) {
// 记录详细错误信息以便调试
System.err.println("无法从类路径加载README_API.md: " + e.getMessage());
return ResponseMessage.error("未找到README_API.md文件");
}
} catch (Exception e) {
// 捕获所有异常并记录详细错误信息
System.err.println("处理README_API.md时出错: " + e.getMessage());
e.printStackTrace();
return ResponseMessage.error("读取README_API.md文件失败: " + e.getMessage()); return ResponseMessage.error("读取README_API.md文件失败: " + e.getMessage());
} }
} }

View File

@@ -3,7 +3,8 @@ package com.qf.myafterprojecy.controller;
import com.qf.myafterprojecy.pojo.Message; import com.qf.myafterprojecy.pojo.Message;
import com.qf.myafterprojecy.pojo.ResponseMessage; import com.qf.myafterprojecy.pojo.ResponseMessage;
import com.qf.myafterprojecy.pojo.dto.MessageDto; import com.qf.myafterprojecy.pojo.dto.MessageDto;
import com.qf.myafterprojecy.service.IMessageService; import com.qf.myafterprojecy.service.imp.IMessageService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -68,7 +68,7 @@ public interface ArticleRepository extends JpaRepository<Article, Integer> {
* @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 = COALESCE(a.viewCount, 0) + 1 WHERE a.articleid = :articleid")
void incrementViewCount(@Param("articleid") Integer articleid); void incrementViewCount(@Param("articleid") Integer articleid);
/** /**
@@ -79,4 +79,11 @@ public interface ArticleRepository extends JpaRepository<Article, Integer> {
*/ */
@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();
/**
* 根据状态查询文章列表
* @param status 文章状态0-草稿1-已发布2-已删除
* @return 返回符合状态条件的文章列表
*/
@Query("SELECT a FROM Article a WHERE a.status = :status")
List<Article> findByStatus(@Param("status") Integer status);
} }

View File

@@ -4,7 +4,8 @@ import com.qf.myafterprojecy.pojo.Message;
import com.qf.myafterprojecy.pojo.ResponseMessage; import com.qf.myafterprojecy.pojo.ResponseMessage;
import com.qf.myafterprojecy.pojo.dto.MessageDto; import com.qf.myafterprojecy.pojo.dto.MessageDto;
import com.qf.myafterprojecy.repository.MessageRepository; import com.qf.myafterprojecy.repository.MessageRepository;
import com.qf.myafterprojecy.service.IMessageService; import com.qf.myafterprojecy.service.imp.IMessageService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -5,6 +5,8 @@ import com.qf.myafterprojecy.pojo.ResponseMessage;
import com.qf.myafterprojecy.pojo.dto.ArticleDto; import com.qf.myafterprojecy.pojo.dto.ArticleDto;
import com.qf.myafterprojecy.repository.ArticleRepository; import com.qf.myafterprojecy.repository.ArticleRepository;
import com.qf.myafterprojecy.repository.CategoryAttributeRepository; import com.qf.myafterprojecy.repository.CategoryAttributeRepository;
import com.qf.myafterprojecy.service.imp.IArticleService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
@@ -46,7 +48,21 @@ public class ArticleService implements IArticleService {
return ResponseMessage.failure("获取文章失败"); return ResponseMessage.failure("获取文章失败");
} }
} }
/**
* 获取已发布的文章列表
* @return 返回包含已发布文章列表的ResponseMessage对象
*/
@Override
@Transactional(readOnly = true)
public ResponseMessage<List<Article>> getPublishedArticles() {
try {
List<Article> articles = articleRepository.findByStatus(1);
return ResponseMessage.success(articles);
} catch (Exception e) {
log.error("获取已发布文章列表失败: {}", e.getMessage());
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) {
@@ -178,10 +194,9 @@ public class ArticleService implements IArticleService {
Article article = articleRepository.findById(id) Article article = articleRepository.findById(id)
.orElseThrow(() -> new RuntimeException("文章不存在")); .orElseThrow(() -> new RuntimeException("文章不存在"));
article.setViewCount(article.getViewCount() + 1); articleRepository.incrementViewCount(id);
Article updatedArticle = articleRepository.save(article);
return ResponseMessage.success(updatedArticle); return ResponseMessage.success(article);
} catch (Exception e) { } catch (Exception e) {
log.error("增加文章浏览量失败: {}", e.getMessage()); log.error("增加文章浏览量失败: {}", e.getMessage());
return ResponseMessage.failure("增加文章浏览量失败"); return ResponseMessage.failure("增加文章浏览量失败");

View File

@@ -4,6 +4,8 @@ import com.qf.myafterprojecy.pojo.Category_attribute;
import com.qf.myafterprojecy.pojo.ResponseMessage; import com.qf.myafterprojecy.pojo.ResponseMessage;
import com.qf.myafterprojecy.pojo.dto.CategoryAttributeDto; import com.qf.myafterprojecy.pojo.dto.CategoryAttributeDto;
import com.qf.myafterprojecy.repository.CategoryAttributeRepository; import com.qf.myafterprojecy.repository.CategoryAttributeRepository;
import com.qf.myafterprojecy.service.imp.ICategoryAttributeService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;

View File

@@ -4,6 +4,8 @@ import com.qf.myafterprojecy.pojo.Category;
import com.qf.myafterprojecy.pojo.ResponseMessage; import com.qf.myafterprojecy.pojo.ResponseMessage;
import com.qf.myafterprojecy.pojo.dto.CategoryDto; import com.qf.myafterprojecy.pojo.dto.CategoryDto;
import com.qf.myafterprojecy.repository.CategoryRepository; import com.qf.myafterprojecy.repository.CategoryRepository;
import com.qf.myafterprojecy.service.imp.ICategoryService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;

View File

@@ -4,6 +4,8 @@ import com.qf.myafterprojecy.pojo.Message;
import com.qf.myafterprojecy.pojo.ResponseMessage; import com.qf.myafterprojecy.pojo.ResponseMessage;
import com.qf.myafterprojecy.pojo.dto.MessageDto; import com.qf.myafterprojecy.pojo.dto.MessageDto;
import com.qf.myafterprojecy.repository.MessageRepository; import com.qf.myafterprojecy.repository.MessageRepository;
import com.qf.myafterprojecy.service.imp.IMessageService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;

View File

@@ -1,4 +1,4 @@
package com.qf.myafterprojecy.service; package com.qf.myafterprojecy.service.imp;
import com.qf.myafterprojecy.pojo.Article; import com.qf.myafterprojecy.pojo.Article;
import com.qf.myafterprojecy.pojo.ResponseMessage; import com.qf.myafterprojecy.pojo.ResponseMessage;
@@ -78,4 +78,9 @@ public interface IArticleService {
* @return 返回包含更新后文章信息的ResponseMessage对象 * @return 返回包含更新后文章信息的ResponseMessage对象
*/ */
ResponseMessage<Article> incrementViewCount(Integer id); ResponseMessage<Article> incrementViewCount(Integer id);
/**
* 获取已发布的文章列表
* @return 返回包含已发布文章列表的ResponseMessage对象
*/
ResponseMessage<List<Article>> getPublishedArticles();
} }

View File

@@ -1,4 +1,4 @@
package com.qf.myafterprojecy.service; package com.qf.myafterprojecy.service.imp;
import com.qf.myafterprojecy.pojo.Category_attribute; import com.qf.myafterprojecy.pojo.Category_attribute;
import com.qf.myafterprojecy.pojo.ResponseMessage; import com.qf.myafterprojecy.pojo.ResponseMessage;

View File

@@ -1,4 +1,4 @@
package com.qf.myafterprojecy.service; package com.qf.myafterprojecy.service.imp;
import com.qf.myafterprojecy.pojo.Category; import com.qf.myafterprojecy.pojo.Category;
import com.qf.myafterprojecy.pojo.ResponseMessage; import com.qf.myafterprojecy.pojo.ResponseMessage;

View File

@@ -1,4 +1,4 @@
package com.qf.myafterprojecy.service; package com.qf.myafterprojecy.service.imp;
import com.qf.myafterprojecy.pojo.Message; import com.qf.myafterprojecy.pojo.Message;
import com.qf.myafterprojecy.pojo.ResponseMessage; import com.qf.myafterprojecy.pojo.ResponseMessage;