电子说
一、前言
一个后端接口大致分为四个部分组成: 接口地址(url)、接口请求方式(get、post等)、请求数据(request)、响应数据(response) 。虽然说后端接口的编写并没有统一规范要求,而且如何构建这几个部分每个公司要求都不同,没有什么“一定是最好的”标准,但其中最重要的关键点就是看是否规范。
二、环境说明
因为讲解的重点是后端接口,所以需要导入一个spring-boot-starter-web
包,而lombok作用是简化类,前端显示则使用了knife4j,具体使用在Spring Boot整合knife4j实现Api文档已写明。另外从springboot-2.3开始,校验包被独立成了一个starter组件,所以需要引入如下依赖:
org.springframework.bootclass="hljs-name"groupId>
spring-boot-starter-validationclass="hljs-name"artifactId>
class="hljs-name"dependency>
com.github.xiaoyminclass="hljs-name"groupId>
knife4j-spring-boot-starterclass="hljs-name"artifactId>
2.0.2class="hljs-name"version>
class="hljs-name"dependency>
org.springframework.bootclass="hljs-name"groupId>
spring-boot-starter-webclass="hljs-name"artifactId>
class="hljs-name"dependency>
org.projectlombokclass="hljs-name"groupId>
lombokclass="hljs-name"artifactId>
trueclass="hljs-name"optional>
class="hljs-name"dependency>
三、参数校验
一个接口一般对参数(请求数据)都会进行安全校验,参数校验的重要性自然不必多说,那么如何对参数进行校验就有讲究了。一般来说有三种常见的校验方式,我们使用了最简洁的第三种方法
业务层校验无需多说,即手动在java的Service层进行数据校验判断。不过这样太繁琐了,光校验代码就会有很多
而使用Validator+ BindingResult
已经是非常方便实用的参数校验方式了,在实际开发中也有很多项目就是这么做的,不过这样还是不太方便,因为你每写一个接口都要添加一个BindingResult参数,然后再提取错误信息返回给前端(简单看一下)。
@PostMapping("/addUser")
public String addUser(@RequestBody @Validated User user, BindingResult bindingResult) {
// 如果有参数校验失败,会将错误信息封装成对象组装在BindingResult里
List
内置参数校验如下:
首先Validator可以非常方便的制定校验规则,并自动帮你完成校验。首先在入参里需要校验的字段加上注解,每个注解对应不同的校验规则,并可制定校验失败后的信息:
@Data
public class User {
@NotNull(message = "用户id不能为空")
private Long id;
@NotNull(message = "用户账号不能为空")
@Size(min = 6, max = 11, message = "账号长度必须是6-11个字符")
private String account;
@NotNull(message = "用户密码不能为空")
@Size(min = 6, max = 11, message = "密码长度必须是6-16个字符")
private String password;
@NotNull(message = "用户邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
}
校验规则和错误提示信息配置完毕后,接下来只需要在接口仅需要在校验的参数上加上@Valid
注解(去掉BindingResult后会自动引发异常,异常发生了自然而然就不会执行业务逻辑):
@RestController
@RequestMapping("user")
public class ValidationController {
@Autowired
private ValidationService validationService;
@PostMapping("/addUser")
public String addUser(@RequestBody @Validated User user) {
return validationService.addUser(user);
}
}
现在我们进行测试,打开knife4j文档地址,当输入的请求数据为空时,Validator会将所有的报错信息全部进行返回,所以需要与全局异常处理一起使用。
// 使用form data方式调用接口,校验异常抛出 BindException
// 使用 json 请求体调用接口,校验异常抛出 MethodArgumentNotValidException
// 单个参数校验异常抛出ConstraintViolationException
// 处理 json 请求体调用接口校验失败抛出的异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResultVO
分组校验有三个步骤:
@Validated
注解添加分组类public interface Update extends Default{
}
@Data
public class User {
@NotNull(message = "用户id不能为空",groups = Update.class)
private Long id;
......
}
@PostMapping("update")
public String update(@Validated({Update.class}) User user) {
return "success";
}
如果Update不继承Default,@Validated({Update.class})
就只会校验属于Update.class
分组的参数字段;如果继承了,会校验了其他默认属于Default.class
分组的字段。
对于递归校验(比如类中类),只要在相应属性类上增加@Valid
注解即可实现(对于集合同样适用)
Spring Validation允许用户自定义校验,实现很简单,分两步:
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {HaveNoBlankValidator.class})// 标明由哪个类执行校验逻辑
public @interface HaveNoBlank {
// 校验出错时默认返回的消息
String message() default "字符串中不能含有空格";
Class?[] groups() default { };
Class? extends Payload[] payload() default { };
/**
* 同一个元素上指定多个该注解时使用
*/
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
public @interface List {
NotBlank[] value();
}
}
public class HaveNoBlankValidator implements ConstraintValidator<HaveNoBlank, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// null 不做检验
if (value == null) {
return true;
}
// 校验失败
return !value.contains(" ");
// 校验成功
}
}
全部0条评论
快来发表一下你的评论吧 !