SpringMvc,Springboot统一校验自定义异常全局异常处理
Posted 诺浅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMvc,Springboot统一校验自定义异常全局异常处理相关的知识,希望对你有一定的参考价值。
引入jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
写一个DTO用来接收客户端传送的参数
@Data
public class AuditListDto
@ApiModelProperty(value = "提交人ID", required = true)
@NotNull
private Long commitPersonnelId;
@ApiModelProperty(value = "提交人名称", required = true)
@NotNull
private String commitPersonnelName;
@ApiModelProperty(value = "巡检设备表ID集合", required = true)
@NotEmpty
private List<Long> inspectionEquipmentIds;
在Controller的方法里面上加上@Validated
注解
@PostMapping("submitAccept")
@ApiOperation(value = "06.巡检数据提交验收", notes = "巡检数据提交验收")
@ApiOperationSupport(order = 22)
public ResultData<Void> submitAccept(@Validated @RequestBody AuditListDto conditionDto)
service.submitAccept(conditionDto);
return ResultData.success();
定义一个统一异常拦截器
package com.yxk.config;
import com.yxk.utils.ResultData;
import com.yxk.utils.ResultDataException;
import com.yxk.utils.Utils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.List;
@RestControllerAdvice
public class GlobalExceptionHandler
private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class.getName());
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ResultData<?> handleException(HttpRequestMethodNotSupportedException e)
return ResultData.failed(ResultData.NOT_SUPPORTED_HTTP_METHOD, "不支持' " + e.getMethod() + "'请求");
@ExceptionHandler(MissingServletRequestParameterException.class)
public ResultData<?> handleException(MissingServletRequestParameterException e)
return ResultData.failed(ResultData.MISSING_HTTP_PARAMETER,
"缺少必要参数" + e.getParameterName() + ", 类型:" + e.getParameterType());
@ExceptionHandler(BindException.class)
public ResultData<?> handleException(BindException e)
return ResultData.failed(ResultData.BIND_ERROR, e.getFieldErrors().get(0).getDefaultMessage());
@ExceptionHandler(ResultDataException.class)
public ResultData<?> handleResultDataException(ResultDataException e)
logger.info("", e);
return e.toResultData();
@ExceptionHandler(DataIntegrityViolationException.class) // uk/fk
public ResultData<?> handleDataIntegrityViolationException(DataIntegrityViolationException e)
final String delFK = "Cannot delete or update a parent row: a foreign key constraint fails";
final String saveFK = "Cannot add or update a child row: a foreign key constraint fails";
final String UK = "Duplicate entry";
final String truncation = "Data truncation";//
logger.error("", e);
if (e instanceof DuplicateKeyException)
// pk (not to here, except direct insert by native sql)
return ResultData.failed(ResultData.INTEGRITY_VIOLATION, "重复的id");
Throwable root = ExceptionUtils.getRootCause(e);
if (root != null)
String err = Utils.findStr(root.getMessage(), UK);
if (err != null) // uk
return ResultData.failed(ResultData.DUPLICATE_ENTRY, "重复数据,不能保存", err);
err = Utils.findStr(root.getMessage(), delFK);
if (err != null) // fk: Cannot delete or update a parent row: a foreign key constraint fails
return ResultData.failed(ResultData.DUPLICATE_ENTRY, "数据已被使用,不能删除", err);
err = Utils.findStr(root.getMessage(), saveFK);
if (err != null) // fk: Cannot add or update a child row: a foreign key constraint fails
return ResultData.failed(ResultData.DUPLICATE_ENTRY, "无效的引用id,不能保存", err);
err = Utils.findStr(root.getMessage(), truncation);
if (err != null) // Data truncation: Out of range value for column 'fee'
return ResultData.failed(ResultData.DUPLICATE_ENTRY, "数据截断(值超出范围)", err);
return ResultData.failed(ResultData.DUPLICATE_ENTRY, "数据不完整", root.getMessage());
return ResultData.failed(ResultData.INTEGRITY_VIOLATION, "数据不完整");
/**
* 处理@Validated参数校验失败异常
*
* @param exception 异常类
* @return 响应
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResultData<?> validExceptionHandler(MethodArgumentNotValidException exception)
BindingResult result = exception.getBindingResult();
StringBuilder stringBuilder = new StringBuilder();
if (result.hasErrors())
List<ObjectError> errors = result.getAllErrors();
if (errors != null)
StringBuilder finalStringBuilder = stringBuilder;
errors.forEach(p ->
FieldError fieldError = (FieldError) p;
logger.warn("Bad Request Parameters: dto entity [],field [],message []", fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage());
finalStringBuilder.append(String.format("%s[%s]%s", p.getObjectName(), ((FieldError) p).getField(), p.getDefaultMessage())).append(",");
);
if (stringBuilder.length() > 0)
stringBuilder = stringBuilder.deleteCharAt(stringBuilder.length() - 1);
return ResultData.failed(ResultData.VALIDATE_ERROR, stringBuilder.toString());
@ExceptionHandler(RuntimeException.class)
public ResultData<?> handlerUnknown(RuntimeException e)
logger.error("", e);
Throwable root = ExceptionUtils.getRootCause(e);
if (root != null)
return ResultData.failed(ResultData.UNKNOWN_ERROR, "未知错误", root.getMessage());
return ResultData.failed(ResultData.UNKNOWN_ERROR, "未知错误", e.getMessage());
自定义异常
public class ResultDataException extends RuntimeException
private static final long serialVersionUID = -9041090610418135434L;
public static ResultDataException of(int code, String message)
return new ResultDataException(code, message);
public static ResultDataException of(int code, String message, Object data)
return new ResultDataException(code, message, null, data);
public static ResultDataException duplicateKey(String message)
return new ResultDataException(ResultData.DUPLICATE_KEY, message);
public static ResultDataException notfound(String message)
return new ResultDataException(ResultData.NOT_FOUND, message);
public static ResultDataException notfound(Long id)
return new ResultDataException(ResultData.NOT_FOUND, "记录不存在: " + id);
public static ResultDataException validateRequired(String field)
return new ResultDataException(ResultData.VALIDATE_ERROR, field + " 不能为空");
public static ResultDataException validteInvalidFormat(String field, String value)
return new ResultDataException(ResultData.VALIDATE_ERROR, field + " 无效格式: " + value);
public static ResultDataException validteTooLong(String field, int maxLength, String value)
return new ResultDataException(ResultData.VALIDATE_ERROR,
String.format("[%s]超长(%d, %d): %s", field, maxLength, value.length(), value));
private final int code;
private final String internalError;
private final Object data;
public ResultDataException(int code, String message)
this(code, message, null);
public ResultDataException(int code, String message, String internalError)
this(code, message, internalError, null);
public ResultDataException(int code, String message, String internalError, Object data)
super(message);
this.code = code;
this.internalError = internalError;
this.data = data;
@SuppressWarnings("unchecked")
public <T> ResultData<T> toResultData()
return (ResultData<T>) ResultData.of(code, super.getMessage(), internalError, data);
public class ResultData<T>
public static <T> ResultData<T> of(int code, String message, T data)
return of(code, message, null, data);
public static <T> ResultData<T> of(int code, String message, String internalError, T data)
ResultData<T> ret = new ResultData<>();
ret.code = code;
ret.msg = message;
ret.internalError = internalError;
ret.data = data;
return ret;
public static <T> ResultList<T> ofList(int code, String message, String internalError, List<T> data)
ResultList<T> result = of(data, data == null ? 0 : data.size());
result.setCode(code);
result.setMsg(message);
result.setInternalError(internalError);
return result;
public static <T> ResultData<T> of(T data)
return of(SUCCESS, null, data);
public static <T> ResultList<T> of(List<T> data)
return of(data, data.size());
public static <T> ResultList<T> of(List<T> data, long total)
ResultList<T> ret = new ResultList<>();
ret.setData(data);
ret.setTotal(total);
return ret;
public static <T> ResultData<T> success(T data)
return of(SUCCESS, null, data);
// success (no ret data)
public static <T> ResultData<T> success()
return of(SUCCESS, null, null);
public static <T> ResultData<T> success(String message, T data) // success with message
return of(SUCCESS, message, data);
//
public static <T> ResultData<T> failed(int code, String message)
return failed(code, message, null);
public static <T> ResultData<T> failed(int code, String message, String internalError)
return of(code, message, internalError, null);
public static <T> ResultData<T> unknown(String message)
return of以上是关于SpringMvc,Springboot统一校验自定义异常全局异常处理的主要内容,如果未能解决你的问题,请参考以下文章