springMVC拦截器的学习

 

1、对springMVC拦截器的学习

(1)在实现上是基于Java的反射机制,是面向切面编程(AOP)的一种运用

(2)springMVC拦截器只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。

(3)springMVC拦截器类似于Servlet开发中的过滤器Filter,用于对处理器Handler(就是Controller)进行预处理和后处理。

2、springMVC拦截器的应用场景

(1)日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。

(2)权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;

(3)性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);

(4)通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。

(5)OpenSessionInView:如hibernate,在进入处理器打开Session,在完成后关闭Session。

3、springMVC拦截器应用实例

要求:登录检测,即当访问系统内容时,若没有登录则返回登录页

(1)搭建好ssm框架

(2)现有登录页面和列表页面

(3)如何设置拦截器,实现只有用户登录后才能访问到list.html

a.在src/main/java目录下创建interceptor包,再创建LoginInterceptor类:

注释中有对springMVC拦截器如何拦截用户请求,并进行相应处理的解释

package intercept;

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

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

/**
 * SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的。
 * HandlerInterceptor 接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。
 * HandlerInterceptorAdapter是实现了HandlerInterceptor 接口的抽象类。
 */
public class LoginIntercept extends HandlerInterceptorAdapter {

	/**
	 * preHandle方法
	 * 1、preHandle方法将在处理用户请求之前进行调用
	 * 2、在一个请求中可以同时存在多个Interceptor ,每个Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法。
	 * 3、由于2的特性,故可以在preHandle方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。
	 * 4、preHandle方法的返回值是Boolean类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;
	 * 当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		
		System.out.println("preHandle在处理请求之前被执行了");
	//return super.preHandle(request, response, handler);
        return false;//改成false才能实现拦截请求
	}
	
	/**
	 * postHandle方法
	 * 1、 postHandle方法,只能是在当前所属的Interceptor 的preHandle 方法的返回值为true 时才能被调用。
	 * 2、postHandle 方法,顾名思义就是在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用。
	 * 3、可以在postHandle方法中对Controller 处理之后的ModelAndView 对象进行操作。
	 * 4、postHandle 方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor 的postHandle 方法反而会后执行。
	 */
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		
		System.out.println("postHandle是在Controller 方法调用之后,在DispatcherServlet 进行视图返回渲染之前被执行");
		super.postHandle(request, response, handler, modelAndView);
	}

	/**
	 * afterCompletion方法
	 * 1、afterCompletion方法也是需要当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。
	 * 2、afterCompletion方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。
	 * 3、afterCompletion方法的主要作用是用于进行资源清理工作的。
	 */
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		
		System.out.println("afterCompletion在请求结束后被执行");
		super.afterCompletion(request, response, handler, ex);
	}
	
}

b.在spring-mvc.xml中配置拦截器组,并把定义的拦截器类加到拦截体系中

拦截器组:<mvc:interceptors></mvc:interceptors>;注意在spring-mvc.xml中加上支持MVC的schema

<?xml version="1.0" encoding="UTF-8"?>
<beans 
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc"

    xsi:schemaLocation="
  					http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
    				http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans.xsd
         	      	http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
         	        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
         	        http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
                       " >
    <!-- 自动扫描并实例化controller层下的类 -->
	<context:component-scan base-package="controller"></context:component-scan>
       
    <!-- springMVC会自动将后台传输给前端的数据转化成JSON,配置如下;   注意:要引入对应的jar包 -->	
    <!--避免IE执行AJAX时,返回JSON出现下载文件 -->   
    <bean id="mappingJacksonHttpMessageConverter"  
        class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">  
        <property name="supportedMediaTypes">  
            <list>  
                <value>text/html;charset=UTF-8</value>  
            </list>  
        </property>  
    </bean>  
    <!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 -->  
    <bean  
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
        <property name="messageConverters">  
            <list>  
                <ref bean="mappingJacksonHttpMessageConverter" /> <!-- JSON转换器 -->  
            </list>  
        </property>  
    </bean>  
    
    
    <mvc:interceptors>
		<!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->
		<!-- <bean class="interceptor.LoginInterceptor"/> -->
		
		<mvc:interceptor>
			<!-- 拦截特定的请求 -->
			<mvc:mapping path="/user/**.do"/>
			
			<!-- 不拦截某些请求 -->
			<mvc:exclude-mapping path="/user/login.do"/>
			
			<!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->
			<bean class="interceptor.LoginInterceptor"/>
		</mvc:interceptor>
	</mvc:interceptors>
    
