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校验通过*/@Overridepublic 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;//文章标题@NotEmptyprivate String content;//文章内容@NotEmpty@URLprivate String coverImg;//封面图像@Stateprivate String state;//发布状态 已发布|草稿@NotNullprivate Integer categoryId;//文章分类idprivate Integer createUser;//创建人IDprivate 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 {@Autowiredprivate ArticleMapper articleMapper;@Overridepublic 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层
@GetMappingpublic 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接口实现层
@Overridepublic PageBean<Article> list(Integer pageNum, Integer pageSize, Integer categoryId, String state) {//1.创建PageBean对象PageBean<Article> pb=new PageBean<>();//2.开启分页查询PageHelperPageHelper.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 mapperPUBLIC "-//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>
结果: