Why:
Why use AOP to achieve verification?
answer:
spring mvc has its own verification mechanism @Valid + BindingResult, but this default implementation must receive BindingResult in the Controller method to perform verification.
eg:
if (result.hasErrors()) { List<ObjectError> allErrors = result.getAllErrors(); List<String> errorlists = new ArrayList<>(); for (ObjectError objectError: allErrors) { errorlists.add(objectError.getDefaultMessage()); } }Get errorlists. If this is implemented, each method that requires verification must be called repeatedly, even if encapsulated.
Maybe the above statement cannot indicate the implementation of spring's @Valid + BindingResult. Let me give you a "chestnut".
1. Chestnut (old version)
1.1 Interface Layer (IDAL)
eg: Simple POST request, @RequestBody receives request data, @Valid + BindingResult performs verification
@ResponseBody @PostMapping("body") public ResponseVO bodyPost(@RequestBody @Valid TestVO body,BindingResult result){ //Check error if (result.hasErrors()) { List<ObjectError> allErrors = result.getAllErrors(); List<String> lists = new ArrayList<>(); for (ObjectError objectError: allErrors) { lists.add(objectError.getDefaultMessage()); } return new ResponseVO(HttpStatus.BAD_REQUEST.value(), "parameter empty", lists); } return new ResponseVO(HttpStatus.OK.value(), "bodyPost", null);}1.2 Entity (vo) verification content
@Valid + BindingResult has a lot of verification annotations, and you can find it as soon as you touch it online!
public class TestVO { @Getter @Setter @Min(value = 0,message = "Request parameter isString cannot be less than 0") private Integer isInt; @Getter @Setter @NotBlank(message = "Request parameter isString cannot be empty") private String isString;}1.3 Results Test
2. aop verification (upgraded version)
It can be seen that if multiple bodies need to be checked like bodyPost, then a piece of code must be reproduced continuously. Even if it is changed to a parent class reusable method, it must be called. So I still feel that it is not elegant after thinking about it. So there is aop for section verification.
2.1 Interface Layer (IDAL)
Yes! You read that right, the above code is gone, and there is no need to call the shared method of the parent class. Just one annotation is done: @ParamValid
@ParamValid@ResponseBody@PostMapping("body")public ResponseVO bodyPost(@RequestBody @Valid TestVO body,BindingResult result){ return new ResponseVO("bodyPost", null);}2.2 Custom annotation
This annotation is also a simple method annotation.
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface ParamValid {}2.3 Key points! Aspect implementation
Detailed explanation of the section:
@Before: Use the annotation method @annotation(XX), this method will be called whenever you use the desired annotation (@ParamValid).
JoinPoint: Get the parameters of the method through JoinPoint to obtain the contents verified by BindingResult
Migrate verification package: Migrate the original verification into Aspect: validRequestParams
Response verification results:
@Aspect@Componentpublic class ParamValidAspect { private static final Logger log = LoggerFactory.getLogger(ParamValidAspect.class); @Before("@annotation(paramValid)") public void paramValid(JoinPoint point, ParamValid paramValid) { Object[] paramObj = point.getArgs(); if (paramObj.length > 0) { if (paramObj[1] instanceof BindingResult) { BindingResult result = (BindingResult) paramObj[1]; ResponseVO errorMap = this.validRequestParams(result); if (errorMap != null) { ServletRequestAttributes res = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletResponse response = res.getResponse(); response.setCharacterEncoding("UTF-8"); response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); response.setStatus(HttpStatus.BAD_REQUEST.value()); OutputStream output = null; try { output = response.getOutputStream(); errorMap.setCode(null); String error = new Gson().toJson(errorMap); log.info("aop parameter irregular detected" + error); output.write(error.getBytes("UTF-8")); } catch (IOException e) { log.error(e.getMessage()); } finally { try { if (output != null) { output.close(); } } catch (IOException e) { log.error(e.getMessage()); } } } } } } } } /** * Verification*/ private ResponseVO validRequestParams(BindingResult result) { if (result.hasErrors()) { List<ObjectError> allErrors = result.getAllErrors(); List<String> lists = new ArrayList<>(); for (ObjectError objectError: allErrors) { lists.add(objectError.getDefaultMessage()); } return new ResponseVO(HttpStatus.BAD_REQUEST.value(), "parameter empty", lists); } return null; }}2.4 Test results
After reading the above two results, you can compare the advantages of using Spring AOP with @Valid + BindingResult for verification:
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.