请求字段的校验在接口开发中也是必不可少的,最常见的就是要判断字段必须不为空。
如上一章节的”提交学生信息”接口,如果我们要校验姓名不能为空,则需要在方法体内校验它。
/**
* 提交学生信息
*
* @param studentDto
* @return
*/
@PutMapping("/student")
public StudentDto student(@RequestBody StudentDto studentDto) throws Exception {
String name = studentDto.getName();
if (name == null || name.length() == 0) {
throw new Exception("姓名不能为空");
}
return studentDto;
}
如果提交的信息字段很多,这样在方法体内就需要对每一个字段都需要写一段这样的判断代码。
那么有没有更优雅的方式?答案肯定是有的,使用@Valid注解。
@Valid注解
首先在pom.xml引入所需的依赖包。
<!--校验组件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
打开右侧的”Maven”,点击一下左上角的小图标,这样项目就可以拉取引入这个新的依赖包。
这时候,就可以对接口的请求对象”StudentDto”进行校验。
/**
* 提交学生信息
*
* @param studentDto
* @return
*/
@PutMapping("/student")
public StudentDto student(@RequestBody @Valid StudentDto studentDto) {
return studentDto;
}
只要在”StudentDto”前面,加上@Valid注解。
/**
* 学生dto
*/
public class StudentDto {
/**
* 姓名
*/
@NotBlank(message = "姓名不能为空")
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 性别
*/
private String sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
主要在想校验的字段上面,加上@NotBlank注解,即可对这个字段进行判空校验,message参数是可以指定报错信息。
我们来运行一下项目,然后通过postman工具模拟请求,这次我们将name字段设置为空。
可以看到,返回信息状态为400 Bad Request。
我们再看看IDE控制台输出了什么信息。
校验生效了,识别到name这个字段的值不能为空(NotBlank),但是请求的字段值现在为空了,同时也看到我们定义的message信息”姓名不能为空”。
把name字段信息填上,再请求一次,看看校验会不会通过。
可以看到能正常返回,说明校验是通过了,因为这时候name字段不空了。
但是这里头又有一个问题,就是这种报错信息不够优雅, 而且前端接口也接收不到我们提示的错误信息啊。这时候,我们就需要对错误信息做一个统一的处理。
@ControllerAdvice注解 和 @ExceptionHandler注解
@ControllerAdvice
注解表示我们定义的是一个控制器增强类,当其他任何控制器发生异常且异常类型符合@ExceptionHandler
注解中指定的异常类时,原请求将会被拦截到这个我们自定义的控制器方法中。
我们来看看这两个注解结合到项目中是什么使用的。
首先,我们创建一个exception包路径,并其下创建一个控制器增强类MyExceptionHandler
package org.liurb.springboot.demo.exception;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
@RestControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public String methodArgumentNotValidExceptionHandler(HttpServletRequest httpServletRequest, MethodArgumentNotValidException e) {
//打印第一条错误信息
String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
System.out.println("参数校验异常:" + message);
return message;
}
}
这里使用的是@RestControllerAdvice注解,因为我们控制器controller加入的注解是@RestController,所以这里是一一对应的。
下面的methodArgumentNotValidExceptionHandler方法可以看到,我们这边拦截的是MethodArgumentNotValidException异常,因为校验注解这边报的异常是这个,所以我们需要处理的是这个异常。
这里需要注意的是每个Exception异常获取的message方式可能会有所不同,所以具体要看错误信息要怎么获取。
我们再用postman模拟请求一次看看这时候返回的错误信息是什么。
这时候我们看到返回的是我们指定的错误信息内容了,是不是很方便,而且前端页面也能够提示我们提示的错误信息内容了。
要使用这种统一异常处理,有个注意的地方就是,异常必须要抛出controller这层,才会被MyExceptionHandler这个类捕获。
意思就是说,如果我们是以下这种写法,就不会被捕获。
@GetMapping("/hello_world")
public String helloWorld() {
try {
System.out.println(1/0);
}catch (Exception e) {
System.out.println("异常:" + e.getMessage());
}
return "Hello World!";
}
在方法体内try/catch了异常,没有往controller层再抛出异常的话,统一异常处理是不起操作的。
IDE控制台输出。
如果将try/catch去掉。
@GetMapping("/hello_world")
public String helloWorld() {
System.out.println(1/0);
return "Hello World!";
}
再请求一次。
IDE控制台输出。
这里统一异常处理类我们加上了最大的异常Exception捕获。
package org.liurb.springboot.demo.exception;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
@RestControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public String methodArgumentNotValidExceptionHandler(HttpServletRequest httpServletRequest, MethodArgumentNotValidException e) {
//打印第一条错误信息
String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
System.out.println("参数校验异常:" + message);
return message;
}
@ExceptionHandler(Exception.class)
public String globalException(HttpServletRequest request, Exception e) {
String message = e.getMessage();
System.out.println("exception异常:" + message);
return message;
}
}
意思是,如果前面的异常类没有定义的(或者没有捕获到的),都会走到Exception这边的处理来。
另附上一些常用的校验注解和作用说明
常用校验注解
@NotNull 被注释的元素必须不为 null
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min) 被注释的元素的大小必须在指定的范围内
@NotBlank 不为null并且包含至少一个非空白字符
@NotEmpty 不为null并且不为空
@Digits 可设定最大整数位数和最大小数位数
@Email 校验是否符合Email格式
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/93620.html