Java中的全局异常处理器 -- GlobalExceptionHandler

发布于:2024-08-16 ⋅ 阅读:(73) ⋅ 点赞:(0)

========================
开发记录:全局异常处理器笔记

import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

import static com.tal.markms.common.CommonConstant.SOCKET_EXCEPTION;



@Slf4j
@RestControllerAdvice(basePackages = {"com.tal.markms"})
public class GlobalExceptionHandler {

    @Value("${spring.profiles.active}")
    private String env;

    /**
     * COMMON异常,自定义异常
     *
     * @param ce
     * @param request
     * @return
     */
    @ExceptionHandler(BizException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    private HttpResult commonExceptionHandler(BizException ce, HttpServletRequest request) {
        log.info("BizException:{}={}", ce.getErrCode().getMessage(), request != null ? request.getRequestURL() : "no-url", ce);
        return new HttpResult(ce.getErrCode().getCode(), ce.getErrCode().getMessage());
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    private HttpResult requestConverterExceptionHandler(HttpMessageNotReadableException ce, HttpServletResponse response) {
        log.info("HttpMessageNotReadableException:{}", ce.getMessage() + "--" + ce.getLocalizedMessage());
        return new HttpResult(ErrorCode.SystemError.ERROR_INVALID_PARAM.getCode(), "提交参数错误" );
    }


    @ExceptionHandler(Exception.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.OK)
    public HttpResult runtimeExceptionHandler(Exception e, HttpServletRequest request) {
        log.error("RuntimeExceptionHandler -> e={}={}", e.getLocalizedMessage(), (request != null ? request.getRequestURL() : "no-url"), e);
        doOriginalException(e);
        if ("dev".equals(env)) {
            e.printStackTrace();
        }
        return new HttpResult(ErrorCode.SystemError.ERROR_SYSTEM_ERROR.getCode(), "服务处理错误,请联系管理员查看原因");
    }

    private void doOriginalException(Throwable original) {
        if (original instanceof SocketException
                || original instanceof RedisConnectionFailureException
                || original instanceof UnknownHostException
                || original instanceof SocketTimeoutException
                || original instanceof MyBatisSystemException
                || original instanceof ConnectException) {
            log.error(SOCKET_EXCEPTION, original.getMessage());
        }
    }
}

@ControllerAdvice 和 @ResponseBody 是 Spring 框架中用于处理控制器层逻辑的两个注解,它们各自的作用如下:

@ControllerAdvice

@ControllerAdvice 是一个增强控制器的注解,允许你定义全局的异常处理、数据绑定、以及数据格式化等功能,应用于多个控制器类。它的主要作用有:

  • 1、全局异常处理:
    • 可以为所有控制器统一定义异常处理逻辑,而无需在每个控制器中重复定义。
    • 使用 @ExceptionHandler 方法捕获并处理指定类型的异常。
  • 2、全局数据绑定:
    • 可以使用 @InitBinder 注解的方法,为所有控制器提供统一的数据绑定逻辑。
  • 3、全局数据格式化:
    • 使用 @ModelAttribute 注解的方法,可以为所有控制器统一添加模型数据。
@ControllerAdvice
public class GlobalControllerAdvice {
    // 处理所有类型为 BizException 的异常
    @ExceptionHandler(BizException.class)
    public ResponseEntity<String> handleBizException(BizException ex) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage());
    }

    // 可以初始化绑定器,用于全局的数据绑定处理
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // 例如,注册一个自定义编辑器
        binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false));
    }

    // 为所有请求提供一个默认的模型属性
    @ModelAttribute
    public void addAttributes(Model model) {
        model.addAttribute("projectName", "My Project");
    }
}

@ResponseBody

@ResponseBody 注解用于将控制器方法的返回值直接作为 HTTP 响应体返回给客户端,而不是默认的视图解析器处理。其主要作用是:

  • 1、返回 JSON 或 XML:
    • 通常用于 RESTful 风格的控制器,返回 JSON、XML 或其他格式的数据。
    • 通过 Spring 的消息转换器自动将返回对象转换为适当的格式。
  • 2、简化响应处理:
    • 不需要返回 ModelAndView,而是直接返回对象,Spring 会负责转换为 HTTP 响应。
@RestController // 等同于 @Controller + @ResponseBody
public class UserController {

    // 返回 JSON 格式的用户数据
    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        // 查询用户逻辑
        return userService.findById(id);
    }

    // 在单个方法上使用 @ResponseBody
    @GetMapping("/status")
    @ResponseBody
    public String status() {
        return "OK";
    }
}

Over !