目录
1. 添加依赖
2. 检查POJO类型的请求参数
3. 关于响应的消息文本
4. 快速失败
5. 检查未封装的请求参数
1. 添加依赖
在pom.xml
中添加spring-boot-starter-validation
依赖项:
<!-- Spring Boot Validation框架,用于检查数据格式 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2. 检查POJO类型的请求参数
首先,在POJO参数前添加@Valid
或@Validated
注解,用于表示此参数是需要通过Validation框架进行检查的!
例如:
@ApiOperation("添加相册")
@PostMapping("/add-new")
// ↓ 新添加的注解
public JsonResult addNew(@Valid AlbumAddNewDTO albumAddNewDTO) {
albumService.addNew(albumAddNewDTO);
return JsonResult.ok();
}
然后,在此参数的属性上添加检查注解,例如添加@NotNull
注解,表示将对此属性进行检查,此属性的值不允许为null
:
@Data
public class AlbumAddNewDTO implements Serializable {
@ApiModelProperty(value = "相册名称", required = true)
@NotNull // 新添加的注解
private String name;
// 省略后续代码
完成后,重启服务,通过API文档提交请求时,故意不提交name
(将对应的输入框删除),则服务器端尝试接收的name
就会是null
,无法通过@NotNull
的检查规则,默认将出现400
错误,例如:
{
"timestamp": "2022-12-01T06:38:26.020+00:00",
"status": 400,
"error": "Bad Request",
"path": "/album/add-new"
}
并且,在服务器端的控制台会提示以下错误:
2022-12-01 14:38:26.017 WARN 10708 --- [io-9080-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors<EOL>Field error in object 'albumAddNewDTO' on field 'name': rejected value [null]; codes [NotNull.albumAddNewDTO.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [albumAddNewDTO.name,name]; arguments []; default message [name]]; default message [不能为null]]
可以看到,当检查不通过时,将出现org.springframework.validation.BindException
异常!
在ServiceCode
中添加新的枚举值:
* 错误:请求参数格式有误
*/
ERR_BAD_REQUEST(400),
在GlobalExceptionHandler
中添加处理BindException
异常的代码:
@ExceptionHandler
public JsonResult handleBindException(BindException e) {
String message = "请求参数格式错误!";
return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, message);
}
3. 关于响应的消息文本
所有检查注解都可以配置检查不通过后的提示文本,例如:
@NotNull(message = "必须提交相册名称")
在处理异常时,应该将此处配置的文本响应到客户端去,可以通过异常对象获取以上文本!
由于客户端提交的若干个请求参数可能有多种错误,则异常对象中可能封装了多个错误信息!如果需要显示所有错误,应该先获取全部信息,然后将这些错误信息组织起来,并响应到客户端去!
所以,处理异常的代码可以调整为:
@ExceptionHandler
public JsonResult handleBindException(BindException e) {
String delimiter = ",";
String prefix = "添加相册失败,";
String suffix = "!";
StringJoiner stringJoiner = new StringJoiner(delimiter, prefix, suffix);
List<FieldError> fieldErrors = e.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
String defaultMessage = fieldError.getDefaultMessage();
stringJoiner.add(defaultMessage);
}
return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, stringJoiner.toString());
}
4. 快速失败
Validation框架有快速失败的机制,默认是未开启的,当客户端提交的请求参数有多种错误时,会进行全部的检查,发现所有错误!如果开启了快速失败,当检查出第1个错误时,就会停止检查!
配置快速失败,需要创建Valiator
类型的对象,通过此对象进行配置,并且,此对象必须被保存在Spring容器中,框架会自动应用它!
当需要创建某个对象并使它保存在Spring容器中,可以在配置类中添加@Bean
方法,此方法返回相关对象,在启动项目时,Spring框架会自动调用此方法并将返回保存在Spring容器中。
在项目的根包下创建config.ValidationConfiguration
配置类,在此配置类中通过@Bean
方法返回Validator
对象,并在返回之前将此对象配置为快速失败的:
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.validation.Validation;
@Slf4j
@Configuration
public class ValidationConfiguration {
public ValidationConfiguration() {
log.debug("创建配置类对象:ValidationConfiguration");
}
@Bean
public javax.validation.Validator validator() {
return Validation.byProvider(HibernateValidator.class)
.configure() // 开始配置
.failFast(true) // 配置快速失败
.buildValidatorFactory() // 构建Validator工厂
.getValidator(); // 从Validator工厂中获取Validator对象
}
}
当配置了快速失败后,无论请求参数有多少种错误,都会在发现第1个错误后停止检查,所以,处理异常时,只需要直接获取错误对象即可,不必获取所有错误对象!即:
@ExceptionHandler
public JsonResult handleBindException(BindException e) {
StringBuilder stringBuilder = new StringBuilder();
String prefix = "添加相册失败,";
String suffix = "!";
String defaultMessage = e.getFieldError().getDefaultMessage();
stringBuilder.append(prefix).append(defaultMessage).append(suffix);
return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, stringBuilder.toString());
}
5. 检查未封装的请求参数
如果某些请求的参数较少,或各参数并不相关,则不会将它们封装在一起,例如:
// http://localhost:9080/brand/delete
@PostMapping("/delete")
public void delete(Long id) {
}
当需要检查这类参数时,首先,需要在当前类上添加@Validated
注解,例如:
@RestController
@RequestMapping("/brand")
@Validated // 新添加的注解
public class BrandController {
// 省略其它代码
然后,在请求参数上添加检查注解,例如:
// http://localhost:9080/brand/delete
@PostMapping("/delete")
// ↓ 新添加的注解
public void delete(@Range(min = 1, max = 996) @RequestParam Long id) {
}
**提示:**以上@RequestParam
在此处并无实际意义,但是,不添加此注解的话,在线API文档的调试界面中不会出现此参数的输入框,所以暂时添加上此注解,后续将删除!
完成后,重启项目,在API文档中调整,如果提交的id
参数值不在[1, 996]
范围内,将出现500
错误(注意:不要处理RuntimeException
),则控制台会提示错误:
javax.validation.ConstraintViolationException: delete.id: 需要在1和996之间
则应该在全局异常处理器添加对以上异常的处理:
@ExceptionHandler
public JsonResult handleConstraintViolationException(ConstraintViolationException e) {
Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
String delimiter = ",";
StringJoiner stringJoiner = new StringJoiner(delimiter);
for (ConstraintViolation<?> constraintViolation : constraintViolations) {
stringJoiner.add(constraintViolation.getMessage());
}
return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST, stringJoiner.toString());
}
个人主页:居然天上楼
感谢你这么可爱帅气还这么热爱学习~~
人生海海,山山而川
你的点赞👍 收藏⭐ 留言📝 加关注✅
是对我最大的支持与鞭策