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(S以上是关于SpringMvc,Springboot统一校验自定义异常全局异常处理的主要内容,如果未能解决你的问题,请参考以下文章