异常处理
异常分类:
异常类型 | 异常处理 |
---|---|
预期异常 | 通过捕获异常从而获取异常信息 |
运行时异常 | 通过规范代码开发、测试通过手段减少运行时异常的发生 |
异常处理目的:
当用户使用程序过程中报错,我们希望能够跳转到一个异常处理页面用来对用户进行提示,而不是网页挂掉。我们可以通过异常处理实现这种效果,比如SpringMVC提供的异常处理机制。
异常处理思路:
系统的 dao、 service、 controller 出现都通过 throws Exception 向上抛出,最终由 Springmvc 前端控制器DispatcherServlet找异常处理器进行异常处理,如图所示:
图片来源于黑马视频
异常处理步骤
1,编写自定义异常类:
自定义异常类代码省略,controller层代码示例如下:
@RequestMapping("/testException")
public String testException() throws SysException {
try {
// 模拟异常
int a = 10/0;
} catch (Exception e) {
// 打印异常信息
e.printStackTrace();
// 向上抛出自定义异常信息
throw new SysException("查询出现错误了...");
}
return "success";
}
2,编写异常处理器:
异常处理器需要实现HandlerExceptionResolver接口;
代码示例:
/**
* 处理异常业务逻辑
* @param request
* @param response
* @param handler
* @param ex
* @return
*/
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
// 获取到异常对象
SysException e = null;
//如果抛出的是系统自定义异常则直接转换
if(ex instanceof SysException){
e = (SysException)ex;
}else{
//如果抛出的不是系统自定义异常则重新构造一个系统错误异常
e = new SysException("系统正在维护....");
}
// 创建ModelAndView对象
ModelAndView mv = new ModelAndView();
//获取异常的提示信息内容
mv.addObject("errorMsg",e.getMessage());
//跳转到error.jsp
mv.setViewName("error");
return mv;
}
3,配置异常处理器:
springmvc.xml中添加自定义异常处理器配置:
<!--配置异常处理器-->
<bean id="sysExceptionResolver" class="com.yp.exception.SysExceptionResolver"></bean>
拦截器
拦截器概述
Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。可以定义拦截器链,拦截器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链中的拦截器会按着定义的顺序执行;
过滤器和拦截器的区别:
过滤器 | 拦截器 |
---|---|
servlet 规范中的一部分,任何框架都可以使用 | SpringMVC框架独有 |
在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截 | 只会对控制器中的方法进行拦截 |
是AOP思想的一种实现方式 | |
自定义拦截器,需要实现HandlerInterceptor接口 |
HandlerInterceptor接口
HandlerInterceptor接口下有三个方法,分别是:preHandle(),postHandle(),afterCompletion();
方法名 | 调用顺序 | 调用方式 | 作用 | 调用时间 |
---|---|---|---|---|
预处理 preHandle() | 按拦截器定义顺序调用 | 只要配置了都会调用 | 1,可以使用request或者response跳转到指定的页面;2,return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法;3,return false不放行,不会执行controller中的方法; | controller方法执行前拦截的方法 |
后处理 postHandle() | 按拦截器定义逆序调用 | 在拦截器链内所有拦截器都返回true才调用 | 1,可以使用request或者response跳转到指定的页面;2,如果指定了跳转的页面,那么controller方法跳转的页面将不会显示; | controller方法执行后执行的方法,在JSP视图执行前 |
afterCompletion() | 按拦截器定义逆序调用 | 只有 对应拦截器的preHandle()方法 返回true才调用 | 1. request或者response不能再跳转页面了; 2,可以在该方法中进行一些资源清理的操作 | 在JSP视图执行后执行 |
拦截器演示示例
1,编写JSP视图和controller代码:
<!--点击事件jsp页面-->
<a href="user/testInterceptor" >拦截器演示</a>
<!--controller层-->
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testInterceptor")
public String testInterceptor() {
System.out.println("testInterceptor执行了......");
return "success";
}
}
<!--success.jsp页面-->
<h3>拦截器处理成功</h3>
<% System.out.println("success.jsp执行了..."); %>
2,自定义拦截器:
<!--自定义拦截器MyInterceptor-->
public class MyInterceptor implements HandlerInterceptor{
/**
* 预处理,controller方法执行前
* return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
* return false不放行
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("controller方法执行前,MyInterceptor执行了......");
return true;
/*
当不想放行,希望进入拦截器后直接跳转到某个提示页面
request.getRequestDispatcher("/WEB-INF/pages/message.jsp").forward(request,response);
return false;
*/
}
/**
* 后处理方法,controller方法执行后,success.jsp执行之前
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("controller方法执行后,success.jsp执行之前,MyInterceptor执行了......");
}
/**
* success.jsp页面执行后,该方法会执行
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("success.jsp执行之后,MyInterceptor执行了......");
}
}
<!--第二个自定义拦截器MyInterceptor2-->
......
3,拦截器配置:
springmvc.xml中添加拦截器配置:
<!--配置拦截器-->
<mvc:interceptors>
<!--配置拦截器-->
<mvc:interceptor>
<!--要拦截的具体的方法-->
<mvc:mapping path="/user/*"></mvc:mapping>
<!--不要拦截的方法
<mvc:exclude-mapping path=""></mvc:mapping>
-->
<!--配置拦截器对象-->
<bean class="com.yp.interceptor.MyInterceptor" ></bean>
</mvc:interceptor>
<!--配置第二个拦截器-->
<mvc:interceptor>
<mvc:mapping path="/**"></mvc:mapping>
<!--
<mvc:exclude-mapping path=""></mvc:mapping>
-->
<bean class="com.yp.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
注意点: <mvc:mapping path=""></mvc:mapping>和<mvc:exclude-mapping path=""></mvc:mapping>不要同时配置。
4,控制台运行结果