</beans>

c.UserController.java

package controller;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import model.User;
import service.UserService;

@Controller
@RequestMapping("/user")
public class UserController {
	@Autowired
	private UserService userService;
	
	@RequestMapping("/list")
	@ResponseBody  
	public Map<String,Object> list(Integer page,Integer rows) {
		return userService.findUser(page,rows);
	}
	
	
	@RequestMapping("/save")
	@ResponseBody  
	public Map<String,Object> save(User user) {
		int res =  userService.saveUser(user);
		Map<String,Object> map = new HashMap<String,Object>();
		if(res == 1) {
			map.put("code",200);
		}else{
			map.put("code", 500);
		}
		return map;
	}
	
	@RequestMapping("/del")
	@ResponseBody  
	public Map<String,Object> del(Integer id) {
		int res = userService.delUserById(id);
		Map<String,Object> map = new HashMap<String,Object>();
		if(res == 1) {
			map.put("code",200);
		}else{
			map.put("code", 500);
		}
		return map;
		
	}
	
	@RequestMapping("/update")
	@ResponseBody  
	public Map<String,Object> update(User user) {
		int res = userService.updateUser(user);
		Map<String,Object> map = new HashMap<String,Object>();
		if(res == 1) {
			map.put("code",200);
		}else{
			map.put("code", 500);
		}
		return map;
	}
	
	@RequestMapping("/login")
	public String login(User user,HttpSession session) {
		System.out.println("login  controller被执行了");
		user = userService.findUser(user);
		if(user!= null) {
		
			return "redirect:/list.html";
		}
		return "redirect:/login.html";
	}
	
}

d.实现拦截的过程(1)

实现效果1:登录成功,显示list.html页面但是没有列表数据

1、login.html点击提交

2、user/login.do(不是要拦截的对象)

3、密码正确---重定向(redirect)到list.html     

3'、密码错误---重定向(redirect)到login.html 

4、user/list.do(是拦截对象,又preHandle方法返回值是false,所以不会返回用户请求的数据)

5、显示list.html页面,但是列表没有数据

实现效果2:没有登录,直接访问list.html页面不会显示数据

1、user/list.do(是拦截对象,又preHandle方法返回值是false,所以不会返回用户请求的数据)

2、显示list.html页面,但是列表没有数据

e.实现拦截过程(2)

实现效果1:登录成功,则preHandle方法返回true,list.html页面会显示列表数据

实现效果2:登录失败,则重定向回login.html页面

实现效果3:没有登录,则直接访问list.html页面会重定向到login.html页面

需要修改两处代码:

UserController.java中:

@RequestMapping("/login")
	public String login(User user,HttpSession session) {
		System.out.println("login  controller被执行了");
		user = userService.findUser(user);
		if(user!= null) {
			session.setAttribute("CURR_USER", user);//添加一个记录当前登录成功的用户的session
			return "redirect:/list.html";
		}
		return "redirect:/login.html";
	}

LoginInterceptor.java中:

@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		
		System.out.println("preHandle在处理请求之前被执行了");
		Object user = request.getSession().getAttribute("CURR_USER");
		if(user!=null){
			return true;
		}else{
			response.sendRedirect("/login.html");
		}
		return false;
	}

(4)总结:对只有登录过后,才能显示list.html页面及数据

1、登录成功,重定向到list.html页面

(1)点击提交,跳转到user/login.do请求,不在拦截器组中,不被拦截。

(2)判断账号密码是否正确,正确则设置session的属性CURR_USER保存当前用户信息,并重定向到list.html页面

(3)进入list.html页面(直接访问list.html,登录成功跳转到list.html),要加载列表数据,会发出请求user/list.do,在拦截器组中,根据session的CURR_USER属性值是否为空,preHandle方法的返回值不同。CURR_USER属性值不为空,则返回true,事实上就没有拦截user/list.do请求,就能请求到数据,list.html页面就能显示数据。CURR_USER属性值为空,则重定向到login.html,并且返回false,拦截user/list.do请求,不能请求到数据。

2、登录失败,重定向回login.html页面;

3、没有登录,直接访问list.html也会重定向到login.html;但是拦截器不会拦截静态资源list.html,因此并不会重定向到login.html,还是会显示list.html,只是没有数据

 

 

猜你喜欢

转载自blog.csdn.net/Carl_changxin/article/details/81909324