



在接口开发的过程中,一个非常重要的原则就是不信任任何的输入,开发者根本不知道传递的是什么参数,因此需要对入参进行参数的校验,否则极有可能引发系统故障,或者造成业务数据的错误。
以前,开发者经常在Controller中对参数进行if…else判断,如果参数不符合要求,就提示用户参数错误,流程不再进行下去,类似下面的代码:
package com.springboot.demo;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController1 {
/**
* 保存新的用户
* @param user
*/
@PostMapping("/save")
public void saveUser(@RequestBody User user) {
if (user.getAge() > 120) {
throw new IllegalArgumentException("最大年龄小于120");
}
if (user.getAge() < 1) {
throw new IllegalArgumentException("最小年龄大于1");
}
if (user.getUserName() == null) {
throw new IllegalArgumentException("用户名不能为空");
}
if (user.getUserName().length() > 10) {
throw new IllegalArgumentException("用户名长度不能超过10");
}
if(user.getPassword()==null){
throw new IllegalArgumentException("密码不能为空");
}
//saveTheUser
}
}
以上代码中对应的User实体类的代码如下:
package com.springboot.demo;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
@Data
public class User {
@Id
@GeneratedValue
private long id;
@Column(nullable = false, unique = true)
private String userName;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private int age;
}
Controller中的if代码能够满足参数校验功能的需要,但是代码逻辑非常“丑陋”,没有一点优雅、复用性可言。Spring Boot中是怎么处理的呢?
在Spring Boot项目中,可以使用Spring Boot Validate进行参数的校验,开发人员只需要简单地标记注解就能完成参数的校验。下面演示Spring Boot的参数校验。
(1)在pom.xml中添加校验的依赖如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
(2)首先新建包com.springboot.demo,再新建一个类UserController2用于参数校验,执行新建用户的保存方法。
package com.springboot.demo;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
public class UserController2 {
/**
* 保存新的用户
* @param user
*/
@PostMapping("/save")
public void saveUser(@Valid @RequestBody User user) {
//saveTheUser
}
}
(3)在包com.springboot.demo中新建User实体类并在其中配置校验,代码如下:
package com.springboot.demo;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.persistence.*;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
@Entity
@Data
public class User {
@Id
@GeneratedValue
private long id;
@NotBlank
@Length(max = 10, message = "用户名长度不能超过10")
@Column(nullable = false, unique = true)
private String userName;
@NotBlank(message = "密码不能为空")
@Column(nullable = false)
private String password;
@Max(value = 120, message = "最大年龄小于120")
@Min(value = 1, message = "最小年龄大于1")
@Column(nullable = false)
private int age;
}
(4)在UserController2的方法中给要校验的参数标记上@Valid注解,再使用如@Not- Blank、@Min和@Max注解并且加上提示信息就能完成参数的校验。
(5)为了系统的完整性,在Spring Boot项目中增加系统异常的处理,需要给用户返回统一的结果并在结果中提示入参的具体错误。在包com.springboot.demo中新建ValidateCommonHandler异常处理类,代码如下:
package com.springboot.demo;
import org.springframework.http.*;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.Response
EntityExceptionHandler;
public class ValidateCommonHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex,
HttpHeaders headers, HttpStatus status,
WebRequest request) {
ResponeVo vo = new ResponeVo();
vo.setCode(500);
for (FieldError fieldError : ex.getBindingResult().getFieldErrors()) {
String defaultMessage = fieldError.getDefaultMessage();
vo.setMessage(defaultMessage);
Object value = fieldError.getRejectedValue();
vo.setData(value);
break;
}
return new ResponseEntity(vo, HttpStatus.OK);
}
}
新建一个ValidateCommonHandler类继承自ResponseEntityExceptionHandler接口,并且重写该接口的handleMethodArgumentNotValid()方法,ResponseEntityExceptionHandler是统一处理所有经过Valid注解的接口,此处统一返回类ResponeVo的信息,用这个类和前端进行Restful交互,只要出现校验命中的就会执行此方法,并且携带具体的错误信息。
(6)在包com.springboot.demo中新建统一返回实体信息类ResponeVo:
package com.springboot.demo;
import lombok.Data;
@Data
public class ResponeVo {
private int code;
private String message;
private Object data;
}
上述代码中,code返回一个标识码,message字段用于返回校验的信息,data返回具体的数据。
Spring Boot Validate的参数校验依赖于注解,可以对不同类型的参数配置相应的注解校验,常用的注解如表3.1所示。
表3.1 Validate注解