我们在开发SpringBoot项目时,有时候需要对外提供接口,对外暴露的接口在接收到请求参数时,我们无法保障参数是否满足我们的需求,比如是否为空、是否长度太长等等,如果我们自己手工一个个属性去校验,那将是非常的麻烦,因此,我们可以使用一些校验框架帮助我们实现改过程,如果存在不符合规则的属性,我们可以示使用全局异常来进行统一处理。下面,潘老师给大家实现一个案例代码,可供大家参考学习。
1、导入依赖
我们在这里使用hibernate-validator
框架进行校验,首先我们需要导入相关依赖:
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.1.7.Final</version> </dependency>
2、请求参数
我们先定义一个请求参数类,这里使用了lombok简化了代码,如下:
@Data @EqualsAndHashCode(callSuper = false) @NoArgsConstructor @AllArgsConstructor public class User { // 用户名 @NotBlank(message = "参数不能为空") @Length(max = 10,message = "参数长度不能超过10") private String username; // 密码 @NotBlank(message = "参数不能为空") @Length(max = 50,message = "参数长度不能超过50") private String password; // 邮箱 @Email(message = "必须为邮箱格式") private String email; }
3、接口校验参数
接下来我们队接收到的User 参数进行校验,只需要在方法参数前加上@Validated
注解,具体代码如下:
@RestController @RequestMapping("/api/user") public class ScheduleApi { @Autowired private UserService userService; /** * 接收用户信息保存 */ @PostMapping("/save") public ResponseResult saveUser(@Validated @RequestBody User user){ // 响应对象-可自行定义 ResponseResult responseResult; // 执行保存操作 boolean flag = userService.save(user); if(flag){ // 保存成功 responseResult = ResponseResult.success(); }else { // 保存失败 responseResult = ResponseResult.fail(); } return responseResult; } }
注意:这里面@Validated注解会对user参数根据实体类中的注解信息进行属性校验,如果有任何一个不满足条件就会抛出MethodArgumentNotValidException异常,这个异常我们需要统一处理
4、全局参数异常处理
我们自定义一个全局异常处理类,我这里定义为GlobalExceptionHandler
,具体代码如下:
@ControllerAdvice @ResponseBody public class GlobalExceptionHandler { /** * 全局方法参数校验异常处理,只要方法抛出MethodArgumentNotValidException异常,就会被此方法拦截处理 */ @ExceptionHandler({MethodArgumentNotValidException.class}) public ResponseResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { StringBuilder sb = new StringBuilder("请求参数异常:"); // 遍历拼接所有参数异常信息 List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors(); fieldErrors.forEach(error->{ sb.append(error.getField()+":"+error.getDefaultMessage()+";"); }); return ResponseResult.fail().setCode(ResponseConstants.PARAM_ERROR_CODE) .setMsg(ResponseConstants.PARAM_ERROR_MSG); } }
注意:这里使用了@ControllerAdvice注解来实现,我们也可以可使用它的basePackages属性指定某个或某些包下的异常进行统一处理,如@ControllerAdvice(basePackages={“com.panziye.controller,com.panziye.thread”})
以上我们就实现了对请求参数的统一校验与统一处理。
5、补充:参数分组校验
有一种特殊的情况就是,如果你的实体类每个属性都写死了校验注解,那么在任何时候只要你在参数前加上@Validated
注解都会使用该规则进行校验,但是有时候我们在不同的方法中,可能会对不同的参数有不同的校验情况,比如在保存时要求这3个属性必须非空,且email满足格式要求,在更新时只需要username不为空,其他属性不校验,那么我们就要对这两种情形进行分组:
1)首先我们需要建一个分组类Groups,类中建多个接口,一个组对应一个接口(我这里就写两个):
public class Groups { // 保存校验组 public interface Insert{} // 更新校验组 public interface Update{} }
2)接着我们对参数类属性注解进行分组校验:
@Data @EqualsAndHashCode(callSuper = false) @NoArgsConstructor @AllArgsConstructor public class User { // 用户名 @NotBlank(message = "参数不能为空",groups = {Groups.Insert.class,Groups.Update.class}) @Length(max = 10,message = "参数长度不能超过10") private String username; // 密码 @NotBlank(message = "参数不能为空",groups = Groups.Insert.class) @Length(max = 50,message = "参数长度不能超过50") private String password; // 邮箱 @Email(message = "必须为邮箱格式",groups = Groups.Insert.class) private String email; }
3)现在在保存和更新方法中,对参数校验的注解就要有所修改,如下:
// 保存 public ResponseResult saveUser(@Validated(value = Groups.Insert.class) @RequestBody User user){ //省略逻辑... } // 更新 public ResponseResult updateUser(@Validated(value = Groups.Update.class) @RequestBody User user){ //省略逻辑... }
提示:这里@Validated中value也可以指定为数组,综合多个分组,比如:@Validated(value = {Groups.Insert.class, Groups.Update.class})
以上,就实现了分组校验啦~