SpringMvc,Springboot统一校验、自定义异常、全局异常处理

青旅半醒 2022-08-31 15:13 357阅读 0赞

引入jar包

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-validation</artifactId>
  4. </dependency>

写一个DTO用来接收客户端传送的参数

  1. @Data
  2. public class AuditListDto {
  3. @ApiModelProperty(value = "提交人ID", required = true)
  4. @NotNull
  5. private Long commitPersonnelId;
  6. @ApiModelProperty(value = "提交人名称", required = true)
  7. @NotNull
  8. private String commitPersonnelName;
  9. @ApiModelProperty(value = "巡检设备表ID集合", required = true)
  10. @NotEmpty
  11. private List<Long> inspectionEquipmentIds;
  12. }

在Controller的方法里面上加上@Validated注解

  1. @PostMapping("submitAccept")
  2. @ApiOperation(value = "06.巡检数据提交验收", notes = "巡检数据提交验收")
  3. @ApiOperationSupport(order = 22)
  4. public ResultData<Void> submitAccept(@Validated @RequestBody AuditListDto conditionDto) {
  5. service.submitAccept(conditionDto);
  6. return ResultData.success();
  7. }

定义一个统一异常拦截器

  1. package com.yxk.config;
  2. import com.yxk.utils.ResultData;
  3. import com.yxk.utils.ResultDataException;
  4. import com.yxk.utils.Utils;
  5. import org.apache.commons.lang3.exception.ExceptionUtils;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import org.springframework.dao.DataIntegrityViolationException;
  9. import org.springframework.dao.DuplicateKeyException;
  10. import org.springframework.validation.BindException;
  11. import org.springframework.validation.BindingResult;
  12. import org.springframework.validation.FieldError;
  13. import org.springframework.validation.ObjectError;
  14. import org.springframework.web.HttpRequestMethodNotSupportedException;
  15. import org.springframework.web.bind.MethodArgumentNotValidException;
  16. import org.springframework.web.bind.MissingServletRequestParameterException;
  17. import org.springframework.web.bind.annotation.ExceptionHandler;
  18. import org.springframework.web.bind.annotation.RestControllerAdvice;
  19. import java.util.List;
  20. @RestControllerAdvice
  21. public class GlobalExceptionHandler {
  22. private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class.getName());
  23. @ExceptionHandler({ HttpRequestMethodNotSupportedException.class})
  24. public ResultData<?> handleException(HttpRequestMethodNotSupportedException e) {
  25. return ResultData.failed(ResultData.NOT_SUPPORTED_HTTP_METHOD, "不支持' " + e.getMethod() + "'请求");
  26. }
  27. @ExceptionHandler({ MissingServletRequestParameterException.class})
  28. public ResultData<?> handleException(MissingServletRequestParameterException e) {
  29. return ResultData.failed(ResultData.MISSING_HTTP_PARAMETER,
  30. "缺少必要参数" + e.getParameterName() + ", 类型:" + e.getParameterType());
  31. }
  32. @ExceptionHandler({ BindException.class})
  33. public ResultData<?> handleException(BindException e) {
  34. return ResultData.failed(ResultData.BIND_ERROR, e.getFieldErrors().get(0).getDefaultMessage());
  35. }
  36. @ExceptionHandler({ ResultDataException.class})
  37. public ResultData<?> handleResultDataException(ResultDataException e) {
  38. logger.info("", e);
  39. return e.toResultData();
  40. }
  41. @ExceptionHandler({ DataIntegrityViolationException.class}) // uk/fk
  42. public ResultData<?> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
  43. final String delFK = "Cannot delete or update a parent row: a foreign key constraint fails";
  44. final String saveFK = "Cannot add or update a child row: a foreign key constraint fails";
  45. final String UK = "Duplicate entry";
  46. final String truncation = "Data truncation";//
  47. logger.error("", e);
  48. if (e instanceof DuplicateKeyException) {
  49. // pk (not to here, except direct insert by native sql)
  50. return ResultData.failed(ResultData.INTEGRITY_VIOLATION, "重复的id");
  51. }
  52. Throwable root = ExceptionUtils.getRootCause(e);
  53. if (root != null) {
  54. String err = Utils.findStr(root.getMessage(), UK);
  55. if (err != null) { // uk
  56. return ResultData.failed(ResultData.DUPLICATE_ENTRY, "重复数据,不能保存", err);
  57. }
  58. err = Utils.findStr(root.getMessage(), delFK);
  59. if (err != null) { // fk: Cannot delete or update a parent row: a foreign key constraint fails
  60. return ResultData.failed(ResultData.DUPLICATE_ENTRY, "数据已被使用,不能删除", err);
  61. }
  62. err = Utils.findStr(root.getMessage(), saveFK);
  63. if (err != null) { // fk: Cannot add or update a child row: a foreign key constraint fails
  64. return ResultData.failed(ResultData.DUPLICATE_ENTRY, "无效的引用id,不能保存", err);
  65. }
  66. err = Utils.findStr(root.getMessage(), truncation);
  67. if (err != null) { // Data truncation: Out of range value for column 'fee'
  68. return ResultData.failed(ResultData.DUPLICATE_ENTRY, "数据截断(值超出范围)", err);
  69. }
  70. return ResultData.failed(ResultData.DUPLICATE_ENTRY, "数据不完整", root.getMessage());
  71. }
  72. return ResultData.failed(ResultData.INTEGRITY_VIOLATION, "数据不完整");
  73. }
  74. /** * 处理@Validated参数校验失败异常 * * @param exception 异常类 * @return 响应 */
  75. @ExceptionHandler(MethodArgumentNotValidException.class)
  76. public ResultData<?> validExceptionHandler(MethodArgumentNotValidException exception) {
  77. BindingResult result = exception.getBindingResult();
  78. StringBuilder stringBuilder = new StringBuilder();
  79. if (result.hasErrors()) {
  80. List<ObjectError> errors = result.getAllErrors();
  81. if (errors != null) {
  82. StringBuilder finalStringBuilder = stringBuilder;
  83. errors.forEach(p -> {
  84. FieldError fieldError = (FieldError) p;
  85. logger.warn("Bad Request Parameters: dto entity [{}],field [{}],message [{}]", fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage());
  86. finalStringBuilder.append(String.format("%s[%s]%s", p.getObjectName(), ((FieldError) p).getField(), p.getDefaultMessage())).append(",");
  87. });
  88. }
  89. if (stringBuilder.length() > 0) {
  90. stringBuilder = stringBuilder.deleteCharAt(stringBuilder.length() - 1);
  91. }
  92. }
  93. return ResultData.failed(ResultData.VALIDATE_ERROR, stringBuilder.toString());
  94. }
  95. @ExceptionHandler(RuntimeException.class)
  96. public ResultData<?> handlerUnknown(RuntimeException e) {
  97. logger.error("", e);
  98. Throwable root = ExceptionUtils.getRootCause(e);
  99. if (root != null) {
  100. return ResultData.failed(ResultData.UNKNOWN_ERROR, "未知错误", root.getMessage());
  101. }
  102. return ResultData.failed(ResultData.UNKNOWN_ERROR, "未知错误", e.getMessage());
  103. }
  104. }

