springboot--实战--大事件--文章分类接口开发详解
文章分类
新增文章分类
首先查看数据库表字段及实体类:
发现create_user
,这是创建人ID,这个字段的值来自于user表中的主键ID,它是用来记录将来这个分类是由哪个用户创建的,这个字段会限制用户只能操作自己创建的分类。
实体类中的属性名与字段名一一对应。
接下来明确需求:
当用户点击左侧的文章分类时,会在页面主区域展示文章分类相关的内容,在页面的右上角有一个添加分类的按钮,点击之后会出现弹窗,用户需要输入分类名称及别名,如果输入校验无错后,最终访问后台接口,完成分类的添加。
根据接口文档分析实现思路:
需要在controller层添加新的CategoryController从而完成分类模块接口的开发,以及在services层及mapper层也需要提供相关的接口方法。
而在Controller类中提供Category实体对象用来接收json数据,因此需要使用@RequestBody注解,让框架自动读取请求体中的JSON数据
以及Service层及mapper层提供对应的业务代码。
代码展示:
Controller层:
@PostMappingpublic Result save(@RequestBody Category category){categoryService.save(category);return Result.success();}
service层:
@Service@RequiredArgsConstructorpublic class CategoryServiceImpl implements CategoryService {private final CategoryMapper categoryMapper;@Overridepublic void save(Category category) {//补充属性值//获取当前用户idMap<String,Object> map = ThreadUtil.get();Integer id = (Integer) map.get("id");category.setCreateUser(id);categoryMapper.save(category);}}
mapper层:
@Mapperpublic interface CategoryMapper {@Insert("insert into category(category_name,category_alias,create_user,create_time,update_time) values(#{categoryName},#{categoryAlias},#{createUser},now(),now())")void save(Category category);}
进行测试:
查看数据库表数据:
测试成功:
发现问题:如果只传递一个参数,程序报错,但是确实在mapper层报错,说明controller层与service层直接通行,应该在实体类中添加参数校验。
public class Category {private Integer id;//主键ID@NotEmptyprivate String categoryName;// 分类名称@NotEmptyprivate String categoryAlias;// 别名private Integer createUser;// 创建者IDprivate LocalDateTime createTime;// 创建时间private LocalDateTime updateTime;// 更新时间}
而且不能同名,因此需要在进行同名校验:
public Result save(@RequestBody @Validated Category category){//判断分类名称是否已存在Category category1 = categoryService.queryCategoryFindByName(category.getCategoryName());if(category1 != null){return Result.error("该分类已存在");}categoryService.save(category);return Result.success();}
再次进行测试:
测试成功,至此新增文章分类接口完成。
文章分类列表
明确需求:
当用户点击左侧菜单中的文章分类后,要在右侧页面主区域,展示出当前用户所有的分类。这些分类数据就需要调用文章分类列表接口来获取。
根据接口文档分析实现思路:
需要在categoryController中实现方法,声明@GetMapping注解表示查询,在service层完成业务代码的编写,在mapper层编译SQL语句
代码展示:
Controller层:
@GetMappingpublic Result<List<Category>> list(){List<Category> list = categoryService.list();return Result.success(list);}
Service层:
@Overridepublic List<Category> list() {Map<String,Object> map = ThreadUtil.get();Integer id = (Integer) map.get("id");return categoryMapper.list(id);}
Mapper层:
@Select("select * from category where create_user = #{createUser}")List<Category> list(@Param("createUser") Integer createUser);
进行测试:
测试成功。
发现问题:发现前端响应数据中时间格式与接口文档中的时间格式不一致。
那么实体类对象转换成JSON字符串的时候如何指定日期格式?
添加@JsonFormat注解指定时间格式。
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private LocalDateTime createTime;// 创建时间@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private LocalDateTime updateTime;// 更新时间
再次进行测试:
测试成功,至此。文章分类列表接口完成。
获取文章分类列表详情
明确需求:
在文章分类列表中点击编辑按钮,弹出弹窗,在弹窗中需要展示被点击这个分类的详细信息,用户在原有信息的基础上进行修改,要想展示被点击分类的详细信息,就需要去调用获取文章分类详细信息的接口,拿到数据之后展示。
根据接口文档分析实现思路:
首先在CategoryController类中声明方法,添加注解,声明参数,并在service层完成业务代码,在mapper层提供SQL语句。
代码展示:
Controller层:
@GetMapping("/detail")public Result<Category> detail(Integer id){Category category = categoryService.findById(id);return Result.success(category);}
Service层:
@Overridepublic Category findById(Integer id) {return categoryMapper.findById(id);}
Mapper层:
@Select("select * from category where id = #{id}")Category findById(Integer id);
进行测试:
测试成功,至此获取文章分类列表详情接口完成。
更新文章分类
明确需求:当用户点击编辑按钮后,在弹窗中显示列表信息,接下来用户可以在输入框中区根据原有的内容进行修改,如果确认没有问题,就访问后台的接口完成分类数据的更新。
根据接口文档分析实现思路:
在Controller层声明方法,并添加@RequestBody @Validated注解,声明传入参数,依旧是service层解决业务代码,mapper层解决SQL注入。
代码展示:
Controller层:
@PutMappingpublic Result update(@RequestBody @Validated Category category){categoryService.update(category);return Result.success();}
实体类:
@Data@AllArgsConstructor@NoArgsConstructorpublic class Category {@NotNullprivate Integer id;//主键ID@NotEmptyprivate String categoryName;// 分类名称@NotEmptyprivate String categoryAlias;// 别名private Integer createUser;// 创建者ID@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private LocalDateTime createTime;// 创建时间@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private LocalDateTime updateTime;// 更新时间
Service层:
@Overridepublic void update(Category category) {category.setUpdateTime(LocalDateTime.now());categoryMapper.update(category);}
Mapper层:
@Update("update category set category_name = #{categoryName},category_alias = #{categoryAlias},create_time = #{createTime} where id = #{id}")void update(Category category);
进行测试:
测试成功,查看数据库:
测试成功。
发现问题:在校验参数时,在实体类中id上添加了@NotNull注解,并且新增文章列表接口与更新文章列表接口的传入参数都是一致的实体类,这就导致我们新增文章列表的接口被拦截,因为该接口传入的参数中id为null,因此被校验出来,拦截。
解决方案:将校验项进行分组,添加与更新的校验规则分离即可,这就需要使用Validation中的分组校验
前置知识:Validation中的分组校验
把校验项进行归类分组,在完成不同的功能的时候,校验指定组中的校验项。
实现步骤:
-
定义分组
-
定义校验项时指定归属的分组
-
校验时指定要校验的分组
注意事项:在@Validated注解中有一个group参数,就是用来指定归属的分组的
代码展示:
1.定义分组
public interface Save{}public interface Update{}
2.定义校验项时指定归属的分组
@NotNull(groups = Update.class)private Integer id;//主键ID@NotEmpty(groups = {Save.class, Update.class})private String categoryName;// 分类名称@NotEmpty(groups = {Save.class, Update.class})
3.校验时指定要校验的分组
@PostMappingpublic Result save(@RequestBody @Validated(Category.Save.class) Category category){//判断分类名称是否已存在Category category1 = categoryService.queryCategoryFindByName(category.getCategoryName());if(category1 != null){return Result.error("该分类已存在");}categoryService.save(category);return Result.success();}@PutMappingpublic Result update(@RequestBody @Validated(Category.Update.class) Category category){categoryService.update(category);return Result.success();}
进行新增接口测试:
进行更新接口测试:
测试成功。
注意事项:
如果同一个校验项属于多个分组,就需要写多个分组的名字,尤其是当校验项较多时,比较麻烦,我们可以借助于Validation中的默认分组优化。
代码展示:
public class Category {@NotNull(groups = Update.class)private Integer id;//主键ID@NotEmptyprivate String categoryName;// 分类名称@NotEmptyprivate String categoryAlias;// 别名private Integer createUser;// 创建者ID@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private LocalDateTime createTime;// 创建时间@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private LocalDateTime updateTime;// 更新时间//如果说某个校验项没有指定分组,默认属于default分组//分组之间可以继承,A extends B 那么A拥有B中所有的校验项// 分组public interface Save extends Default {}// 分组public interface Update extends Default{}
再次进行测试新增接口:
测试成功,查看数据库
再次进行测试更新接口:
查看数据库:
至此,更新文章分类接口完成。
注意事项:定义校验项时如果没有指定分组,则属于Default分组,分组之间可以继承。
总结:
-
如何定义分组? 在实体类内部定义接口
-
如何对校验项分组? 通过groups属性指定
-
校验如何指定分组? 通过@Validated注解的value属性赋值
-
校验项默认属于什么组? Default
删除文章分类
练习:
代码展示:
Controller:
@DeleteMappingpublic Result delete(Integer id){categoryService.delete(id);return Result.success();}
Service层:
@Overridepublic void delete(Integer id) {categoryMapper.delete(id);}
Mapper层:
@Delete("delete from category where id = #{id}")void delete(Integer id);
进行测试:
测试成功,查看数据库:
至此,文章分类所有接口均已完成。
希望对大家有所帮助,让我们一起进步