Springboot模块系列:数据校验

it2026-03-12  2

1 入参实体

package com.company.web.dto; import javax.validation.constraints.*; import java.io.Serializable; /** * Question and answer. * @author xindaqi * @since 2020-10-20 */ public class QuestionAnswerInputDTO implements Serializable{ @NotNull @NotBlank(message = "参数为空") private String questions; @NotNull @NotBlank(message = "参数为空answer") private String answers; public void setQuestions(String questions) { this.questions = questions; } public String getQuestions() { return questions; } public void setAnswers(String answers) { this.answers = answers; } public String getAnswers() { return answers; } }

2 统一返回数据

package com.company.web.vo.common; import com.company.web.enums.common.*; /** * Uniform response. * @author xindaqi * @since 2020-10-20 * @param <T> */ public class ResponseVO<T> { private Integer code; private String msg; private T data; public void setCode(Integer code) { this.code = code; } public Integer getCode() { return code; } public void setMsg(String msg) { this.msg = msg; } public String getMsg() { return msg; } public void setData(T data) { this.data = data; } public T getData() { return data; } public ResponseVO(){} public ResponseVO(Integer code, String msg) { this.code = code; this.msg = msg; } public ResponseVO(Integer code, String msg, T data) { this.code = code; this.msg = msg; this.data = data; } public static ResponseVO ok() { return new ResponseVO(EnumsCode.SUCCESS.getCode(), EnumsCode.SUCCESS.getMsg()); } public static ResponseVO ok(Object data) { return new ResponseVO(EnumsCode.SUCCESS.getCode(), EnumsCode.SUCCESS.getMsg(), data); } public static ResponseVO fail() { return new ResponseVO(EnumsCode.FAIL.getCode(), EnumsCode.FAIL.getMsg()); } public static ResponseVO invalid() { return new ResponseVO(EnumsCode.INVALID.getCode(), EnumsCode.FAIL.getMsg()); } public static ResponseVO invalid(String msg) { return new ResponseVO(EnumsCode.INVALID.getCode(), msg); } public static ResponseVO empty() { return new ResponseVO(EnumsCode.EMPTY.getCode(), EnumsCode.EMPTY.getMsg()); } public static ResponseVO exception(Integer code) { switch (code) { case 4003: return new ResponseVO(EnumsCode.ARITHMETICEXCEPTION.getCode(), EnumsCode.ARITHMETICEXCEPTION.getMsg()); case 4004: return new ResponseVO(EnumsCode.NULLPOINTEREXCEPTION.getCode(), EnumsCode.NULLPOINTEREXCEPTION.getMsg()); } return new ResponseVO(EnumsCode.INVALID.getCode(), EnumsCode.INVALID.getMsg()); } }

3 数据校验

测试数据:

{ "questions":"", "answers":"1234" }

3.1 请求体数据校验

使用Valid类校验.

import javax.validation.Valid; Usage package com.company.web.controller; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.validation.annotation.Validated; import org.springframework.validation.BindException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.company.web.dto.*; import com.company.web.service.*; import com.company.web.vo.common.*; import javax.validation.Valid; import javax.validation.constraints.NotBlank; import java.util.List; /** * Transactional test. * @author xindaqi * @since 2020-10-20 */ @CrossOrigin(origins = "*", maxAge = 3600) @RestController @RequestMapping("/api/function/test") public class TransactionalTestController { static Logger logger = LoggerFactory.getLogger(TransactionalTestController.class); @Autowired private IDataSaveService dataSaveService; @RequestMapping(value = "/transactional/rollback/raw", method = RequestMethod.POST) public ResponseVO saveDataWithRollback(@RequestBody @Valid QuestionAnswerInputDTO params) { // TODO logic. } }

3.2 请求URL数据校验

使用Validated类校验和NotBlank,NotNull等校验在类上使用注解@Validated import org.springframework.validation.annotation.Validated; import javax.validation.constraints.NotBlank; Usage package com.company.web.controller; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.validation.annotation.Validated; import org.springframework.validation.BindException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.company.web.dto.*; import com.company.web.service.*; import com.company.web.vo.common.*; import javax.validation.Valid; import javax.validation.constraints.NotBlank; import java.util.List; /** * Transactional test. * @author xindaqi * @since 2020-10-20 */ @CrossOrigin(origins = "*", maxAge = 3600) @RestController @RequestMapping("/api/function/test") @Validated public class TransactionalTestController { static Logger logger = LoggerFactory.getLogger(TransactionalTestController.class); @Autowired private IDataSaveService dataSaveService; @RequestMapping(value = "/transactional/rollback/raw", method = RequestMethod.GET) public ResponseVO saveDataWithRollback(@NotBlank(message = "不能为空") @RequestParam("id") String id) { // TODO logic. } }

3.3 统一数据校验

3.3.1 统一异常捕获

package com.company.web.exception; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.MethodArgumentNotValidException; // import org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import com.company.web.vo.common.*; import java.util.List; import java.util.stream.Collectors; import javax.validation.ConstraintViolationException; /** * Uniform exception handle. * @author xindaqi * @since 2020-10-21 */ @RestControllerAdvice public class GlobalExceptionHandler { static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 参数绑定异常 * @param e * @return */ @ExceptionHandler(BindException.class) public ResponseVO validationExceptionHandler(BindException e) { BindingResult bindingResult = e.getBindingResult(); List<FieldError> fieldErrors = bindingResult.getFieldErrors(); // fieldErrors.forEach(fieldError -> { // errorMsg += fieldError.getDefaultMessage(); // }); // fieldErrors.stream().map(FieldError::getDefaultMessage).collect(Collectors.toList()); // // String errorMsg = String.join(",", fieldErrors); // String errorMsg = fieldErrors.toString(); String errorMsg = "bindException"; logger.info("Bind Validataion: {}", errorMsg); return ResponseVO.invalid(errorMsg); } /** * 方法参数校验异常 * @param e * @return */ @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseVO methodValidationExceptionHandler(MethodArgumentNotValidException e) { BindingResult bindingResult = e.getBindingResult(); List<FieldError> fieldErrors = bindingResult.getFieldErrors(); fieldErrors.forEach(fieldError -> { logger.info("Invalid message: {}", fieldError.getDefaultMessage()); }); fieldErrors.stream().map(FieldError::getDefaultMessage).collect(Collectors.toList()); logger.info("field error: {}", fieldErrors); String errorMsg = fieldErrors.toString(); logger.info("Method Validataion: {}", errorMsg); return ResponseVO.empty(); } /** * 空指针异常 * @param e * @return */ @ExceptionHandler(NullPointerException.class) public ResponseVO exceptionHandler(NullPointerException e) { String errorMsg = e.getMessage(); logger.info("Null pointer Exception Validataion: {}", errorMsg); return ResponseVO.exception(4004); } /** * 数据计算异常 * @param e * @return */ @ExceptionHandler(ArithmeticException.class) public ResponseVO exceptionHandler(ArithmeticException e) { String errorMsg = e.getMessage(); logger.info("Arithmetic Exception Validataion: {}", errorMsg); return ResponseVO.exception(4003); } /** * 未知异常 * @param e * @return */ @ExceptionHandler(Exception.class) public ResponseVO exceptionHandler(Exception e) { String errorMsg = e.getMessage(); logger.info("Exception Validataion: {}", errorMsg); return ResponseVO.invalid(errorMsg); } }

3.3.2 数据校验

统一数据校验,将捕获的异常交给全局异常处理类省去了try…catch省去了BindingResult package com.company.web.controller; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.validation.annotation.Validated; import org.springframework.validation.BindException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.company.web.dto.*; import com.company.web.service.*; import com.company.web.vo.common.*; import javax.validation.Valid; import javax.validation.constraints.NotBlank; import java.util.List; /** * Transactional test. * @author xindaqi * @since 2020-10-20 */ @CrossOrigin(origins = "*", maxAge = 3600) @RestController @RequestMapping("/api/function/test") @Validated public class TransactionalTestController { static Logger logger = LoggerFactory.getLogger(TransactionalTestController.class); @Autowired private IDataSaveService dataSaveService; @RequestMapping(value = "/transactional/rollback/raw", method = RequestMethod.POST) public ResponseVO saveDataWithRollback(@RequestBody @Valid QuestionAnswerInputDTO params) { Boolean dataSaveFlag = dataSaveService.saveQuestionAndAnswerWithTransactionRollback(params); if(dataSaveFlag) { logger.info("成功--保存问题和答案"); return ResponseVO.ok(); }else { logger.info("失败--保存问题和答案"); return ResponseVO.fail(); } } } 结果 { "code": 4001, "msg": "空数据", "data": null }

3.4 独立数据校验

独立数据校验使用try…catch捕获异常使用BindingResult进行数据校验 package com.company.web.controller; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.validation.annotation.Validated; import org.springframework.validation.BindException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.company.web.dto.*; import com.company.web.service.*; import com.company.web.vo.common.*; import javax.validation.Valid; import javax.validation.constraints.NotBlank; import java.util.List; /** * Transactional test. * @author xindaqi * @since 2020-10-20 */ @CrossOrigin(origins = "*", maxAge = 3600) @RestController @RequestMapping("/api/function/test") public class TransactionalTestController { static Logger logger = LoggerFactory.getLogger(TransactionalTestController.class); @Autowired private IDataSaveService dataSaveService; @RequestMapping(value = "/transactional/rollback/raw", method = RequestMethod.POST) public ResponseVO saveDataWithRollback(@RequestBody @Valid QuestionAnswerInputDTO params, BindingResult bindingResult) { try { if(bindingResult.hasErrors()){ logger.info("Error:{}", bindingResult.getAllErrors()); List<FieldError> fieldErrors = bindingResult.getFieldErrors(); fieldErrors.forEach(fieldError ->{ logger.error("Error filed: {}. \n Error message: {}", fieldError.getField(), fieldError.getDefaultMessage()); }); return ResponseVO.empty(); } Boolean dataSaveFlag = dataSaveService.saveQuestionAndAnswerWithTransactionRollback(params); if(dataSaveFlag) { logger.info("成功--保存问题和答案"); return ResponseVO.ok(); }else { logger.info("失败--保存问题和答案"); return ResponseVO.fail(); } }catch(Exception e) { e.printStackTrace(); return ResponseVO.invalid(); } } } 结果 { "code": 4001, "msg": "空数据", "data": null } Error:[Field error in object 'questionAnswerInputDTO' on field 'questions': rejected value []; codes [NotBlank.questionAnswerInputDTO.questions,NotBlank.questions,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [questionAnswerInputDTO.questions,questions]; arguments []; default message [questions]]; default message [参数为空]]

4 小结

数据校验:统一数据校验使用@Valid校验数据和@RestControllerAdvice增强Controller,借助ExceptionHandler捕获异常,省略try…catch数据校验:独立数据校验:使用BindingResult,独立对数据有性进行判断,需要使用try…catch数据校验:请求体校验,使用@Valid校验RequestBody数据校验:URL参数校验,使用@Validated在类上注解,同时使用NotNull等校验RequestParam

[参考文献] [1]https://blog.csdn.net/Xin_101/article/details/109206848

最新回复(0)