SpringMVC(6)异常处理及拦截器
1、异常处理
1.1、异常处理的思路
系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的 dao、 service、 controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端控制器交由异常处理器进行异常处理,如下图 :
1.2、SpringMVC的异常处理
1.自定义异常类
public class SysException extends Exception {
private String message;
public SysException(String message) {
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
2.定义异常处理器
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SysExceptionResolver implements HandlerExceptionResolver {
/**
* 处理异常业务逻辑
* @param httpServletRequest
* @param httpServletResponse
* @param o
* @param e
* @return
*/
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
//获取异常对象
SysException ex = null;
if (e instanceof SysException){
ex = (SysException)e;
}else {
ex = new SysException("系统正在维护....");
}
//创建ModelAndvies对象
ModelAndView mv = new ModelAndView();
mv.addObject("error",ex.getMessage());
mv.setViewName("error");
return mv;
}
}
3.配置异常处理器对象
<!--配置异常处理器对象-->
<bean id="sysExceptionResolver" class="wf.exception.SysExceptionResolver"/>
4.测试异常处理的jsp
<a href="user/teseException">拦截器</a>
5.测试异常处理控制器
@RequestMapping("/teseException")
public String teseException() throws SysException {
System.out.println("teseException方法执行了");
try {
int a = 10/0;
} catch (Exception e) {
e.printStackTrace();
throw new SysException("查询用户错误");
}
return "success";
}
2、拦截器
2.1、拦截器概述
Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
用户可以自己定义一些拦截器来实现特定的功能。
谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但是也有区别,接下来我们就来说说他们的区别:
过滤器是 servlet 规范中的一部分, 任何 java web 工程都可以使用。
拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。
过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。
拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp, html,css,image 或者 js 是不会进行拦
截的。
它也是 AOP 思想的具体应用。
我们要想自定义拦截器, 要求必须实现: HandlerInterceptor 接口。
2.2、自定义拦截器
1.创建拦截器类
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
/**
* 预处理,controller方法执行前
* return true,放行执行下一个拦截器,若没有则执行controller
* false不放行请求失败
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器执行了....前111");
// request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return true;
}
/**
* 后处理方法,controller方法之后,success方法之前
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器执行了....后111");
// request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
}
/**
* success.jsp页面执行后,该方法执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("success.jsp页面执行后,该方法执行111");
}
}
2.在配置文件springmvc.xml中配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<!--配置具体拦截器-->
<mvc:interceptor>
<!--要拦截的具体方法-->
<mvc:mapping path="/user/*"/>
<!--不拦截的方法
<mvc:exclude-mapping path=""/>-->
<!--配置拦截器对象-->
<bean id="myInterceptor" class="wf.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
然后在访问controller时就会先经过拦截器在进行之后操作
2.3、拦截器的HandlerInterceptor接口中的方法
public interface HandlerInterceptor {
/**
* 如何调用:
* 按拦截器定义顺序调用
* 何时调用:
* 只要配置了都会调用
* 有什么用:
* 如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去
* 进行处理,则返回 true。
* 如果程序员决定不需要再调用其他的组件去处理请求,则返回 false。
*/
default boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler)
throws Exception {
return true;
}
/**
* 如何调用:
* 按拦截器定义逆序调用
* 何时调用:
* 在拦截器链内所有拦截器返成功调用
* 有什么用:
* 在业务处理器处理完请求后,但是 DispatcherServlet 向客户端返回响应前被调用,
* 在该方法中对用户请求 request 进行处理。
*/
default void postHandle(HttpServletRequest request, HttpServletResponse
response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
/**
* 如何调用:
* 按拦截器定义逆序调用
* 何时调用:
* 只有 preHandle 返回 true 才调用
* 有什么用:
* 在 DispatcherServlet 完全处理完请求后被调用,
* 可以在该方法中进行一些资源清理的操作。
*/
default void afterCompletion(HttpServletRequest request, HttpServletResponse
response, Object handler,
@Nullable Exception ex) throws Exception {
}
}
2.4、多个拦截器的执行顺序
多个拦截器是按照配置的顺序决定的。
多个拦截器的springmvc.xml配置
<!--配置拦截器-->
<mvc:interceptors>
<!--配置具体拦截器-->
<mvc:interceptor>
<!--要拦截的具体方法-->
<mvc:mapping path="/user/*"/>
<!--不拦截的方法
<mvc:exclude-mapping path=""/>-->
<!--配置拦截器对象-->
<bean id="myInterceptor1" class="wf.interceptor.MyInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<!--要拦截的具体方法-->
<mvc:mapping path="/user/*"/>
<!--不拦截的方法
<mvc:exclude-mapping path=""/>-->
<!--配置拦截器对象-->
<bean id="myInterceptor2" class="wf.interceptor.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
执行顺序
多个拦截器,如果其中一个拦截器拦截请求,那么之后就会逐级执行前一个拦截器的afterCompletion方法