springmvc错误处理

如果没有异常处理, 是直接将异常抛给jsp, jsp处理了。

 

 

 

  1. 使用 @ ExceptionHandler 注解

  2. 实现 HandlerExceptionResolver 接口, 并加入spring容器

  3. 使用 @controlleradvice 注解

就来看看这几种方式

1. 使用 @ ExceptionHandler 注解

HiController:

@Controller
public class HiController {
    @RequestMapping("/hi")
    public ModelAndView getHi() {
        ModelAndView mav = new ModelAndView("me");
//        String hi = "hi".substring(1,5);
        int a = 1/0;

        return mav;
    }

    @ExceptionHandler(value=StringIndexOutOfBoundsException.class)
    @ResponseBody
    public String handleStringException() {
        return "string out of bounds";
    }

    @ExceptionHandler(value=ArithmeticException.class)
    @ResponseBody
    public String handleException() {
        return "number illegal";
    }
}

再写一个Controller:

@Controller
public class MyController {
    @RequestMapping("/hello")
    public String getHello() {
        int a = 1/0;
        return "say Hello";
    }
}

结果:

 

 这种只能处理@ExceptionHandler所在Handler的异常。别的Handler的异常不能处理。 想定义全局的,这种每个Controller都要写一遍,所以并不好用

看了一下源码,DispatcherServlet的catch里做了一些异常处理,直到这里:

拿到的是这个Handler(HiController)的ExceptionHandlerMethodResolver,   如果进的是/mvc/hello (另一个Controller), resolver就是空的。 所以它只能执行对应的Controller

 

 

后面做的事情,大概就是找到match的Exception,然后通过反射调用这个handleStringException,再处理对应的ModelAndView:

具体debug看一下:

通过抛出的异常,找到对应的方法:返回的 method 是 public java.lang.String com.springmvc.HiController.handleException(),

 

 再通过反射调用HiController.handleException()方法,

 

 

 

2. 实现 HandlerExceptionResolver 接口

代码:

1.还是用上面两个Controller

2. MyHandlerExceptionResolver :

//@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView mav = new ModelAndView("exception");
        return mav;
    }
}

3. springMVC.xml:

<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp/"></property>
<property name="suffix" value=".jsp"></property>
<property name="cache" value="false"></property>
</bean>
<bean name="handlerExceptionResolver" class="exception.MyHandlerExceptionResolver"/>

jsp:

 

访问:

 

这里使用@Component没有效果,可以看到springMVC容器中根本没有自定义的ExceptionResolver,很奇怪使用@Component为什么没有加入到容器中?  但是使用xml能加入到容器,所以xml的没问题

 

 

 

 

先看看上面用到的Exception的继承关系

HandlerExceptionResolver接口就一个方法:

public interface HandlerExceptionResolver {

    @Nullable
    ModelAndView resolveException(
            HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);

}

 

 

 

Q1:自定义的handlerExceptionResolver是怎么注册的? 

启动spring的时候注册的, 调用到Listener 

 

 

 

 

 

 

 

 

 从spring容器中获取type为org.springframework.web.servlet.HandlerExceptionResolver的bean:

 

Q2: 为什么使用Component 自定义的ExceptionResolver没有注册到容器中?

今天再看, 用另一个Controller看看容器中到底有没有这个bean, 结果是false, 一开始以为是bean的实例化顺序发现想法不对。

 

@RestController
public class MyController {

    @Autowired
    ApplicationContext ac;

    @RequestMapping("/hello")
    public String getHello() {
        boolean b = ac.containsBean("myHandlerExceptionResolver");
        System.out.println("contains: " + b);
        return "say Hello";
    }
}

 

再看原来是扫描包的问题:

    <!--配置包扫描-->
    <context:component-scan base-package="com.springmvc"></context:component-scan>
    <context:component-scan base-package="inteceptor"></context:component-scan>
    <context:component-scan base-package="exception"></context:component-scan>

所以那天我自己实现interceptor接口也没成功。下一篇试试。

 

 

Q3: 这种怎么对不同的exception进入不同的处理页面?

 

 

 

3. 使用 @controlleradvice 注解

 controlleradvice看完aop再看是为什么?

先实验一下就完

 

代码:

ExceptionController:

 

@ControllerAdvice
public class ExceptionController {


    @ExceptionHandler(value=ArithmeticException.class)
    @ResponseBody
    public String handleArithmeticException() {
        return "math illegal";
    }


    @ExceptionHandler(value=StringIndexOutOfBoundsException.class)
    @ResponseBody
    public String handleStringException() {
        return "string out of bounds";
    }
}

测试用HiController:

@Controller
public class HiController {
    @RequestMapping("/hi")
    public ModelAndView getHi() {
        ModelAndView mav = new ModelAndView("me");
        int a = 1/0;
        return mav;
    }

    @RequestMapping("/hii")
    public ModelAndView getHii() {
        ModelAndView mav = new ModelAndView("me");
        String hi = "hi".substring(1, 5);
        return mav;
    }

}

结果, 不在同一个controller中能处理不同的exception:

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2020-10-18 22:46  圣金巫灵  阅读(284)  评论(0编辑  收藏  举报