1.优化改进全局异常类

2.项目介绍调整
This commit is contained in:
海言
2026-01-09 11:41:19 +08:00
parent 27b45cca66
commit 055987541c
6 changed files with 209 additions and 106 deletions

View File

@@ -0,0 +1,80 @@
package cn.xf.basedemo.common.exception;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import jakarta.servlet.http.HttpServletRequest;
/**
* @Description: 全局异常处理类 (使用 @RestControllerAdvice 替代旧版
* HandlerExceptionResolver)
* @Author: xiongfeng
* @Date: 2025/1/9
* @Version: 2.0
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理登录/认证异常
*/
@ExceptionHandler(LoginException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
public GenericResponse<Void> handleLoginException(LoginException e, HttpServletRequest request) {
log.warn("认证失败 [URL:{}]: code={}, message={}", request.getRequestURI(), e.getCode(), e.getMessage());
return new GenericResponse<>(e.getCode(), null, e.getMessage());
}
/**
* 处理业务逻辑异常
*/
@ExceptionHandler(BusinessException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST) // 或者使用 HttpStatus.OK根据前端约定
public GenericResponse<Void> handleBusinessException(BusinessException e, HttpServletRequest request) {
log.warn("业务异常 [URL:{}]: code={}, message={}", request.getRequestURI(), e.getCode(), e.getMessage());
return new GenericResponse<>(e.getCode(), null, e.getMessage());
}
/**
* 处理参数校验异常 (处理 @Valid / @Validated 触发的异常)
*/
@ExceptionHandler({ MethodArgumentNotValidException.class, BindException.class })
@ResponseStatus(HttpStatus.BAD_REQUEST)
public GenericResponse<Void> handleValidationException(Exception e, HttpServletRequest request) {
BindingResult bindingResult = null;
if (e instanceof MethodArgumentNotValidException) {
bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
} else if (e instanceof BindException) {
bindingResult = ((BindException) e).getBindingResult();
}
String errorMsg = "参数校验失败";
if (bindingResult != null && bindingResult.hasErrors()) {
FieldError fieldError = bindingResult.getFieldError();
if (fieldError != null) {
errorMsg = fieldError.getDefaultMessage();
}
}
log.warn("参数校验失败 [URL:{}]: {}", request.getRequestURI(), errorMsg);
return new GenericResponse<>(ResponseCode.USER_INPUT_ERROR.getCode(), null, errorMsg);
}
/**
* 处理所有未知的系统异常 (兜底)
*/
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public GenericResponse<Void> handleSystemException(Exception e, HttpServletRequest request) {
// 生产级关键点:必须记录异常堆栈,否则无法排查 BUG
log.error("系统发生未知异常 [URL:{}]", request.getRequestURI(), e);
return new GenericResponse<>(500, null, "系统内部繁忙,请稍后再试");
}
}

View File

@@ -1,53 +0,0 @@
package cn.xf.basedemo.common.exception;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @Description: 全局异常捕获类所有异常包括拦截器、Controller、视图HandlerExceptionResolver更底层
* @ClassName: GlobalExceptionResolver
* @Author: xiongfeng
* @Date: 2025/8/23 23:30
* @Version: 1.0
*/
@Slf4j
@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
response.setContentType("application/json;charset=UTF-8");
try (PrintWriter writer = response.getWriter()) {
if (ex instanceof LoginException) {
response.setStatus(HttpStatus.FORBIDDEN.value());
LoginException le = (LoginException) ex;
writer.write(new ObjectMapper().writeValueAsString(
new GenericResponse<>(le.getCode(), null, le.getMessage())
));
} else if (ex instanceof BusinessException) {
BusinessException be = (BusinessException) ex;
response.setStatus(HttpStatus.BAD_REQUEST.value());
writer.write(new ObjectMapper().writeValueAsString(
new GenericResponse<>(be.getCode(), null, be.getMessage())
));
} else {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
writer.write(new ObjectMapper().writeValueAsString(
new GenericResponse<>(500, null, "系统异常")
));
}
} catch (IOException ioEx) {
log.error("写响应失败", ioEx);
}
return new ModelAndView();
}
}

View File

@@ -8,6 +8,7 @@ import cn.xf.basedemo.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
@@ -27,7 +28,7 @@ public class UserController {
@Operation(summary = "用户登录", description = "用户登录")
@PostMapping("/login")
public RetObj login(@RequestBody LoginInfoRes res) {
public RetObj login(@RequestBody @Validated LoginInfoRes res) {
return userService.login(res);
}

View File

@@ -1,6 +1,7 @@
package cn.xf.basedemo.model.res;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
@@ -16,6 +17,7 @@ public class LoginInfoRes {
/**
* 登录密文
*/
@NotBlank(message = "登录密文不能为空")
@Schema(name = "登录密文")
private String encryptedData;
}