在SpringMVC中的拦截器可以是运行在控制器(Controller)之前的组件,可以设置拦截器应用于哪些请求路径,当发生这些请求时,拦截器会自动执行,在执行过程中,可以对请求相关数据进行判断,选择阻止继续向后执行,或选择放行。
注意:拦截器是一个若干种请求都会经历的执行过程,但是,并不一定需要阻止继续运行,只要是若干种请求都需要做相同的事情,也许每种请求的处理过程都是选择放行,也可以使用拦截器。
首先,所有的拦截器类都必须实现HandlerInterceptor
接口,可以自定义LoginInterceptor
:
public class LoginInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("LoginInterceptor.preHandle()");
return false;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("LoginInterceptor.postHandle()");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("LoginInterceptor.afterCompletion()");
}
}
在拦截器的3个方法中,只有preHandle()
方法是运行在控制器(Controller)之前的,另2个方法是运行在控制器之后的,所以,只有preHandle()
具有真正意义的“拦截”功能,该方法的返回值是boolean
类型的,当返回true
时表示放行,返回false
时将阻止继续向后执行,即控制器并不会被执行:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("LoginInterceptor.preHandle()");
// 获取Session
HttpSession session = request.getSession();
// 检查Session中是否有登录信息
if (session.getAttribute("uid") == null) {
// 没有登录信息,重定向到登录页
response.sendRedirect("../user/login.do");
// 执行拦截
return false;
}
// 放行
return true;
}
注意:即使已经决定了重定向,还是需要return false;否则处理流程会继续向执行,控制器中的方法还是会被调用,达不到阻止运行的效果!
所有的拦截器都需要在Spring的配置文件中进行配置,在SpringMVC框架中,允许使用若干个拦截器,形成拦截器链,即某个请求可能需要经过多个拦截器,仅当每个拦截器都放行时,才会执行控制器中的方法!在配置文件中,配置的先后顺序决定了多个拦截器的执行顺序:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/main/index.do"/>
<bean class="cn.tedu.spring.LoginInterceptor">bean>
mvc:interceptor>
mvc:interceptors>
在配置每个拦截器时,允许使用若干个
节点以配置若干个拦截路径,例如:
<mvc:interceptor>
<mvc:mapping path="/main/index.do"/>
<mvc:mapping path="/user/password.do"/>
<mvc:mapping path="/user/info.do"/>
<mvc:mapping path="/user/handle_password.do"/>
<mvc:mapping path="/user/handle_info.do"/>
<bean class="cn.tedu.spring.LoginInterceptor">bean>
mvc:interceptor>
在配置路径,还可以使用*
作为通配符,例如:
在使用*
作为通配符时,需要注意,1个星号只能匹配1层路径,例如/main/*
可以匹配上/main/index.do
,也可以匹配/main/hello.do
,但是,不可以匹配上/main/a/index.do
!
如果一定要匹配若干层路径,必须使用2个星号,例如配置为/main/**
,可以匹配上/main/index.do
,也可以匹配/main/a/hello.do
,甚至可以匹配/main/a/b/c/d/hello.do
,即无视路径中后续的层级。
所以,可以配置为:
如果通配符匹配的路径过多,需要从中去除某些请求路径,还可以添加例外:
<mvc:interceptor>
<mvc:mapping path="/main/**"/>
<mvc:mapping path="/user/**"/>
<mvc:exclude-mapping path="/user/reg.do" />
<mvc:exclude-mapping path="/user/handle_reg.do" />
<mvc:exclude-mapping path="/user/login.do" />
<mvc:exclude-mapping path="/user/handle_login.do" />
<bean class="cn.tedu.spring.LoginInterceptor">bean>
mvc:interceptor>
也就是说,凡/user/
下的路径都会经过该拦截器,但是,/user/login.do
是不被处理的!添加到“例外”中的路径,在请求时,并不是拦截器直接放行,而是拦截器根本就不执行!
a
对应的就是110 0001
,但是,由于ASCII码都只占1个字节,只能128种不同的可能,所以,无法表示中文。拦截器与过滤器的区别:
拦截器(Interceptor)是SpringMVC中的组件,过滤器(Filter)是JavaEE中的组件。
拦截器是运行在DispatcherServlet
之后且在所有控制器(Controller)之前的组件,所以,仅当被DispatcherServlet
接收的请求才可能被拦截器处理,例如DispatcherServlet
配置的是*.do
,那拦截器就只能处理某些*.do
的请求,而例如*.html
或*.jpg
都不在拦截器可处理的范围之内!过滤器是运行在所有的Servlet之前的组件,甚至可以处理所有的请求,是根据它在web.xml中配置的节点的值来决定的。
拦截器的配置更加灵活,可以有若干个拦截路径(黑名单),也可以有若干个例外路径(白名单),而过滤器只能配置1个过滤路径,如果使用了通配符,例如配置为*.do
或/*
等,只能在过滤器类中编写代码添加例外。
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
在Java中,异常的体系结构:
Throwable
Error
OutOfMemoryError
Exception
SQLException
IOException
FileNotFoundException
RuntimeException
NullPointerException
ClassCastException
NumberFormatException
IndexOutOfBoundsException
ArrayIndexOutOfBoundsException
StringIndexOutOfBoundsException
在Exception
中,除了RuntimeException
及其子孙类异常,其它的异常都是必须通过语法进行处理的!处理方式可以是try...catch
进行捕获并处理,也可以是在方法的签名中添加throws
声明抛出。
其实,处理异常的本质应该是:给予用户某些提示,告之操作失败的原因,避免用户再次提交错误的数据,另外,也可能在处理过程中,对已经发生的错误尽可能的补救,例如关闭某些已经打开的流对象。
某一种异常在项目的多个请求处理过程中,都可能出现,在SpringMVC中,提供了统一处理异常的做法:将@ExceptionHandler
添加在自定义的用于处理异常的方法之前,该自定义方法应该:
使用public
权限;
返回值的设计原则与处理请求的方法的相同;
方法名称可以自由定义;
方法中必须添加异常类型的参数,另外还可以添加例如HttpServletRequest
等参数,但不可以添加其它参数。
例如:
@ExceptionHandler({IndexOutOfBoundsException.class, NullPointerException.class})
public String handleException(Throwable ex, HttpServletRequest request) {
String errorMessage = null;
if (ex instanceof NullPointerException) {
errorMessage = "错误:请提交用户名!";
} else if (ex instanceof IndexOutOfBoundsException) {
errorMessage = "错误:使用的索引超出了界限!";
}
request.setAttribute("msg", errorMessage);
return "error";
}
在@ExceptionHandler
注解中,可以配置需要处理的异常的种类,当配置后,仅当指定的异常出现时,才会调用匹配的方法进行处理,而其它异常是不予处理的!如果没有配置需要处理哪些异常,则任何异常出现都会进行处理!
在处理时,@ExceptionHandler
只能作用于当前控制器类!要让若干个类都能使用该异常处理,可以把这段代码抽取到超类,然后去继承它