SpringMvc(异常处理)

1、内置异常处理解析器

打开 DispatcherServlet.properties
文件,这里面可以看到SpringMvc的一些内置的api,在这个key后面就是我们的异常处理解析器,默认的异常处理类有三个,如下示例:

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

在解析异常的时候,SpringMvc会在会从默认的处理器去搜索相对应的处理器。


1、org.springframework.web.servlet.HandlerExceptionResolver SpringMvc中的默认处理器。


2、org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver 处理SpringMvc中的一般异常。


3、org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver专门处理@ResponseStatus注解类型的异常,@ResponseStatus注解一般会标记在方法上,然后方法抛出一个异常。


4、org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver 处理@ExceptionHandler(例如平时的404,500等异常)。


5、AbstractHandlerMethodExceptionResolver: 是ExceptionHandlerExceptionResolver的父类


6、SimpleMappingExceptionResolver:通过配置的异常类和view的对应关系解析异常,将哪些异常直接指定到哪个视图上面去。

2、统一异常处理

2.1、获得Java处理类的异常信息并输出

注:要导入Tomcat依赖包,才可以使用jsp文件中的命令。
@ExceptionHandler注解如果写在控制器中,只能处理当前控制器的方法。

@Controller
public class ExceptionController {
    @RequestMapping("/exception01")
    public String exception01(@RequestParam("name") String name){
        System.out.println("方法处理中01");
        return "show";
    }

    @RequestMapping("/exception02")
    public String exception02(@RequestParam("name") String name){
        System.out.println("方法处理中02");
        return "show";
    }

    @ExceptionHandler(Exception.class)
    public ModelAndView handleException(Exception ex){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error");
        modelAndView.addObject("ex",ex);
        //日志记录
        System.out.println(ex.getMessage());
        return modelAndView;
    }
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
        出错了。<br/>
        <%= ((Exception)request.getAttribute("ex")).getMessage() %>
</body>
</html>

2.2、Java异常栈信息输出

别人的代码:

public static String getStackTrace(Throwable throwable){
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    try {
        throwable.printStackTrace(pw);
        return sw.toString();
    } finally {
        pw.close();
    }
}

我的代码:

@ExceptionHandler(Exception.class)
public ModelAndView handleException(Exception ex){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("error");
    modelAndView.addObject("ex",ex);
    //日志记录,获取到完整的堆栈信息
    System.out.println(getStackTrace(ex));
    return modelAndView;
}

public static String getStackTrace(Throwable throwable){
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    try {
        throwable.printStackTrace(pw);
        return sw.toString();
    } finally {
        pw.close();
    }
}

报错截图:

在这里插入图片描述

2.3、处理全局异常

处理异常的优先级

1、全局异常
2、处理器异常
3、全局异常中的具体异常
就近原则,如果自己当前控制器中有异常处理方法,就会用自己的
如果没有,就会用全局的异常处理,如果全局的异常处理有多个
则会精确匹配,匹配到最精准的那个

@ControllerAdvice注解标注在类上时,代表处理全局异常

@ControllerAdvice
public class GeneralExceptionHandler {

    /**
     * 全局异常处理
     * @param ex
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ModelAndView handleException01(Exception ex){
        System.out.println("全局异常处理。");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error");
        modelAndView.addObject("ex",ex);
        //日志记录,获取到完整的堆栈信息
        System.out.println(getStackTrace(ex));
        return modelAndView;
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ModelAndView handleException02(Exception ex){
        System.out.println("全局异常处理,参数找不到了。");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error");
        modelAndView.addObject("ex",ex);
        //日志记录,获取到完整的堆栈信息
        System.out.println(getStackTrace(ex));
        return modelAndView;
    }

    public static String getStackTrace(Throwable throwable){
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        try {
            throwable.printStackTrace(pw);
            return sw.toString();
        } finally {
            pw.close();
        }
    }
}

2.4、统一处理异常(json或页面)

我们可以通过多种方式去判断什么时候是ajax的json请求进来,什么时候是从页面访问过来,因为我们在做统一异常处理时两种不同场景的处理方式会不同,

集成jackson的pom配置文件如下

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.10.3</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.10.3</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.10.3</version>
</dependency>

都在代码中写着

/* 1、根据用户请求的方法是否是一个需要返回json数据的方法
        // 获得类上面的某个注解
        RestController restController = handlerMethod.getClass().getAnnotation(RestController.class);
        // 获得方法上的某个注解
        ResponseBody responseBody = handlerMethod.getMethod().getAnnotation(ResponseBody.class);
        // 如果当前请求是ajax就返回json
        if(restController != null || responseBody != null){}*/package cool.ale.exception;

import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.MissingPathVariableException;
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;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * @author dujlc
 *
 *
 *   统一异常处理:同时返回普通请求和ajax请求
 *      普通请求:返回视图,错误信息
 *      ajax:返回json
 *      {
 *          code
 *          message
 *      }
 *
 */
@ControllerAdvice
public class GeneralExceptionHandler {

    /**
     * 全局异常处理
     * @param ex
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ModelAndView handleException01(HttpServletRequest request,
                                          HttpServletResponse response,
                                          HandlerMethod handlerMethod,
                                          Exception ex) throws IOException {
        System.out.println("全局异常处理。");
        /* 1、根据用户请求的方法是否是一个需要返回json数据的方法
        // 获得类上面的某个注解
        RestController restController = handlerMethod.getClass().getAnnotation(RestController.class);
        // 获得方法上的某个注解
        ResponseBody responseBody = handlerMethod.getMethod().getAnnotation(ResponseBody.class);
        // 如果当前请求是ajax就返回json
        if(restController != null || responseBody != null){}*/

        // 2、如果请求头中的类型包含了 Content-Type 包含 application/json
        if (!StringUtils.isEmpty(request.getHeader("Content-Type")) && request.getHeader("Content-Type").indexOf("application/json") > -1){
            // 可直接依照下面的方式输出
            //response.getWriter().write("sss");
            // 但是我们一般是集成jackson,返回json
            // ModelAndView既支持json返回、也支持视图返回
            // ResponseBody的底层也是做了这个MappingJackson2JsonView
            ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
            // 通常会根据不同的异常返回不同的编码,这里为了简单,先随便写一种s
            modelAndView.addObject("code", HttpStatus.INTERNAL_SERVER_ERROR.value());
            modelAndView.addObject("message",ex.getMessage());
            return modelAndView;
        }
        else{
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.setViewName("error");
            modelAndView.addObject("ex",ex);
            //日志记录,获取到完整的堆栈信息
            System.out.println(getStackTrace(ex));
            return modelAndView;
        }
    }

    public static String getStackTrace(Throwable throwable){
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        try {
            throwable.printStackTrace(pw);
            return sw.toString();
        } finally {
            pw.close();
        }
    }
}

2.5、处理404页面

1、在WEB-INF文件夹下创建一个404.html文件
2、spring的配置文件中配置静态资源映射

<mvc:resources mapping="/404.html" location="/"></mvc:resources>

3、web.xml中映射资源

<error-page>
    <error-code>404</error-code>
    <location>/404.html</location>
</error-page>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值