【SpringMVC】拦还是不拦

【是什么】

      拦截是AOP的一种实现策略,类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。

【三个方法】

源码展示:

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.method.HandlerMethod;

public interface HandlerInterceptor {

	boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
	    throws Exception;

	void postHandle(
			HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
			throws Exception;

	void afterCompletion(
			HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception;

}

方法分析:

1.preHandle方法:

     预处理方法,该方法会在Controller的方法执行前会被调用,可以使用这个方法来中断或者继续执行链的处理,当返回true时,处理执行链会继续,当返回false时,则不会去执行Controller的方法。(应用:身份认证、身份授权)

2.postHandle方法:

      后处理方法,进入Handler方法之后,返回modelAndView之前执行。(应用:从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图)

3.afterCompletion方法:

      整个请求处理完毕方法,在请求过程完成之后执行。该方法可以用来清理资源。(应用:统一异常处理,统一日志处理,性能监控等)

【正常流程测试】

拦截器实现代码(HandlerInterceptor1 与HandlerInterceptor2打印内容略有不同其他相同)

package cn.itcast.ssm.controller.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * 测试拦截器1
 * 
 * @author happy
 *
 */
public class HandlerInterceptor1 implements HandlerInterceptor {

	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {

		System.out.println("===========HandlerInterceptor1...preHandle");

		// return false表示拦截,不向下执行
		// return true表示放行
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {

		System.out.println("===========HandlerInterceptor1...postHandle");

	}

	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {

		System.out.println("===========HandlerInterceptor1...afterCompletion");
	}

}

springmvc.xml(在环境搭建成功的基础上加上拦截器配置)

<!--拦截器 -->
<mvc:interceptors>
	<!--多个拦截器,顺序执行 -->
	<mvc:interceptor>
		<!-- /**表示所有url包括子url路径 -->
		<mvc:mapping path="/**" />
		<bean class="cn.itcast.ssm.controller.interceptor.HandlerInterceptor1"></bean>
	</mvc:interceptor>
	<mvc:interceptor>
		<mvc:mapping path="/**" />
		<bean class="cn.itcast.ssm.controller.interceptor.HandlerInterceptor2"></bean>
	</mvc:interceptor>
</mvc:interceptors>

测试Controller代码:

package cn.itcast.ssm.controller.interceptor;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class TestController {

	@RequestMapping("/test")
	public String test() throws Exception {
		System.out.println("===========TestController方法执行");
		return "test";
	}

}

JSP页面代码:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
	<%
		System.out.println("===========test.jsp");
	%>
</body>
</html>

测试网址:http://localhost:8080/springmvc_mybatis/test.action

控制台打印结果:


由此可见,当两个拦截器都放行时,preHandle方法按顺序执行,

postHandleafterCompletion按拦截器配置的逆向顺序执行。

【拦截测试:1放行2拦截】
      也就是说HandlerInterceptor1 的
preHandle方法为return true,HandlerInterceptor2preHandle方法为return false

运行结果为:


      由此可见,拦截器1放行,拦截器2 preHandle才会执行。拦截器2 preHandle不放行,拦截器2postHandleafterCompletion不会执行。

【拦截测试:1拦截2放行】

      也就是说HandlerInterceptor1的preHandle方法为return false,HandlerInterceptor2preHandle方法为return true

运行结果为:


由此可见,拦截器1 preHandle不放行,postHandleafterCompletion不会执行。拦截器1 preHandle不放行,则拦截器2不执行。

【实践--登陆认证】

需求:

      如果用户session存在则跳转到正确页面,如果用户session不存在,则跳转到登陆页面

登陆Controller实现:

package cn.itcast.ssm.controller;

import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LoginController {

	// 登陆
	@RequestMapping("/login")
	public String login(HttpSession session, String username, String password)
			throws Exception {

		// 调用service进行用户身份验证
		// ...

		// 在session中保存用户身份信息
		session.setAttribute("username", username);
		// 重定向到商品列表页面
		return "redirect:/items/queryItems.action";
	}

}

登陆拦截器实现:

package cn.itcast.ssm.controller.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * 登陆认证拦截器
 * 
 * @author happy
 *
 */
public class LoginInterceptor implements HandlerInterceptor {

	// 身份认证,如果认证通过表示当前用户没有登陆,需要此方法拦截不再向下执行
	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		System.out.println("===========LoginInterceptor...preHandle");
		// 获取请求的url
		String url = request.getRequestURI();
		// 判断url是否是公开 地址(实际使用时将公开 地址配置配置文件中)
		// 这里公开地址是登陆提交的地址
		if (url.indexOf("login.action") >= 0) {
			// 如果进行登陆提交,放行
			return true;
		}

		// 判断session
		HttpSession session = request.getSession();
		// 从session中取出用户身份信息
		String username = (String) session.getAttribute("username");

		if (username != null) {
			// 身份存在,放行
			return true;
		}

		// 执行这里表示用户身份需要认证,跳转登陆页面
		request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,
				response);

		// return false表示拦截,不向下执行
		// return true表示放行
		return false;
	}

	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {

		System.out.println("===========LoginInterceptor...postHandle");

	}

	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {

		System.out.println("===========LoginInterceptor...afterCompletion");
	}

}

Springmvc.xml文件配置:(添加登陆认证拦截器的配置,并且放在第一个拦截位置)

<!-- 登陆认证拦截器 -->
<mvc:interceptor>
	<mvc:mapping path="/**"/>
	<bean class="cn.itcast.ssm.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>

登陆页面jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>系统登陆</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/login.action" method="post">
用户账号:<input type="text" name="username" /><br/>
用户密码 :<input type="password" name="password" /><br/>
<input type="submit" value="登陆"/>
</form>
</body>

</html>

【interceptor和Filter】

      1.interceptor则基于java本身的反射机制,而Filter基于回调函数,我们需要实现的filter接口中doFilter方法就是回调函数。

      2.interceptor与servlet容器无关,而Filter是依赖于servlet容器的,即只能在servlet容器中执行,很显然没有servlet容器就无法来回调doFilter方法。

      3.Interceptor只能过滤请求,而Filter的过滤范围比Interceptor大,Filter除了过滤请求外通过通配符可以保护页面,图片,文件等等

     4.Interceptor可以通过在xml声明是guest请求还是user请求来辨别是否过滤,而Filter的过滤一般是在加载的时候在init方法声明。

     5.action的生命周期中,interceptor可以多次被调用,而Filter只能在容器初始化时被调用一次

过滤器的博客推荐:http://blog.csdn.net/u013036274/article/details/52592818

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值