Spring —— 拦截器和异常处理
一、前言
本文需要的Maven坐标如下:主要是Spring框架和MVC框架,还有JSP需要的坐标。
<dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.1.9.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.9.RELEASE</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>javax.servlet.jsp-api</artifactId><version>2.3.3</version><scope>provided</scope></dependency><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><dependency><groupId>taglibs</groupId><artifactId>standard</artifactId><version>1.1.2</version></dependency>
SpringMVC的配置如下:
<!--mvc组件扫描--><context:component-scan base-package="com.yds.controller"/><!-- 配置内部资源视图解析器(自动指定前后缀)--><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/"/><property name="suffix" value=".jsp"/></bean><!-- mvc的注解驱动--><mvc:annotation-driven/><!-- 静态资源权限开放--><mvc:default-servlet-handler/>
记得配置前端控制器:
<!-- 配置SpringMVC的前端控制器--><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-mvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>DispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
二、拦截器
1.准备工作
与JavaWeb中的拦截器相似,主要功能是在目标方法放行前对其进行处理,首先我们需要创建一个目标方法:
@Controller
public class TargetController {@RequestMapping("/target")public ModelAndView show() {System.out.println("目标资源执行...");ModelAndView modelAndView = new ModelAndView();modelAndView.addObject("name","yds");modelAndView.setViewName("index");return modelAndView;}
}
访问“/target”资源后将执行show方法,并设置模型,便于在JSP文件中显示并跳转:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
</head>
<body>
<h2>Hello ${name}!!!</h2>
</body>
</html>
我们访问资源,不出意外的,效果如下:
同时控制台会有如下显示:
2.拦截器
这里我们开始配置拦截器:
<mvc:interceptor><!--对哪些资源执行拦截操作--><mvc:mapping path="/**"/><bean class="com.yds.interceptor.MyInterceptor"/></mvc:interceptor>
我们创建一个拦截器类,注意,这个类需要实现HandlerInterceptor接口:
这个接口有三个方法:分别是预处理、后处理、返回处理。
public class MyInterceptor implements HandlerInterceptor {//在目标方法执行之前执行@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle...");String parameter = request.getParameter("param");if(parameter.equals("yes")){return true;}else {request.getRequestDispatcher("/error.jsp").forward(request,response);return false;//返回true表示放行,false表示不放行}}//在目标方法执行之后,视图对象返回之前执行@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {modelAndView.addObject("name","xzt");System.out.println("postHandle...");}//整个流程都执行完毕后执行@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion...");}}
这里我们只有将请求参数设置为yes时,预处理时才会放行,才能够进行后面的操作,否则将跳转到error.jsp报错。
error.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %><html>
<head><title>Title</title>
</head>
<body>
<h1>error</h1>
</body>
</html>
我们执行程序:
可以看到拦截器成功拦截,并且在后处理阶段将Modle中的数据更改了,同时控制台显示出了这些处理的顺序。
3.拦截器链
和Javaweb中相似,拦截器链会按照一定的顺序对目标方法进行拦截。
我们这里再次创建一个拦截器类:
public class MyInterceptor2 implements HandlerInterceptor {//在目标方法执行之前执行@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle22222..");return true;}//在目标方法执行之后,视图对象返回之前执行@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle22222...");}//整个流程都执行完毕后执行@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion22222...");}
}
同时配置拦截器:
<!-- 配置拦截器--><mvc:interceptors><mvc:interceptor><!--对哪些资源执行拦截操作--><mvc:mapping path="/**"/><bean class="com.yds.interceptor.MyInterceptor"/></mvc:interceptor><mvc:interceptor><!--对哪些资源执行拦截操作--><mvc:mapping path="/**"/><bean class="com.yds.interceptor.MyInterceptor2"/></mvc:interceptor></mvc:interceptors>
控制台的结果如下:
三、异常处理
异常处理可以有两种手段:1.使用Spring的简单映射异常处理器 2.自定义映射异常处理器。
1.简单映射异常处理器
首先来看第一种:
我们这里采用注解配置Spring(这样就并不需要再配置applicationContext了)
先编写Service层:
public interface DemoService {
}
@Service("demoService")
public class DemoServiceImp implements DemoService{public void show1(){System.out.println("抛出类型转化异常...");Object str ="zhangsan";Integer num = (Integer)str;}public void show5() throws MyException {System.out.println("自定义异常...");throw new MyException();}
}
然后创建一个Controller调用Service层的方法:
@Controller
public class DemoController {@Autowired@Qualifier("demoService")private DemoServiceImp demoService;@RequestMapping("/show")public String show() throws MyException {System.out.println("show running...");demoService.show1();return "index";}}
我们这里主要尝试两个异常,一个是Java自带的异常,一个是我们自定义的异常,首先先关注Java自带的异常(show1):这里我们会抛出一个类型转换异常,我们配置简单映射异常处理器:
<!-- 配置简单映射异常处理器--><bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"><property name="defaultErrorView" value="error"/> <!--默认错误视图--><property name="exceptionMappings"><map><entry key="java.lang.ClassCastException" value="error1"/><entry key="com.yds.exception.MyException" value="error2"/></map></property></bean>
这样只要抛出对应的异常,我们就会跳转到对应配置的JSP文件(这里是error1)。
自己写的各种JSP文件(error)如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %><html>
<head><title>Title</title>
</head>
<body>
<h1>common error</h1>
<h1>${info}</h1>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %><html>
<head><title>Title</title>
</head>
<body>
<h1>类型转化异常</h1>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %><html>
<head><title>Title</title>
</head>
<body>
<h1>自定义异常</h1>
</body>
</html>
自定义异常如下:
public class MyException extends Exception {}
同理,如果调用show5方法,就会跳转到error2:
2.自定义映射异常处理器
使用自定义的映射异常处理器,首先创建一个类:
public class MyExceptionResolver implements HandlerExceptionResolver {/*参数Exception:异常对象返回值ModelAndView,跳转的视图信息*/@Overridepublic ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {ModelAndView modelAndView = new ModelAndView();if (e instanceof MyException) {modelAndView.addObject("info", "自定义异常");} else if (e instanceof ClassCastException) {modelAndView.addObject("info", "类型转换异常");}modelAndView.setViewName("error");return modelAndView;}
}
往Modle中存入数据,然后显示在error中的el表达式中,在这之前,不要忘了将处理器配置到Spring中:
<bean class="com.yds.resolver.MyExceptionResolver"/>
调用show5和show1,它们的效果分别是: