yangweijie / note

个人博客
https://yangweijie.github.io/note/
10 stars 1 forks source link

springboot整合validation统一参数检查 #92

Open yangweijie opened 3 years ago

yangweijie commented 3 years ago

1.背景

 实际开发中对参数进行检查,是常见  比如如下代码 

/**
     * 参数检查测试(传统做法)
     *
     * @param dto
     * @return
     */
    @GetMapping("/paramCheckOld")
    public BaseResponse paramCheckOld(@RequestBody UserDTO dto) {
        // 参数检查
        if (StrUtil.isEmpty(dto.getWeChat())) {
            return ResponseBuilder.failed("微信号为空");
        }
        if (StrUtil.isEmpty(dto.getName())) {
            return ResponseBuilder.failed("姓名为空");
        }

        if (dto.getStatus() != null
                || dto.getStatus() != -1
                || dto.getStatus() != 0
                || dto.getStatus() != 1) {
            return ResponseBuilder.failed("状态为-1,0,1或者null");
        }
        // .....如果参数很多这里必然后崩溃..........
        // 调用业务方法
        // 响应结果
        System.out.println("dto=" + dto);
        return ResponseBuilder.success("统一参数检查.....");
    }



 但是正确的做法应该是,这里其实只使用了一个@Validated注解就搞定了,太方便了..... 



 /**
     * 统一参数检查(牛逼的做法)
     *
     * @param dto
     * @return
     */
    @GetMapping("/paramCheck")
    public BaseResponse paramCheck(@RequestBody @Validated UserDTO dto) {
        // 参数检查(已检查)
        // 调用业务方法
        // 响应结果
        System.out.println("dto=" + dto);
        return ResponseBuilder.success("统一参数检查.....");
    }





2.步骤

 步骤一:引入jar包 

 <!--  统一参数校验-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

 步骤二:参数上贴标签 



package com.ldp.user.entity.dto;

import com.ldp.user.common.validation.EnumValue;
import lombok.Data;

import javax.validation.constraints.NotBlank;

/**
 * @author 姿势帝-博客园
 * @address https://www.cnblogs.com/newAndHui/
 * @WeChat 851298348
 * @create 01/01 4:00
 * @description
 */
@Data
public class UserDTO {
    @NotBlank(message = "微信号不能为空")
    private String weChat;

    @NotBlank(message = "姓名不能为空")
    private String name;
    /**
     * 年龄
     */
    private Integer age;
    /**
     * 状态
     * -1:冻结用户 ,0:正常用户, 1:没有实名认证
     */
    @EnumValue(intValues = {-1, 0, 1}, message = "状态为-1,0,1或者null")
    private Integer status;
    /**
     * 地址
     */
    private String address;
}



 步骤三:控制层方法上贴标签(当然在其他方法上也可以用的,只是一般我们用在控制层上)  

/**
     * 统一参数检查(牛逼的做法)
     *
     * @param dto
     * @return
     */
    @GetMapping("/paramCheck")
    public BaseResponse paramCheck(@RequestBody @Validated UserDTO dto) {
        // 参数检查(已检查)
        // 调用业务方法
        // 响应结果
        System.out.println("dto=" + dto);
        return ResponseBuilder.success("统一参数检查.....");
    }

  步骤四:统一参数检查不通过时提示消息获取  

  /**
     * 参数异常捕获
     *
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = ConstraintViolationException.class)
    public Object constraintViolationExceptionHandler(ConstraintViolationException ex) {
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();
        List<String> msgList = new ArrayList<>();
        while (iterator.hasNext()) {
            ConstraintViolation<?> cvl = iterator.next();
            msgList.add(cvl.getMessageTemplate());
        }
        return ResponseBuilder.failed(msgList.toString());
    }

    @ExceptionHandler(BindException.class)
    @ResponseBody
    public Object getBindException(BindException ex) {
        List<ObjectError> objectErrors = ex.getBindingResult().getAllErrors();
        if (!CollectionUtils.isEmpty(objectErrors)) {
            StringBuilder msgBuilder = new StringBuilder();
            for (ObjectError objectError : objectErrors) {
                msgBuilder.append(objectError.getDefaultMessage()).append(",");
            }
            String errorMessage = msgBuilder.toString();
            if (errorMessage.length() > 1) {
                errorMessage = errorMessage.substring(0, errorMessage.length() - 1);
            }
            return ResponseBuilder.failed(errorMessage);
        }
        return ResponseBuilder.failed(ex.getMessage());
    }

  步骤五测试  

  @Test
    void paramCheck() {
        String url = urlLocal + "/userOrder/paramCheck";
        System.out.println("请求地址:" + url);
        HttpRequest request = HttpUtil.createRequest(Method.GET, url);
        Map<String, Object> map = new TreeMap<>();
        // 业务参数
      //  map.put("weChat", "851298348");
       // map.put("name", "李东平");
        map.put("age", "18");
        map.put("status", "0");
        map.put("address", "四川成都");

        // 公用参数
        map.put("appid", "1001");
        map.put("sequenceId", "seq" + System.currentTimeMillis());
        map.put("timeStamp", System.currentTimeMillis());
        map.put("sign", signApi(map, "123456"));
        String param = JSON.toJSONString(map);
        request.body(param);
        System.out.println("请求参数:" + param);
        request.header("Authorization", token);
        request.setConnectionTimeout(60 * 1000);
        String response = request.execute().body();
        System.out.println("请求结果:" + response);
    }

  测试结果: 

{"message":"微信号不能为空,姓名不能为空","code":900}



3.常用检查规则注解

  

JSR提供的校验注解:         
@Null   被注释的元素必须为 null    
@NotNull    被注释的元素必须不为 null    
@AssertTrue     被注释的元素必须为 true    
@AssertFalse    被注释的元素必须为 false    
@Min(value)     被注释的元素必须是一个数字,其值必须大于等于指定的最小值    
@Max(value)     被注释的元素必须是一个数字,其值必须小于等于指定的最大值    
@DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值    
@DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值    
@Size(max=, min=)   被注释的元素的大小必须在指定的范围内    
@Digits (integer, fraction)     被注释的元素必须是一个数字,其值必须在可接受的范围内    
@Past   被注释的元素必须是一个过去的日期    
@Future     被注释的元素必须是一个将来的日期    
@Pattern(regex=,flag=)  被注释的元素必须符合指定的正则表达式    


Hibernate Validator提供的校验注解:  
@NotBlank(message =)   验证字符串非null,且trim后长度必须大于0    
@Email  被注释的元素必须是电子邮箱地址    
@Length(min=,max=)  被注释的字符串的大小必须在指定的范围内    
@NotEmpty   被注释的字符串的必须非空    
@Range(min=,max=,message=)  被注释的元素必须在合适的范围内

 

4.自定义检查规则注解

 如果这些注解还不能满足我们的需求,那么我么可以自己定义满足自己业务规则的注解  这里以自定义一个枚举值检查的注解,这个在实际生产中用的非常普遍  比如在传入用户状态时,只嗯传入-1,0,1或者null,其都是参数不合法的检查注解  https://www.cnblogs.com/newAndHui/p/14185807.html 

完美!