Spring Boot全局异常捕获处理

目标:通过ControllerAdvice和ExceptionHandler捕获异常和错误信息,向前端返回json格式的状态码及异常描述信息。

1.创建一个全局异常捕获处理类GlobalExceptionHandler

package com.qiqi.exception;
import com.qiqi.utils.ExceptionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 全局异常捕获处理
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * http请求的方法不正确
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public String httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e) {
        logger.error("http请求的方法不正确:【"+e.getMessage()+"】");
        return ExceptionUtil.resultOf(ResultStatusCode.RequestMethodNotAllowed);
    }

    /**
     * 请求参数不全
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public String missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e) {
        logger.error("请求参数不全:【"+e.getMessage()+"】");
        return ExceptionUtil.resultOf(ResultStatusCode.MissingServletRequestParameter);
    }

    /**
     * 请求参数类型不正确
     */
    @ExceptionHandler(TypeMismatchException.class)
    @ResponseBody
    public String typeMismatchExceptionHandler(TypeMismatchException e) {
        logger.error("请求参数类型不正确:【"+e.getMessage()+"】");
        return ExceptionUtil.resultOf(ResultStatusCode.TypeMismatchException);
    }

    /**
     * 数据格式不正确
     */
    @ExceptionHandler(DataFormatException.class)
    @ResponseBody
    public String dataFormatExceptionHandler(DataFormatException e) {
        logger.error("数据格式不正确:【"+e.getMessage()+"】");
        return ExceptionUtil.resultOf(ResultStatusCode.DataFormatException);
    }

    /**
     * 用户没找到
     */
    @ExceptionHandler(UserNotFoundException.class)
    @ResponseBody
    public String userNotFoundExceptionHandler(UserNotFoundException e) {
        logger.error("用户没找到:【"+e.getMessage()+"】");
        return ExceptionUtil.resultOf(ResultStatusCode.UserNotExist);
    }

    /**
     * 非法输入
     */
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseBody
    public String illegalArgumentExceptionHandler(IllegalArgumentException e) {
        logger.error("非法输入:【"+e.getMessage()+"】");
        return ExceptionUtil.resultOf(ResultStatusCode.IllegalArgumentException);
    }


    @ExceptionHandler  //处理其他异常
    @ResponseBody
    public String allExceptionHandler(Exception e){
        logger.error("具体错误信息:【"+ExceptionUtil.getErrorMessage(e)+"】"); //会记录出错的代码行等具体信息
        int count = 0; //只打印15行的错误堆栈
        for (StackTraceElement stackTraceElement : e.getStackTrace()) {
            logger.error(stackTraceElement.toString());
            if(count++ > 13) break;
        }
        return ExceptionUtil.resultOf(ResultStatusCode.SystemException);
    }

}

2.自定义了一些异常UserNotFoundException、DataFormatException等。

public class UserNotFoundException extends Exception {
    public UserNotFoundException() {
    }

    public UserNotFoundException(String message) {
        super(message);
    }

    public UserNotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}

 3.自定义一个异常状态码的枚举类 ResultStatusCode

public enum ResultStatusCode {

    Success("0", "Success"),
    UserNotExist("1", "User not exist"),
    InValidParameter("2","Invalid parameter"),
    DataFormatException("4", "DataFormat exception"),
    DataNotExistException("5", "DataNotExistException"),
    TimeFormatException("6","TimeFormat Exception"),
    PictureFormatException("7","PictureFormat Exception"),
    IllegalArgumentException("8","IllegalArgumentException"),
    TokenInvalidOrOverdueException("9", "Token invalid or overdue exception"),
    AuthorizationCodeError("10", "authorization code error"),
    WrongSignatureException("11","Wrong Signature Exception"),
    SystemException("50", "system Exception"),
    MissingServletRequestParameter("400","Missing servletRequest parameter"),
    TypeMismatchException("401","Request parameter Type not match"),
    RequestMethodNotAllowed("405","Request method  not Allowed"),
    ;

    private String code;
    private String msg;

    private ResultStatusCode(String code,String msg){
        this.code=code;
        this.msg=msg;
    }

    public String getMsg(){
        return this.msg;
    }
    public String getCode(){
        return this.code;
    }

}

4.自定义异常处理工具类

里面编写两个方法:

方法一:打印异常的详细信息

方法二:将枚举类型的状态码及描述转为json

注意:fastjson包,必须为1.2.24,否则没有configEnumAsJavaBean()方法。

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.qiqi.exception.ResultStatusCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * 返回异常的处理
 */
public class ExceptionUtil {

    private static final Logger logger = LoggerFactory.getLogger(ExceptionUtil.class);

    private ExceptionUtil() {
    }

    /**
     * 获取异常信息
     *
     * @param e 异常
     */
    public static String getErrorMessage(Exception e) {
        StringWriter sw = null;
        PrintWriter pw = null;
        try {
            sw = new StringWriter();
            pw = new PrintWriter(sw);
            // 将出错的栈信息输出到printWriter中
            e.printStackTrace(pw);
            pw.flush();
            sw.flush();
        } finally {
            if (sw != null) {
                try {
                    sw.close();
                } catch (IOException e1) {
                    logger.info(e1.getMessage());
                }
            }
            if (pw != null) {
                pw.close();
            }
        }
        return sw.toString();
    }
    /**
     * 异常信息-->json
     *
     */
    public static String resultOf(ResultStatusCode resultStatusCode) {
        SerializeConfig config = new SerializeConfig();
        config.configEnumAsJavaBean(ResultStatusCode.class);
        return JSON.toJSONString(resultStatusCode, config);
    }

}

5.使用

Controller层:抛出异常让GlobalExceptionHandler捕获处理

注意:显示的throw异常后,后面的代码不再会被执行到。

    /**
     * 删除用户
     */
    @RequestMapping(value = "/delete", method = RequestMethod.GET)
    public Response deleteUser(@RequestParam(value = "user_id", required = true) String userId)
            throws UserNotFoundException {
        Response response = new Response();
        long id = Long.parseLong(userId);
        userService.deleteUser(id);
        response = new Response("0","删除用户成功",null);
        logger.info("删除用户:id="+ userId + "  result="+response.toString());
        return response;
    }

Service层: 抛出异常

    public void deleteUser(long userId )throws UserNotFoundException {
        if (userRepository.existsById(userId) == false){
             throw new UserNotFoundException();
        }
        userRepository.deleteById(userId);
    }

6.测试结果

一:填写请求参数时,故意让String类型的user_id =“3a",在long id = Long.parseLong(userId);转换时,会抛出IllegalArgumentException异常的子类NumberFormatException。由于我们在GlobalExceptionHandler捕获处理了IllegalArgumentException这个非法输入异常,并对其定义了状态码及描述。所以前端会收到json格式的响应:

{"code":"8","msg":"IllegalArgumentException"}

而在控制台,会输出日志:2019-01-04 14:39:21.437 ERROR com.qiqi.exception.GlobalExceptionHandler Line:118 - 非法输入:【For input string: "3a"】

二:请求时发送POST请求(代码中要求是GET请求)

前端响应:{"code":"405","msg":"Request method  not Allowed"}

后台日志:2019-01-04 14:41:41.963 ERROR com.qiqi.exception.GlobalExceptionHandler Line:58  - http请求的方法不正确:【Request method 'POST' not supported】

三:在程序中抛出IOException

IOException异常没有单独捕获,被捕获在allExceptionHandler方法中,在这个方法中打印出了异常的详细信息,包括出现异常的代码行号等,同时还打印了异常的堆栈信息。

前端响应:{"code":"50","msg":"system Exception"}

后台日志:

2019-01-04 14:57:08.583 ERROR com.qiqi.exception.GlobalExceptionHandler Line:145 - 具体错误信息:【java.io.IOException
	at com.qiqi.service.UserService.getUser(UserService.java:42)
	at com.qiqi.controller.UserController.getUser(UserController.java:47)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:791)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)
】
2019-01-04 14:57:08.587 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - com.qiqi.service.UserService.getUser(UserService.java:42)
2019-01-04 14:57:08.587 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - com.qiqi.controller.UserController.getUser(UserController.java:47)
2019-01-04 14:57:08.587 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2019-01-04 14:57:08.588 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
2019-01-04 14:57:08.588 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
2019-01-04 14:57:08.588 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - java.lang.reflect.Method.invoke(Method.java:497)
2019-01-04 14:57:08.588 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
2019-01-04 14:57:08.588 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
2019-01-04 14:57:08.588 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
2019-01-04 14:57:08.588 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
2019-01-04 14:57:08.589 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
2019-01-04 14:57:08.589 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
2019-01-04 14:57:08.589 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
2019-01-04 14:57:08.589 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
2019-01-04 14:57:08.589 ERROR com.qiqi.exception.GlobalExceptionHandler Line:148 - org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)

 

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Boot提供了全局异常处理机制,可以通过以下几个步骤搭建全局异常捕获。 1. 创建一个全局异常处理类,使用@ControllerAdvice注解标记该类为全局异常处理类,并使用@ExceptionHandler注解定义要捕获异常类型。 2. 在全局异常处理类中编写异常处理方法,通过@ExceptionHandler注解标注,指定要捕获异常类型。在方法中可以定义异常处理的逻辑,比如返回自定义的错误信息、记录日志等。 3. 如果要返回自定义的错误信息,可以创建一个自定义的返回结果类,用于封装错误信息。在异常处理方法中将错误信息封装到自定义的返回结果类中,并将其返回给前端。 4. 使用@ControllerAdvice注解标记的全局异常处理类,会自动将其注册为bean,并作为全局异常处理器生效。 下面是一个简单的示例代码: ```java @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<ErrorResponse> handleException(Exception ex) { ErrorResponse error = new ErrorResponse(); error.setMessage("系统内部错误"); error.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR); } } public class ErrorResponse { private String message; private int status; // 省略getter和setter方法 } ``` 在上述示例中,我们通过@ControllerAdvice注解标记了一个全局异常处理类GlobalExceptionHandler,并通过@ExceptionHandler注解定义了handleException方法,用于捕获Exception类型的异常。在方法中,我们创建了一个ErrorResponse对象,并将错误信息封装到该对象中返回给前端。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值