自定义异常

  1. public class ResultDataException extends RuntimeException {
  2. private static final long serialVersionUID = -9041090610418135434L;
  3. public static ResultDataException of(int code, String message) {
  4. return new ResultDataException(code, message);
  5. }
  6. public static ResultDataException of(int code, String message, Object data) {
  7. return new ResultDataException(code, message, null, data);
  8. }
  9. public static ResultDataException duplicateKey(String message) {
  10. return new ResultDataException(ResultData.DUPLICATE_KEY, message);
  11. }
  12. public static ResultDataException notfound(String message) {
  13. return new ResultDataException(ResultData.NOT_FOUND, message);
  14. }
  15. public static ResultDataException notfound(Long id) {
  16. return new ResultDataException(ResultData.NOT_FOUND, "记录不存在: " + id);
  17. }
  18. public static ResultDataException validateRequired(String field) {
  19. return new ResultDataException(ResultData.VALIDATE_ERROR, field + " 不能为空");
  20. }
  21. public static ResultDataException validteInvalidFormat(String field, String value) {
  22. return new ResultDataException(ResultData.VALIDATE_ERROR, field + " 无效格式: " + value);
  23. }
  24. public static ResultDataException validteTooLong(String field, int maxLength, String value) {
  25. return new ResultDataException(ResultData.VALIDATE_ERROR,
  26. String.format("[%s]超长(%d, %d): %s", field, maxLength, value.length(), value));
  27. }
  28. private final int code;
  29. private final String internalError;
  30. private final Object data;
  31. public ResultDataException(int code, String message) {
  32. this(code, message, null);
  33. }
  34. public ResultDataException(int code, String message, String internalError) {
  35. this(code, message, internalError, null);
  36. }
  37. public ResultDataException(int code, String message, String internalError, Object data) {
  38. super(message);
  39. this.code = code;
  40. this.internalError = internalError;
  41. this.data = data;
  42. }
  43. @SuppressWarnings("unchecked")
  44. public <T> ResultData<T> toResultData() {
  45. return (ResultData<T>) ResultData.of(code, super.getMessage(), internalError, data);
  46. }
  47. }
  48. public class ResultData<T> {
  49. public static <T> ResultData<T> of(int code, String message, T data) {
  50. return of(code, message, null, data);
  51. }
  52. public static <T> ResultData<T> of(int code, String message, String internalError, T data) {
  53. ResultData<T> ret = new ResultData<>();
  54. ret.code = code;
  55. ret.msg = message;
  56. ret.internalError = internalError;
  57. ret.data = data;
  58. return ret;
  59. }
  60. public static <T> ResultList<T> ofList(int code, String message, String internalError, List<T> data) {
  61. ResultList<T> result = of(data, data == null ? 0 : data.size());
  62. result.setCode(code);
  63. result.setMsg(message);
  64. result.setInternalError(internalError);
  65. return result;
  66. }
  67. public static <T> ResultData<T> of(T data) {
  68. return of(SUCCESS, null, data);
  69. }
  70. public static <T> ResultList<T> of(List<T> data) {
  71. return of(data, data.size());
  72. }
  73. public static <T> ResultList<T> of(List<T> data, long total) {
  74. ResultList<T> ret = new ResultList<>();
  75. ret.setData(data);
  76. ret.setTotal(total);
  77. return ret;
  78. }
  79. public static <T> ResultData<T> success(T data) {
  80. return of(SUCCESS, null, data);
  81. }
  82. // success (no ret data)
  83. public static <T> ResultData<T> success() {
  84. return of(SUCCESS, null, null);
  85. }
  86. public static <T> ResultData<T> success(String message, T data) { // success with message
  87. return of(SUCCESS, message, data);
  88. }
  89. //
  90. public static <T> ResultData<T> failed(int code, String message) {
  91. return failed(code, message, null);
  92. }
  93. public static <T> ResultData<T> failed(int code, String message, String internalError) {
  94. return of(code, message, internalError, null);
  95. }
  96. public static <T> ResultData<T> unknown(String message) {
  97. return of(UNKNOWN_ERROR, message, null);
  98. }
  99. public static <T> ResultData<T> unknown(Throwable t) {
  100. String message = t.getMessage();
  101. if (message == null || message.isEmpty()) {
  102. message = t.toString();
  103. }
  104. return of(UNKNOWN_ERROR, message, null);
  105. }
  106. public static <T> ResultData<T> notfound(String message) {
  107. return failed(NOT_FOUND, message);
  108. }
  109. //
  110. public static final int SUCCESS = 0;
  111. public static final int UNKNOWN_ERROR = -1;
  112. public static final int DUPLICATE_KEY = 1; // primaryKey
  113. public static final int DUPLICATE_ENTRY = 2; // uk
  114. public static final int INTEGRITY_VIOLATION = 3; // fk
  115. public static final int DISALLOW_OPERATION = 4;
  116. public static final int VALIDATE_ERROR = 5; // required/String format/value range
  117. // module defined code...
  118. public static final int UNAUTHORIZED = 401;
  119. public static final int FORBIDDEN = 403;
  120. public static final int NOT_FOUND = 404;
  121. /** * process data(record) is not in the biz rules expired status, or input * param(some-field) not in expired state(value-range). */
  122. public static final int ILLEGAL_STATE = 411;
  123. /** * http request BindException */
  124. public static final int BIND_ERROR = 412;
  125. /** * http request method is not supported. */
  126. public static final int NOT_SUPPORTED_HTTP_METHOD = 413;
  127. /** * http request missing some param */
  128. public static final int MISSING_HTTP_PARAMETER = 414;
  129. //
  130. private int code;
  131. private String msg;
  132. private String internalError;
  133. private T data;
  134. private Object extData;
  135. @SuppressWarnings("unchecked")
  136. public <R> R andThen(Consumer<R> f) {
  137. f.accept((R) this);
  138. return (R) this;
  139. }
  140. @SuppressWarnings("unchecked")
  141. public <R> R andThen(boolean predicate, Consumer<R> f) {
  142. if (predicate) {
  143. f.accept((R) this);
  144. }
  145. return (R) this;
  146. }
  147. public String toString() {
  148. return new StringBuilder().append("code=").append(code).append(", msg=").append(msg).append(", data=")
  149. .append(data).toString();
  150. }
  151. @JsonIgnore
  152. public boolean isSuccessed() {
  153. return code == SUCCESS;
  154. }
  155. @JsonIgnore
  156. public boolean isFailed() {
  157. return !isSuccessed();
  158. }
  159. public int getCode() {
  160. return code;
  161. }
  162. public void setCode(int code) {
  163. this.code = code;
  164. }
  165. public String getMsg() {
  166. return msg;
  167. }
  168. public void setMsg(String message) {
  169. this.msg = message;
  170. }
  171. public T getData() {
  172. return data;
  173. }
  174. public void setData(T data) {
  175. this.data = data;
  176. }
  177. public String getInternalError() {
  178. return internalError;
  179. }
  180. public void setInternalError(String internalError) {
  181. this.internalError = internalError;
  182. }
  183. public Object getExtData() {
  184. return extData;
  185. }
  186. public void setExtData(Object extData) {
  187. this.extData = extData;
  188. }
  189. }
  190. public class Utils {
  191. private Utils() {
  192. }
  193. public static String findStr(String s, String search) {
  194. if (s == null) {
  195. return s;
  196. }
  197. int idx = s.indexOf(search);
  198. if (idx > -1) {
  199. return s.substring(idx);
  200. }
  201. return null;
  202. }
  203. }

发表评论

表情:
评论列表 (有 0 条评论,357人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java全局异常处理-定义异常处理

    > 哈喽!大家好,我是旷世奇才李先生 > 文章持续更新,可以微信搜索【小奇JAVA面试】第一时间阅读,回复【资料】更有我为大家准备的福利哟,回复【项目】获取我为大家准备的项