@Validated & @Valid 注解的区别

1.两者的采用的不同规范及相应注解包的引入:

@Validated是Spring Validation验证框架对参数的验证机制所使用的注解,使用的是Spring的 JSR-303规范,它是标准JSR-303规范的一种变种)。

需要引入的注解包为: import org.springframework.validation.annotation.Validated;

@Valid是由javax提供的,使用的是标准的JSR-303规范。

需要引入的注解包为:import javax.validation.Valid;

此外,@Valid配合BindingResult可以直接将参数校验的结果按照自定义格式输出到我们想要的位置。

2.代码实例一,当请求是Post请求时:@RequestBody参数校验

2.1 需要进行参数验证的RequetBody:

package com.test.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
import java.util.Map;

@Data
@Accessors(chain = true)
public final class TestDTO {

    @NotBlank(message = "Missing Mandatory Field")
    String id;

    @NotBlank(message = "Missing Mandatory Field")
    String name;

    @NotBlank(message = "Missing Mandatory Field")
    String sex;
}

2.2 使用TestDTO作为入参的Controller

package com.test.controller;

import com.test.model.*;
import com.test.TestService;
import com.accenture.atchk.blockchain.util.CommonUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@RestController
@RequestMapping(value = "/test/v1.0")
public class TestController {

    private static final ObjectMapper jackson = new ObjectMapper();

    private static Logger logger = LoggerFactory.getLogger(TestController.class);

    TestService testService;

    @Autowired
    public TestController(TestService testService) {
        this.testService = testService;
    }

    @PostMapping(value = "/valid")
    public ResponseEntity<List<OutcomeDTO>> submit(@Valid @RequestBody TestDTO testDTO, BindingResult bindingResult) {

        CommonUtils.parameterChecking(bindingResult);

        String today = OffsetDateTime.now().format(DateTimeFormatter.ofPattern("uuuu-MM-dd"));

        List<OutcomeDTO> outcomeDTOList = testService.submit(today, testDTO.getId(), testDTO);
        logger.info("Record outcome list for TransactionId {}: {}", testDTO.getId(), outcomeDTOList);

        Map<String, MemberAccountTxnDTO> result = testService.recordOutcome(today, transactionDTO.getId() + ":" + UUID.randomUUID().toString(), outcomeDTOList);
        if (result != null) {
            result.forEach((key, value) -> {
                try {
                    logger.info("Record outcome result key {}: {}", key, jackson.writeValueAsString(value));
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
            });
        } else {
            logger.info("Result is null");
        }
        return new ResponseEntity<>(outcomeDTOList, HttpStatus.OK);
    }
}

注意:

1.RequestBody 要同上述一样与BindnigResult相邻,否则出现以下情况:

实例代码:

    @PatchMapping(value = "/{test1}/tests/{test2}")
    public ResponseEntity<BaseSuccessResponse> test(@Valid @RequestBody RequestBody request,@PathVariable(name = "test1") String test1,BindingResult bindingResult,@PathVariable(name = "test2") String test2) throws Exception {
        CommonUtils.parameterChecking(bindingResult);
        
        BaseSuccessResponse baseSuccessResponse = testService.testValid(request, test1, test2);
        return new ResponseEntity<>(baseSuccessResponse, HttpStatus.OK);
    }

实例代码解析:由于RequestBody request 同 BindingResult之间间隔了一个参数,这时候如果RequestBody中某个字段时为Null时就不会出现自定义的参数异常信息!

如:不会出现的错误信息为Missing Mandatory Field,而是会出现System Exception!

2.如果Post的请求参数中出现多个RequestBody时,就要使用多个@Valid和BindingResult,如:

public void test()( @RequestBody @Valid RequestBody bodyOne, BindingResult result,
                    @RequestBody @Valid RequestBody bodyTwo, BindingResult result2){
      CommonUtils.parameterChecking(result);
      CommonUtils.parameterChecking(result2);
}

2.3 参数校验工具类CommomUtils.java

package com.test.util;

import com.test.CustomException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import com.test.enums.Error;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**当想要使得CommonUtils作为Bean使用@Autowired注入时需要使用@Component来生成Bean实例
  *@Autowired 
  *private CommonUtils commonUtils;
  *@Component 
  *public class CommonUtils{}
  **/

public class CommonUtils {

    public static void parameterChecking(BindingResult bindingResult) throws CustomException {
        if (bindingResult.hasErrors()) {
            List<FieldError> listError = bindingResult.getFieldErrors();
            Set<String> parameters = new HashSet<>();
            Iterator keys = listError.iterator();
            FieldError iterator = null;
            while (keys.hasNext()) {
                iterator = (FieldError) keys.next();
                String field = iterator.getField();
                parameters.add(field);
            }
            if (iterator != null) {
                throw new CustomException(Error.getErrorByMessage(iterator.getDefaultMessage()), parameters);
            }
        }
    }
}

4.实例代码二,当请求为Get请求时:@RequestParam参数校验

使用校验bean的方式,即@Valid注解,没有办法校验RequestParam的内容,一般在处理Get请求(或参数比较少)的时候,会使用如下方式进行校验:

package com.test.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(value = "/test/v1.0")
public class TestController {

    private static final ObjectMapper jackson = new ObjectMapper();

    private static Logger logger = LoggerFactory.getLogger(TestController.class);

    @RequestMapping(value = "/test", method = RequestMethod.GET)
    或者
    @GetMapping(value = "/test")
    public void test(@RequestParam(name = "name", required = true) String name,@RequestParam(name = "sex", required = true) String sex) {
        System.out.println(name + "," + sex);
    }
}

此时,需要对参数进行校验时,需要在所在的Controller上使用@Validated注解来使得的验证生效。

package com.test.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(value = "/test/v1.0")
@Validated
public class TestController {

    private static final ObjectMapper jackson = new ObjectMapper();

    private static Logger logger = LoggerFactory.getLogger(TestController.class);

    TestService testService;

    @Autowired
    public TestController(TestService testService) {
        this.testService = testService;
    }
    @RequestMapping(value = "/test", method = RequestMethod.GET)
    或者
    @GetMapping(value = "/test")
    public void test( @Range(min = 0, max = 99, message = "年龄只能从0-99")
                      @RequestParam(name = "age", required = true)
                      int age,
                      @Min(value = 160, message = "身高最小只能160")
                      @Max(value = 200, message = "身高最大只能200")
                      @RequestParam(name = "height", required = true)
                      int height) {
        System.out.println(age + "," + height);
    }
}
发布了22 篇原创文章 · 获赞 5 · 访问量 2200

猜你喜欢

转载自blog.csdn.net/calm_encode/article/details/103815219