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