1.实体类和表结构
2. 新增文章分类
接口文档
实现
完整代码放在校验部分
结果:
参数校验(Validation自定义)
对state的校验(已发布|草稿),已有的注解不能满足校验需求,这时就需要自定义校验注解
步骤:
- 自定义注解State(里面必须提供三个属性message,groups,payload)
- 自定义校验数据的类StateValidation实现ConstraintValidator接口(需要重写isValid这个方法,方法内部提供校验规则)
- 在需要校验的地方使用自定义注解(Validation会解析到我们自定义的注解@State,解析到了之后就能够找到这个注解,并且解析到这个注解上组合的另外一个注解@Constraint,这个注解的内部会有一个validatedBy的属性,这个属性作用指定谁来提供校验规则,比如validateBy=StateValidation.class,它就指向了我们自定义的StateValidation类,最终调用里面的isValid方法,完成参数的校验)
新建一个anno软件包,包下新建一个State接口
package org.exampletest.anno;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import org.exampletest.validation.StateValidation;
import java.lang.annotation.*;
@Documented//元注解,可以抽取到帮助文档里面的
//元注解,标识我们自定义的注解可以用在哪些地方,用在类上还是属性上还是方法上,还是参数上?
// 我们这里只用到属性上
@Target({ElementType.FIELD})
//元注解,标识这个自定义注解将来在哪个阶段会被保留,编译阶段?源码阶段?运行时阶段?
// 我们这里需要保留到运行时阶段
@Retention(RetentionPolicy.RUNTIME)//元注解,标识这个自定义注解将来在哪个阶段会被保留,编译阶段?源码阶段?运行时阶段?我们这里需要保留到运行时阶段
@Constraint(validatedBy = {StateValidation.class})//元注解,标识这个注解的校验逻辑由哪个类实现
public @interface State {
// 提供校验失败后的提示信息
String message() default "state参数的值只能时已发布或者草稿";
//指定分组
Class<?>[] groups() default {};
// 负载,获取到state注解的附加信息
Class<? extends Payload>[] payload() default {};
}
新建一个软件包validation,包下新建一个StateValidation类
package org.exampletest.validation;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.exampletest.anno.State;
// implements ConstraintValidator<给哪个注解提供校验规则,校验的数据类型>
public class StateValidation implements ConstraintValidator<State,String> {
/**
*
* @param value 将来要校验的数据
* @param context
* @return 返回false,校验不通过,返回true校验通过
*/
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
//提供校验规则
if(value ==null){
return false;
}
if(value.equals("已发布") || value.equals("草稿")){
return true;
}
return false;
}
}
在Article属性上添加注解:
package org.exampletest.pojo;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
import org.exampletest.anno.State;
import org.hibernate.validator.constraints.URL;
import java.time.LocalDateTime;
@Data
public class Article {
private Integer id;//主键ID
@NotEmpty
@Pattern(regexp="^\\S{1,10}$")
private String title;//文章标题
@NotEmpty
private String content;//文章内容
@NotEmpty
@URL
private String coverImg;//封面图像
@State
private String state;//发布状态 已发布|草稿
@NotNull
private Integer categoryId;//文章分类id
private Integer createUser;//创建人ID
private LocalDateTime createTime;//创建时间
private LocalDateTime updateTime;//更新时间
}
service层代码:
package org.exampletest.service;
import org.exampletest.pojo.Article;
public interface ArticleService {
void add(Article article);
}
service层接口实现:
package org.exampletest.service.impl;
import org.exampletest.mapper.ArticleMapper;
import org.exampletest.pojo.Article;
import org.exampletest.service.ArticleService;
import org.exampletest.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Map;
@Service
public class ArticleServicempl implements ArticleService {
@Autowired
private ArticleMapper articleMapper;
@Override
public void add(Article article) {
//补充属性值
article.setCreateTime(LocalDateTime.now());
article.setUpdateTime(LocalDateTime.now());
Map<String,Object> map=ThreadLocalUtil.get();
Integer userId = (Integer)map.get("id");
article.setCreateUser(userId);
articleMapper.add(article);
}
}
Mapper层:
package org.exampletest.mapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.exampletest.pojo.Article;
@Mapper
public interface ArticleMapper {
//新增
@Insert("insert into article(title,content,cover_img,state,category_id,create_user,create_time,update_time)"+
"values (#{title},#{content},#{coverImg},#{state},#{categoryId},#{createUser},#{createTime},#{updateTime})")
void add(Article article);
}
2.文章列表(条件分页)
接口文档
实现
在controller里面添加方法,方法的返回类型为Result<PageBean<Article>>,(PageBean是我们自定义的一个对象,用来封装分页查询的结果,做分页查询的时候一般都会定义这个一个对象,里面至少包含两个属性,一个是total代表总条数,一个是items代表的是当前页面的数据集合)
方法上需要声明四个参数,分别接收前端传来四个参数。其中categoryId,state这两个参数是非必须传递的,因此需要在这两个参数前添加一个@RequestParam(required=false)注解,告诉MVC框架,这两个参数是非必须的。
在service层里面首先要构建一个PageBean对象,用它来封装将来查询的数据。
分页查询将来会借助mybatis提供的分页插件PageHelper,使用pageHelper进行分页查询的话,只需要在调用map的方法执行SQL之前,开启分页查询。(需要在pom.mxl文件中导入pagehelper的坐标)
<!--PageHelper坐标-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.6</version>
</dependency>
开启分页查询之后,调用map方法执行SQL就可以了。然后是条件搜索,前端有可能会传也可以不传,所以SQL不能写死,需要使用到myBatis的动态SQL技术来编写这段SQL了
代码:Controller层
@GetMapping
public Result<PageBean<Article>> list(
Integer pageNum,
Integer pageSize,
@RequestParam(required = false) Integer categoryId,
@RequestParam(required = false) String state
){
PageBean<Article> pb= articleService.list(pageNum,pageSize,categoryId,state);
return Result.success(pb);
}
Service层
//条件分页列表查询
PageBean<Article> list(Integer pageNum, Integer pageSize, Integer categoryId, String state);
Service接口实现层
@Override
public PageBean<Article> list(Integer pageNum, Integer pageSize, Integer categoryId, String state) {
//1.创建PageBean对象
PageBean<Article> pb=new PageBean<>();
//2.开启分页查询PageHelper
PageHelper.startPage(pageNum,pageSize);
//3.调用mapper层查询
Map<String,Object>map= ThreadLocalUtil.get();
Integer userId = (Integer)map.get("id");
List<Article> as = articleMapper.list(userId, categoryId,state);
//Page中提供了方法,可以获取PageHelper分页查询后,得到的总记录条数和当前页数据,所以进行强转
Page<Article> p = (Page<Article>) as;
//把数据填充到PageBean中
pb.setTatal(p.getTotal());
pb.setItems(p.getResult());
return pb;
}
Mapper层
//查询
List<Article> list(Integer userId, Integer categoryId, String state);
在resources层下,建立与mapper相同路径的目录,新建配置文件编写映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.exampletest.mapper.ArticleMapper">
<!-- 动态SQL-->
<select id ="list" resultType="org.exampletest.pojo.Article">
select * from article
<where>
<if test="categoryId!=null">
category_id = #{categoryId}
</if>
<if test="state!=null">
and state = #{state}
</if>
and create_user = #{userId}
</where>
</select>
</mapper>
结果: