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(UNKNOWN_ERROR, message, null);
}
public static <T> ResultData<T> unknown(Throwable t) {
String message = t.getMessage();
if (message == null || message.isEmpty()) {
message = t.toString();
}
return of(UNKNOWN_ERROR, message, null);
}
public static <T> ResultData<T> notfound(String message) {
return failed(NOT_FOUND, message);
}
//
public static final int SUCCESS = 0;
public static final int UNKNOWN_ERROR = -1;
public static final int DUPLICATE_KEY = 1; // primaryKey
public static final int DUPLICATE_ENTRY = 2; // uk
public static final int INTEGRITY_VIOLATION = 3; // fk
public static final int DISALLOW_OPERATION = 4;
public static final int VALIDATE_ERROR = 5; // required/String format/value range
// module defined code...
public static final int UNAUTHORIZED = 401;
public static final int FORBIDDEN = 403;
public static final int NOT_FOUND = 404;
/** * process data(record) is not in the biz rules expired status, or input * param(some-field) not in expired state(value-range). */
public static final int ILLEGAL_STATE = 411;
/** * http request BindException */
public static final int BIND_ERROR = 412;
/** * http request method is not supported. */
public static final int NOT_SUPPORTED_HTTP_METHOD = 413;
/** * http request missing some param */
public static final int MISSING_HTTP_PARAMETER = 414;
//
private int code;
private String msg;
private String internalError;
private T data;
private Object extData;
@SuppressWarnings("unchecked")
public <R> R andThen(Consumer<R> f) {
f.accept((R) this);
return (R) this;
}
@SuppressWarnings("unchecked")
public <R> R andThen(boolean predicate, Consumer<R> f) {
if (predicate) {
f.accept((R) this);
}
return (R) this;
}
public String toString() {
return new StringBuilder().append("code=").append(code).append(", msg=").append(msg).append(", data=")
.append(data).toString();
}
@JsonIgnore
public boolean isSuccessed() {
return code == SUCCESS;
}
@JsonIgnore
public boolean isFailed() {
return !isSuccessed();
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String message) {
this.msg = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getInternalError() {
return internalError;
}
public void setInternalError(String internalError) {
this.internalError = internalError;
}
public Object getExtData() {
return extData;
}
public void setExtData(Object extData) {
this.extData = extData;
}
}
public class Utils {
private Utils() {
}
public static String findStr(String s, String search) {
if (s == null) {
return s;
}
int idx = s.indexOf(search);
if (idx > -1) {
return s.substring(idx);
}
return null;
}
}
还没有评论,来说两句吧...