73 lines
3.2 KiB
Java
73 lines
3.2 KiB
Java
package com.yunhai.userbase.common;
|
||
|
||
import org.springframework.core.Ordered;
|
||
import org.springframework.core.annotation.Order;
|
||
import org.springframework.validation.BindException;
|
||
import org.springframework.validation.FieldError;
|
||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||
|
||
import javax.validation.ConstraintViolation;
|
||
import javax.validation.ConstraintViolationException;
|
||
import java.util.LinkedHashMap;
|
||
import java.util.Map;
|
||
import java.util.stream.Collectors;
|
||
|
||
/**
|
||
* 全局异常处理器:仅处理「参数校验」类异常,把 Spring 默认抛出的冗长消息收敛成「一句话」返回,
|
||
* 避免前端收到整段 Validation failed ... 堆栈文本。<br>
|
||
* 返回 HTTP 200 + {@code {code:4, msg:..., data:null}} 结构(而非 HTTP 400),
|
||
* 与前端 alova errorHandle 的约定一致:status!=200 会被当作网络错误,code=4 才走「参数错误」分支。<br>
|
||
* 注意:本处理器【不】处理业务异常(如 {@code DException}),业务异常交由项目框架统一处理
|
||
* (返回 code=5、msg=异常消息),此处若拦截会覆盖框架行为。
|
||
*
|
||
* @author chenx
|
||
*/
|
||
@RestControllerAdvice
|
||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||
public class GlobalExceptionHandler {
|
||
|
||
/** 参数校验失败的业务码,前端按「参数错误」处理 */
|
||
private static final int CODE_PARAM_ERROR = 4;
|
||
|
||
/** @RequestBody + @Validated/@Valid 失败:提取每个字段的 defaultMessage。 */
|
||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||
public Map<String, Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex) {
|
||
return paramError(fieldErrorsMessage(ex.getBindingResult().getFieldErrors()));
|
||
}
|
||
|
||
/** 普通 Bean 参数(如 SortChildren/Move 的 @Validated 请求体对象)校验失败。 */
|
||
@ExceptionHandler(BindException.class)
|
||
public Map<String, Object> handleBind(BindException ex) {
|
||
return paramError(fieldErrorsMessage(ex.getBindingResult().getFieldErrors()));
|
||
}
|
||
|
||
/** 方法级约束(@PathVariable/@RequestParam 上的 @NotNull 等)校验失败。 */
|
||
@ExceptionHandler(ConstraintViolationException.class)
|
||
public Map<String, Object> handleConstraintViolation(ConstraintViolationException ex) {
|
||
String msg = ex.getConstraintViolations().stream()
|
||
.map(ConstraintViolation::getMessage)
|
||
.collect(Collectors.joining(";"));
|
||
return paramError(msg);
|
||
}
|
||
|
||
private String fieldErrorsMessage(java.util.List<FieldError> fieldErrors) {
|
||
if (fieldErrors == null || fieldErrors.isEmpty()) {
|
||
return "参数校验失败";
|
||
}
|
||
return fieldErrors.stream()
|
||
.map(FieldError::getDefaultMessage)
|
||
.collect(Collectors.joining(";"));
|
||
}
|
||
|
||
/** HTTP 200 + code/msg/data 结构体,前端根据 code 提示 msg */
|
||
private Map<String, Object> paramError(String msg) {
|
||
Map<String, Object> body = new LinkedHashMap<>();
|
||
body.put("code", CODE_PARAM_ERROR);
|
||
body.put("msg", msg);
|
||
body.put("data", null);
|
||
return body;
|
||
}
|
||
}
|