美文网首页
参数校验功能

参数校验功能

作者: 寂静的春天1988 | 来源:发表于2020-08-25 08:58 被阅读0次

集成验证框架步骤

1、在pom.xml引入相关jar包
2、在待验证的实体里添加相应的注解
3、在controller中添加相应的注解
4、做参数校验工具类,完成service层的参数校验

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

有的版本在spring-boot-starter-web中集成了验证框架,就不用单独引入验证框架了。

新增请求中用户名不能为空,而修改请求用户名可以为空。针对同一个字段在不同请求中有不同的校验规则。需要定义多个接口

public interface InsertVaildationGroup {

}
public interface UpdateVaildationGroup {

}
@Data
public class UserDTO implements Serializable{
    
    
    /**
     * 
     */
    private static final long serialVersionUID = 5144803032215944382L;
    
    @NotBlank(message = "用户名不能为空",groups = {InsertVaildationGroup.class})
    private String username;
    
    @Length(min = 6,max = 18,message = "密码长度需在6-18位之间")
    private String password;
    
    @NotEmpty(message = "邮箱不能为空!",groups = {InsertVaildationGroup.class})
    @Email(message = "邮箱格式错误")
    private String email;

    @NotNull(message = "年龄不能为空",groups = {InsertVaildationGroup.class})
    @Max(value = 60,message = "年龄不能大于60")
    @Min(value = 18,message = "年龄不能小于18岁")
    private Integer age;

    @NotNull(message = "版本号不能为空",groups = {UpdateVaildationGroup.class})
    private String phone;

    /**
     * 版本号
     */
    private Long version;

}

通过groups属性来区分,在不同请求下的是否需要校验。如果没用groups ,那么如果值为空就不会校验,值不为空就会校验

@Validated
public class UserController {
    
    @Autowired
    private UserService userService;
    
    
    @PostMapping()
    public ResponseResult save(@Validated(value = {InsertVaildationGroup.class}) @RequestBody UserDTO userDTO) {
        if(userService.save(userDTO)>0) {
            return ResponseResult.success("新增成功");
        }
        return ResponseResult.fail(ErrorCodeEnum.INSERT_FIILURE);
    }
    
    @PutMapping("/{id}")
    public ResponseResult update(@NotNull(message = "用户id不能为空") @PathVariable("id")Long id, @RequestBody UserDTO userDTO) {
        if(userService.update(id, userDTO)>0) {
            return ResponseResult.success("更新成功");
        }
        return ResponseResult.fail(ErrorCodeEnum.UPDATE_FIILURE);
        
    }

如果是对象类型的参数用@Validated,如果是简单类型的参数直接在参数前面写校验注解,但是需要在controller上加@Validated注解。

测试结果.png

使用postman测试,发现已经被拦截下来了,返回400。这是controller的校验。接下来写service层的校验

@Data
public class PageQuery<T> implements Serializable{

    private static final long serialVersionUID = 2220927012679224629L;

    @NotNull(message = "页码不能为空")
    @Min(message = "不能小于1", value = 1)
    private Integer pageNo=1;
    
    @NotNull(message = "每页条数不能为空")
    @Max(message = "不能大于100", value = 100)
    private Integer pageSize=20;

    private T query;
    
}
public class VaildatorUtils {
    
    private static Validator validator=Validation.buildDefaultValidatorFactory().getValidator();
    
    public static<T> void validate(T object,Class... groups) {
        Set<ConstraintViolation<T>> validate=validator.validate(object, groups);
        if(!CollectionUtils.isEmpty(validate)) {
            StringBuilder exceptionMessage=new StringBuilder();
            validate.forEach(constraintViolation -> {
                exceptionMessage.append(constraintViolation.getMessage());
            });
            throw new RuntimeException(exceptionMessage.toString());
        }
    }
}
@Override
    public PageResult<List<UserDTO>> query(PageQuery<UserQueryDTO> pageQuery) {
        // 手动校验功能
        VaildatorUtils.validate(pageQuery);
        
        Page page=new Page(pageQuery.getPageNo(),pageQuery.getPageSize());
        UserDO query=new UserDO();
        BeanUtils.copyProperties(pageQuery.getQuery(), query);
        QueryWrapper queryWrapper=new QueryWrapper(query);
        IPage<UserDO> userDOIPage =userMapper.selectPage(page,queryWrapper);
        
        // 结果解析
        PageResult pageResult=new PageResult();
        pageResult.setPageNo((int) userDOIPage.getCurrent());
        pageResult.setPageSize((int) userDOIPage.getSize());
        pageResult.setTotal(userDOIPage.getTotal());
        pageResult.setPageNum(userDOIPage.getPages());
        
        List<UserDTO> useDTOList=Optional.ofNullable(userDOIPage.getRecords())
                .map(List::stream)
                .orElseGet(Stream::empty)
                .map(userDO -> {
                    UserDTO userDTO = new UserDTO();
                    BeanUtils.copyProperties(userDO, userDTO);
                    return userDTO;
                }).collect(Collectors.toList());
        pageResult.setData(useDTOList);
        return pageResult;
    }

统一异常处理

之前可以看到,参数校验是直接抛出异常到前端了。非常不友好,可以使用异常处理来改造。

/**
 * 全局异常处理
 * @author user
 *
 */

@ResponseBody
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    
    /**
     * 捕获参数校验错误
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public final ResponseResult methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException ex, WebRequest request) {
        List<ObjectError> allErrors =  ex.getBindingResult().getAllErrors();
        Object[] messages = allErrors.stream().map(ObjectError::getDefaultMessage).toArray();
        return ResponseResult.fail(ErrorCodeEnum.PARAM_ERROR.getCode(), Arrays.toString(messages));
    }
    @ExceptionHandler(BindException.class)
    public final ResponseResult bindExceptionHandler(BindException ex, WebRequest request) {
        List<ObjectError> allErrors = ex.getAllErrors();
        Object[] messages = allErrors.stream().map(ObjectError::getDefaultMessage).toArray();
        return ResponseResult.fail(ErrorCodeEnum.PARAM_ERROR.getCode(), Arrays.toString(messages));
    }
    
    
    @ExceptionHandler(value = RuntimeException.class)
    public ResponseResult runtimeExceptionHandler(RuntimeException e) {
        log.error("运行时异常",e);
        return ResponseResult.fail(ErrorCodeEnum.UNKNOWN_ERROR.getCode(), e.getMessage());
    }
    
    @ResponseBody
    @ExceptionHandler(value = Throwable.class)
    public ResponseResult throwableHandler(Throwable e) {
        log.error("系统级异常",e);
        return ResponseResult.fail(ErrorCodeEnum.SYSTEM_ERROR.getCode(), e.getMessage());
    }
}

image.png image.png
image.png

级联验证

image.png

@Size :验证list是否符合要求
@Valid:验证list中的userinfo是否符合要求

自定义校验注解

/**
 * 自定义手机号约束注解
 * @author user
 *
 */

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
// 约束注解关联的验证器
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
    
    String message() default "手机号验证错误";
    
    Class<?>[] groups() default {};
    
    Class<? extends Payload>[] payload() default {};
}
public class PhoneValidator implements ConstraintValidator<Phone, String>{


    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        // 实现自定义逻辑
        if(value!=null && value.trim().length()==11) {
            return true;
        }
        return false;
    }


}

相关文章

网友评论

      本文标题:参数校验功能

      本文链接:https://www.haomeiwen.com/subject/bvyhfktx.html