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);
}
}