package com.aurora.controller; import com.aurora.annotation.OptLog; import com.aurora.model.dto.*; import com.aurora.enums.FilePathEnum; import com.aurora.service.ArticleService; import com.aurora.strategy.context.ArticleImportStrategyContext; import com.aurora.strategy.context.UploadStrategyContext; import com.aurora.model.vo.*; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.validation.Valid; import java.util.List; import static com.aurora.constant.OptTypeConstant.*; //API(Application Programming Interface,应用程序编程接口)就像是一个软件服务员 // 它定义了一套明确的规则,让不同的软件应用能够安全、高效地相互“对话”和协作,而无需了解对方内部的复杂细节 //使用Swagger注解标记本类为API的"文章模块"分组,方便生成交互式文档 @Api(tags = "文章模块") //类定义,@Api注解来自Swagger,用于分组API文档,给API接口添加标签 @RestController //一个REST控制器,返回数据而非视图,返回数据通常为JSON格式,结合了@Controller和@ResponseBody,用于REST API public class ArticleController { //每个API方法使用@GetMapping、@PostMapping等,对应HTTP方法 //使用依赖注入自动装配ArticleService,避免手动实例化(推荐构造函数注入,但字段注入常见于简单场景) @Autowired //字段注入:@Autowired 用于依赖注入 private ArticleService articleService; @Autowired private UploadStrategyContext uploadStrategyContext; // 注入文件上传策略上下文,用于处理文件存储(如文章图片) @Autowired private ArticleImportStrategyContext articleImportStrategyContext; // 注入文章导入策略上下文,支持多种格式的文章导入(如Markdown、Word) // 获取置顶和推荐文章:HTTP GET请求,路径为/articles/topAndFeatured @ApiOperation("获取置顶和推荐文章") @GetMapping("/articles/topAndFeatured") public ResultVO listTopAndFeaturedArticles() { return ResultVO.ok(articleService.listTopAndFeaturedArticles());// 调用Service层方法,返回统一封装的结果对象ResultVO } // 获取所有文章列表(分页卡片形式) @ApiOperation("获取所有文章") @GetMapping("/articles/all") //返回值是ResultVO>,其中ResultVO是统一的返回结果包装类 //PageResultDTO是分页结果的封装类,ArticleCardDTO是文章卡片形式的数据传输对象(只包含文章列表展示需要的信息,比如标题、简介) public ResultVO> listArticles() { return ResultVO.ok(articleService.listArticles()); } // 根据分类ID查询文章:使用@RequestParam接收URL查询参数(如?categoryId=1) @ApiOperation("根据分类id获取文章") @GetMapping("/articles/categoryId") public ResultVO> getArticlesByCategoryId(@RequestParam Integer categoryId) { //@RequestParam用来接收URL查询参数(就是URL中?后面的参数),如果@RequestParam后没写参数名,默认会匹配和方法名参数一致的查询参数 return ResultVO.ok(articleService.listArticlesByCategoryId(categoryId)); //PageResultDTO为分页文章卡片数据 } // 根据文章ID获取详情:使用@PathVariable从URL路径中提取参数(如/articles/1) @ApiOperation("根据id获取文章") //是Swagger相关的注解,用来给接口添加说明,方便生成接口文档让开发、测试人员查看 @GetMapping("/articles/{articleId}") //@GetMapping表示这是一个处理GET请求的接口,接口路径为/articles/{articleId} //其中{articleId}是一个路径参数占位符比如请求/articles/1时,1就会作为articleId的值 public ResultVO getArticleById(@PathVariable("articleId") Integer articleId) { //@PathVariable("articleId"):用于从URL路径中提取和占位符所对应的参数,把它赋值给方法参数Integer articleId return ResultVO.ok(articleService.getArticleById(articleId)); //调用articleService(业务对象)的getArticleById方法,传入获取到的articleId来查询文章详情 //最后用ResultVO.ok()把查询到的ArticleDTO(文章数据传输对象)包装成统一的返回结果并返回 } // 校验文章访问密码:@RequestBody接收JSON格式的密码对象 @ApiOperation("校验文章访问密码") @PostMapping("/articles/access")//处理post请求的接口。请求路径为/articles/access(post请求更适合传递密码这类私密数据) public ResultVO accessArticle(@Valid @RequestBody ArticlePasswordVO articlePasswordVO) { // @Valid触发参数校验,确保ArticlePasswordVO对象中的参数符合约束(如非空,密码格式,必填) //@RequestBody表示把请求体(RequestBody)中的JSON数据转换为ArticlePasswordVO类型的对象articlePasswordVO //调用业务对象articleService的accessArticle方法,传入密码参数对象进行校验,校验完成后通过ResultVO.ok()返回成功的统一结果 articleService.accessArticle(articlePasswordVO); return ResultVO.ok();// 返回空结果表示成功 } @ApiOperation("根据标签id获取文章") @GetMapping("/articles/tagId") public ResultVO> listArticlesByTagId(@RequestParam Integer tagId) { return ResultVO.ok(articleService.listArticlesByTagId(tagId)); } @ApiOperation("获取所有文章归档") //获取文章归档列表(按时间分组) @GetMapping("/archives/all") //无参数 public ResultVO> listArchives() { //是文章归档的数据传输对象(包含年月,对应的文章数量等信息) return ResultVO.ok(articleService.listArchives()); } @ApiOperation("获取后台文章") @GetMapping("/admin/articles") //路径带/admin说明是后台接口,通常需要权限 public ResultVO> listArticlesAdmin(ConditionVO conditionVO) { //ConditionVO conditionVO是用来传递查询条件,比如文章标题、状态等筛选条件,是一个条件封装的VO(Value Object,值对象)类 //ArticleAdminDTO是后台文章的数据传输对象(会包含更多的管理相关的信息) return ResultVO.ok(articleService.listArticlesAdmin(conditionVO)); } // 保存或更新文章:@RequestBody接收文章数据,@Valid触发校验 @OptLog(optType = SAVE_OR_UPDATE) //项目里自定义注解,记录操作日志(如保存/更新),作用是自动记录该接口的操作日志 @ApiOperation("保存和修改文章") @PostMapping("/admin/articles") public ResultVO saveOrUpdateArticle(@Valid @RequestBody ArticleVO articleVO) { //@Valid触发对ArticleVO对象的参数校验(比如文章标题不为空,内容长度是否符合要求等),需要在ArticleVO的属性上配置@NotBlank、@Length等校验注解 //@RequestBody:将前端传递到请求体(JSON形式)的文章数据,转换成ArticleVO类型的对象articleVO articleService.saveOrUpdateArticle(articleVO); return ResultVO.ok(); } @OptLog(optType = UPDATE) @ApiOperation("修改文章是否置顶和推荐") @PutMapping("/admin/articles/topAndFeatured") //处理PUT请求的后台接口(PUT常用于更新数据) public ResultVO updateArticleTopAndFeatured(@Valid @RequestBody ArticleTopFeaturedVO articleTopFeaturedVO) { //@RequestBody将请求体中JSON格式的“文章ID+置顶状态+推荐状态”数据,转换成ArticleTopFeaturedVO类型的对象articleTopFeaturedVO articleService.updateArticleTopAndFeatured(articleTopFeaturedVO); return ResultVO.ok(); } // 逻辑删除或恢复文章(通过更新状态字段而非物理删除),不是从数据库删除,而是通过修改文章的“状态字段” @ApiOperation("删除或者恢复文章") @PutMapping("/admin/articles") public ResultVO updateArticleDelete(@Valid @RequestBody DeleteVO deleteVO) { articleService.updateArticleDelete(deleteVO); return ResultVO.ok(); } //直接从数据库删除文章,无法恢复 @OptLog(optType = DELETE) @ApiOperation(value = "物理删除文章") @DeleteMapping("/admin/articles/delete") //处理DELETE请求的后台接口(DELETE请求专门用于删除类操作) public ResultVO deleteArticles(@RequestBody List articleIds) { //@RequestBody:将请求体中JSON形式的文章ID列表(List articleIds)转换成相应的集合对象,比如前端传递[1,2,3],就会对应删除ID为1,2,3的文章 articleService.deleteArticles(articleIds); return ResultVO.ok(); } // 上传文章图片:MultipartFile接收文件,返回图片访问路径 @OptLog(optType = UPLOAD) //表示“上传”类型的操作,用来自动记录“上传文章图片”的操作日志 @ApiOperation("上传文章图片") @ApiImplicitParam(name = "file", value = "文章图片", required = true, dataType = "MultipartFile") // 给Swagger文档补充参数说明,参数名file,含义是“文章图片”,为必填项,数据类型为MultipartFile(Spring中专门用来接收上传文件的类型) @PostMapping("/admin/articles/images") public ResultVO saveArticleImages(MultipartFile file) { // 通过策略上下文上传文件,FilePathEnum指定存储路径 //参数MultipartFile:接受前端上传的图片文件 //返回值ResultVO:返回图片的访问路径(字符串形式,比如/upload/artic;e/202505/123.jpg) return ResultVO.ok(uploadStrategyContext.executeUploadStrategy(file, FilePathEnum.ARTICLE.getPath())); } // 后台根据文章ID获取详情(可能包含敏感字段) @ApiOperation("根据id查看后台文章") @ApiImplicitParam(name = "articleId", value = "文章id", required = true, dataType = "Integer") @GetMapping("/admin/articles/{articleId}")//{articleId}为路径参数,比如查询ID为。。的文章 public ResultVO getArticleBackById(@PathVariable("articleId") Integer articleId) { //参数@PathVariable:将URL路径中{articleId}对应的数值转换成Integer类型的参数articleId //ArticleAdminViewDTO是后台文章详情的数据传输对象,包含文章的完整信息(含敏感字段) return ResultVO.ok(articleService.getArticleByIdAdmin(articleId)); } // 导入文章:文件+类型参数,支持多种格式 @OptLog(optType = UPLOAD) @ApiOperation(value = "导入文章") @PostMapping("/admin/articles/import") public ResultVO importArticles(MultipartFile file, @RequestParam(required = false) String type) { //参数MultipartFile:接受前端上传的文章导入文件(各种格式) //@RequestParam(required = false) String type:接受文件类型参数,required=false表示类型参数可选(不传则默认形式) articleImportStrategyContext.importArticles(file, type); return ResultVO.ok(); } // 导出文章:返回导出文件的路径或ID列表 @OptLog(optType = EXPORT) //表示这是“导出”类型的操作,用来记录“到处文章”的操作日志 @ApiOperation(value = "导出文章") @ApiImplicitParam(name = "articleIdList", value = "文章id", required = true, dataType = "List") //value为必填项,数据类型List(文章ID的集合) @PostMapping("/admin/articles/export")//导出操作需传递文章ID列表,用POST请求更适合传递集合类参数 public ResultVO> exportArticles(@RequestBody List articleIds) { //@RequestBody:将请求体中JSON形式的文章ID列表转换成List类型的参数articleIds return ResultVO.ok(articleService.exportArticles(articleIds)); //调用业务层articleService.exportArticles(articleIds)执行文章导出操作,导出完成后返回文件路径/ID列表的统一结果 } // 搜索文章接口:通过ConditionVO封装搜索条件(如关键词、分类、发布时间范围等) @ApiOperation(value = "搜索文章") @GetMapping("/articles/search") public ResultVO> listArticlesBySearch(ConditionVO condition) { //ConditionVO condition:接收前端传递的搜索条件 //如果是GET请求,条件会以查询参数的形式传递,比如/articles/search?keyword=春天&pageNum=1,Spring会自动把查询参数匹配到ConditionVO的属性上) //ArticleSearchDTO是搜索结果的展示类(只包含标题、简介、发布时间等搜索结果需要的信息) return ResultVO.ok(articleService.listArticlesBySearch(condition)); } }