要学习拦截器,我们先学习两个东西,HandlerInterceptor 和 WebMvcConfigurer

HandleInterceptor: 在Spring中定义一个Interceptor是非常简单的,主要有两种方式:

第一种:实现HandlerInterceptor 接口,或者是继承实现了HandlerInterceptor 接口的类,例如HandlerInterceptorAdapter;

第二种:实现Spring的WebRequestInterceptor接口,或者继承实现类:WebMvcConfigurerAdapter。

HandlerInterceptorAdapter这个适配器,它有三个方法:

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {    
        return true;    
}    
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception {    
}    
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {    
}
  1. preHandle() 该方法在处理请求之前进行调用,就是在执行Controller的任务之前。如果返回true就继续往下执行,返回false就放弃执行。可以进行编码、安全控制,用户是否登录等处理;
  2. postHandle() 该方法将在请求处理之后,DispatcherServlet进行视图返回渲染之前进行调用,可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作;
  3. afterCompletion该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行,用于进行资源清理;可以根据ex是否为null判断是否发生了异常,进行日志记录;
    如果基于XML配置使用Spring MVC,可以利用SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping进行Url映射(相当于struts的path映射)和拦截请求(注入interceptors)。如果基于注解使用Spring MVC,可以使用DefaultAnnotationHandlerMapping注入interceptors。注意无论基于XML还是基于注解,HandlerMapping Bean都是需要在XML中配置的。

xml文件配置拦截器:

<!--配置拦截器, 多个拦截器,顺序执行 -->
<mvc:interceptors>
		<!-- 进入和退出  web会话的时候, 记录相关请求信息-->
		<mvc:interceptor>
		    <!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller --> 
			<mvc:mapping path="/**" />
			<beans:bean class="com.daling.hawk.common.platform.aop.LogInterceptor" />
		</mvc:interceptor>

		<!-- 用户登录状态检查, 定义不需要登陆检查的URL-->
		 <mvc:interceptor>
			<mvc:mapping path="/**" />
			<beans:bean class="com.daling.hawk.common.platform.aop.LoginValidateInterceptor">
				<beans:property name="uncheckedUrlPrefix">
					<beans:list>
						<beans:value>inner/</beans:value>
						<beans:value>openapi/</beans:value>
						<beans:value>outer/</beans:value>
					</beans:list>
				</beans:property>
				<beans:property name="uncheckedUrls">
					<beans:list>
						<beans:value>main/login.do</beans:value>
					</beans:list>
				</beans:property>
			</beans:bean>
		</mvc:interceptor>

		<mvc:interceptor>
			<!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller -->  
			<mvc:mapping path="/**" />
			<beans:bean class="com.daling.hawk.common.platform.aop.JdbcUtilsInterceptor" />
		</mvc:interceptor>

		<mvc:interceptor>
			<!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller -->  
			<mvc:mapping path="/**" />
			<beans:ref bean="localeChangeInterceptor" />
		</mvc:interceptor>
	</mvc:interceptors>

LoginValidateInterceptor 负责检查用户是否登录,如果未登录,则跳到登录页面

public class LoginValidateInterceptor extends HandlerInterceptorAdapter {
	static Logger log = LoggerFactory.getLogger(LoginValidateInterceptor.class);
	// 不需要检查的URL前缀
	private List<String> uncheckedUrlPrefix;
	// 不需要检查的URL
	private List<String> uncheckedUrls;
	// get/set方法省略
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object target) throws Exception {
		String realUri = ******;//需要检查的请求路径
		//获取不包含应用名字的URI的路径, 并去掉最前面的"/"
	 	//如路径为http://localhost:8080/appName/user/list.do, 得到的值为"user/list.do",其中       appNames为应用的名字
		// 如果配置了不需要检查的url前缀,而且是以该前缀为开头,则通过
		if (uncheckedUrlPrefix != null && !uncheckedUrlPrefix.isEmpty()) {
			for (String s : uncheckedUrlPrefix) {
				if (realUri.startsWith(s.trim())) {
					log.info("REQ_URL:[{}] matchs UNCHK_URL:[{}]", realUri, s);
					return true;
				}
			}
		}

		if (uncheckedUrls != null && !uncheckedUrls.isEmpty() && uncheckedUrls.contains(realUri)) {
			// 不需要检查
			log.info("REQ_URL:[{}] is UNCHK_URL", realUri);
			return true;
		}
		log.info("start try fetch user info...");
		DLoginUser dLoginUser = Users.getUser(request);
		if (dLoginUser == null || !dLoginUser.isLogined()) {
			// 未登录,转向登录页面!
			log.info("User Not Logined...");
			response.setContentType("application/json;charset=UTF-8");
			response.setCharacterEncoding("UTF-8");
			response.setHeader("relogin", "t");
			return false;
		}
		return true;
	}

}

WebMvcConfigurerAdapter:对Spring进行配置

@Configuration
public class WebSecurityConfig extends WebMvcConfigurerAdapter {
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        /*调用我们创建的SessionInterceptor。
        * addPathPatterns("/api/**)的意思是这个链接下的都要进入到SessionInterceptor里面去执行
        * excludePathPatterns("/login")的意思是login的url可以不用进入到SessionInterceptor中,直接
        * 放过执行。
        * */
        SessionInterceptor sessionInterceptor=new SessionInterceptor();
        registry.addInterceptor(sessionInterceptor).addPathPatterns("/api/**")
                .excludePathPatterns("/login","/verify");
         /* 注意:如果像下面代码那样写是不可以的。这样等于是创建了多个Interceptor。而不是只有一个Interceptor 
        	* /       
//        registry.addInterceptor(sessionInterceptor).excludePathPatterns("/login");
//        registry.addInterceptor(sessionInterceptor).excludePathPatterns("/verify");
    }
}