Java异常全局处理案例怎么开发

wen java案例 26

本文目录导读:

Java异常全局处理案例怎么开发

  1. Spring Boot 全局异常处理(推荐)
  2. 使用示例
  3. Java原生Web应用(非Spring)
  4. 高级配置
  5. 测试类
  6. 最佳实践建议

我来详细介绍Java异常全局处理的几种主流实现方案。

Spring Boot 全局异常处理(推荐)

1 创建统一响应类

// 响应状态码枚举
public enum ResultCode {
    SUCCESS(200, "成功"),
    ERROR(500, "系统异常"),
    BAD_REQUEST(400, "请求参数错误"),
    UNAUTHORIZED(401, "未授权"),
    FORBIDDEN(403, "权限不足"),
    NOT_FOUND(404, "资源不存在");
    private final int code;
    private final String message;
    // 构造方法、getter方法省略
}
// 统一响应类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
    private int code;
    private String message;
    private T data;
    private long timestamp;
    public static <T> Result<T> success(T data) {
        return new Result<>(ResultCode.SUCCESS.getCode(), 
                          ResultCode.SUCCESS.getMessage(), 
                          data, System.currentTimeMillis());
    }
    public static <T> Result<T> error(ResultCode resultCode) {
        return new Result<>(resultCode.getCode(), 
                          resultCode.getMessage(), 
                          null, System.currentTimeMillis());
    }
    public static <T> Result<T> error(int code, String message) {
        return new Result<>(code, message, null, System.currentTimeMillis());
    }
    public static <T> Result<T> error(String message) {
        return new Result<>(ResultCode.ERROR.getCode(), 
                          message, null, System.currentTimeMillis());
    }
}

2 自定义业务异常

// 业务异常类
@Getter
public class BusinessException extends RuntimeException {
    private int code;
    private String message;
    public BusinessException(ResultCode resultCode) {
        super(resultCode.getMessage());
        this.code = resultCode.getCode();
        this.message = resultCode.getMessage();
    }
    public BusinessException(int code, String message) {
        super(message);
        this.code = code;
        this.message = message;
    }
    public BusinessException(String message) {
        super(message);
        this.code = ResultCode.ERROR.getCode();
        this.message = message;
    }
}
// 参数校验异常
public class ParamValidateException extends RuntimeException {
    private final String field;
    private final String message;
    public ParamValidateException(String field, String message) {
        super(message);
        this.field = field;
        this.message = message;
    }
    // getter方法省略
}

3 全局异常处理器

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 处理业务异常
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.OK)
    public Result<?> handleBusinessException(BusinessException e) {
        log.error("业务异常:code={}, message={}", e.getCode(), e.getMessage());
        return Result.error(e.getCode(), e.getMessage());
    }
    /**
     * 处理参数校验异常
     */
    @ExceptionHandler(ParamValidateException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<?> handleParamValidateException(ParamValidateException e) {
        log.error("参数校验异常:field={}, message={}", e.getField(), e.getMessage());
        return Result.error(ResultCode.BAD_REQUEST.getCode(), e.getMessage());
    }
    /**
     * 处理参数绑定异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<?> handleValidationException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        Map<String, String> errors = new HashMap<>();
        bindingResult.getFieldErrors().forEach(error -> 
            errors.put(error.getField(), error.getDefaultMessage())
        );
        log.error("参数校验失败:{}", errors);
        return Result.error(ResultCode.BAD_REQUEST.getCode(), 
                          "参数校验失败:" + errors.toString());
    }
    /**
     * 处理HTTP请求方法不支持
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    public Result<?> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e) {
        log.error("请求方法不支持:{}", e.getMessage());
        return Result.error(405, "请求方法不支持:" + e.getMessage());
    }
    /**
     * 处理资源找不到
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Result<?> handleNoHandlerFound(NoHandlerFoundException e) {
        log.error("资源不存在:{}", e.getMessage());
        return Result.error(ResultCode.NOT_FOUND.getCode(), "请求的资源不存在");
    }
    /**
     * 处理参数类型不匹配
     */
    @ExceptionHandler(TypeMismatchException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<?> handleTypeMismatch(TypeMismatchException e) {
        log.error("参数类型不匹配:{}", e.getMessage());
        return Result.error(ResultCode.BAD_REQUEST.getCode(), 
                          "参数类型不匹配:" + e.getPropertyName());
    }
    /**
     * 处理缺失请求参数
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<?> handleMissingParam(MissingServletRequestParameterException e) {
        log.error("缺少必要参数:{}", e.getParameterName());
        return Result.error(ResultCode.BAD_REQUEST.getCode(), 
                          "缺少必要参数:" + e.getParameterName());
    }
    /**
     * 处理未知异常
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<?> handleException(Exception e, HttpServletRequest request) {
        log.error("系统异常:uri={}, message={}", request.getRequestURI(), e.getMessage(), e);
        return Result.error(ResultCode.ERROR.getCode(), "系统繁忙,请稍后重试");
    }
}

使用示例

1 控制器中使用

@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
    @PostMapping("/register")
    public Result<UserVO> register(@Valid @RequestBody RegisterDTO registerDTO) {
        // 业务逻辑
        if (userService.existsByUsername(registerDTO.getUsername())) {
            throw new BusinessException(400, "用户名已存在");
        }
        UserVO userVO = userService.register(registerDTO);
        return Result.success(userVO);
    }
    @GetMapping("/{id}")
    public Result<UserVO> getUser(@PathVariable Long id) {
        if (id == null || id <= 0) {
            throw new ParamValidateException("id", "用户ID无效");
        }
        UserVO userVO = userService.getUserById(id);
        if (userVO == null) {
            throw new BusinessException(ResultCode.NOT_FOUND);
        }
        return Result.success(userVO);
    }
}
// 请求DTO
@Data
public class RegisterDTO {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 50, message = "用户名长度要在3-50之间")
    private String username;
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度要在6-20之间")
    private String password;
    @Email(message = "邮箱格式不正确")
    private String email;
}

Java原生Web应用(非Spring)

1 Filter方式

@WebFilter("/*")
public class ExceptionFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(request, response);
        } catch (BusinessException e) {
            handleException(response, e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("系统异常", e);
            handleException(response, 500, "系统内部错误");
        }
    }
    private void handleException(ServletResponse response, int code, String message) 
            throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        writer.write(JSON.toJSONString(Result.error(code, message)));
        writer.flush();
        writer.close();
    }
}

高级配置

1 配置文件

# application.yml
spring:
  mvc:
    throw-exception-if-no-handler-found: true
  resources:
    add-mappings: false
# 自定义异常配置
exception:
  include-stacktrace: never
  log-level: ERROR

2 配置类

@Configuration
public class ExceptionConfig {
    @Bean
    public FilterRegistrationBean<ExceptionFilter> exceptionFilterRegistration() {
        FilterRegistrationBean<ExceptionFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new ExceptionFilter());
        registration.addUrlPatterns("/*");
        registration.setOrder(1);
        return registration;
    }
}

测试类

@SpringBootTest
@AutoConfigureMockMvc
public class GlobalExceptionHandlerTest {
    @Autowired
    private MockMvc mockMvc;
    @Test
    public void testBusinessException() throws Exception {
        mockMvc.perform(get("/api/users/999"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.code").value(404))
               .andExpect(jsonPath("$.message").value("资源不存在"));
    }
    @Test
    public void testValidationException() throws Exception {
        String invalidUser = "{\"username\":\"\",\"password\":\"123\"}";
        mockMvc.perform(post("/api/users/register")
               .contentType(MediaType.APPLICATION_JSON)
               .content(invalidUser))
               .andExpect(status().isBadRequest())
               .andExpect(jsonPath("$.code").value(400));
    }
}

最佳实践建议

  1. 区分异常类型:业务异常、系统异常、参数异常分别处理
  2. 日志记录:不同级别异常记录不同日志
  3. 安全考虑:生产环境隐藏详细错误信息
  4. 国际化:支持多语言错误消息
  5. 监控告警:关键异常告警通知

这样的全局异常处理方案可以统一错误响应格式,提高代码的可维护性和用户体验。

抱歉,评论功能暂时关闭!