1. 程式人生 > >spring mvc攔截器專案例項

spring mvc攔截器專案例項

處理器攔截器簡介:

1.1.1攔截器介面

package org.springframework.web.servlet;  
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;  
}   

preHandle:預處理回撥方法,實現處理器的預處理(如登入檢查),第三個引數為響應的處理器;

    返回值:true表示繼續流程(如呼叫下一個攔截器或處理器);

             false表示流程中斷(如登入檢查失敗),不會繼續呼叫其他的攔截器或處理器,此時我們需要通過response來產生響應;

postHandle:後處理回撥方法,實現處理器的後處理(但在渲染檢視之前),此時我們可以通過modelAndView(模型和檢視物件)對模型資料進行處理或對檢視進行處理,modelAndView也可能為null。

afterCompletion:整個請求處理完畢回撥方法,即在檢視渲染完畢時回撥,如效能監控中我們可以在此記錄結束時間並輸出消耗時間,還可以進行一些資源清理,類似於try-catch-finally中的finally,但僅呼叫處理器執行鏈中preHandle返回true的攔截器的afterCompletion

2.1.2、攔截器介面卡

有時候我們可能只需要實現三個回撥方法中的某一個,如果實現HandlerInterceptor介面的話,三個方法必須實現,不管你需不需要,此時spring提供了一個HandlerInterceptorAdapter介面卡(一種介面卡設計模式的實現),允許我們只實現需要的回撥方法。

package com.rmyy.web.Interceptors;

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

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

public class ParametersInterceptor implements HandlerInterceptor {

	@Override
	public void afterCompletion(HttpServletRequest arg0,
			HttpServletResponse arg1, Object arg2, Exception arg3)
			throws Exception {
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse arg1,
			Object arg2, ModelAndView arg3) throws Exception {
		request.setAttribute("parameterMap", request.getParameterMap());
	}

	@Override
	public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
			Object arg2) throws Exception {
		return true;
	}

}

2.1.3、執行流程圖

已下圖是正常流程

 

 已下是中斷流程

 

中斷流程中,比如是HandlerInterceptor2中斷的流程(preHandle返回false),此處僅呼叫它之前攔截器的preHandle返回true的afterCompletion方法。

2.1.4、攔截器的一個專案的例項:

1.WEB-INF目錄下新建一個dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
		http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

	<import resource="classpath:/applicationContext.xml" />

	<context:component-scan base-package="com.rmyy.web" />
	<context:annotation-config />
	<mvc:resources mapping="/s/**" location="/s/" />
	<mvc:resources mapping="/error/**" location="/error/" />
	<mvc:resources mapping="/help/**" location="/help/" />
	<mvc:resources mapping="/favicon.ico" location="/s/img/favicon.ico" />
	
	<mvc:resources mapping="/pdfcore/**" location="/pdfcore/" />
	
	<!-- <mvc:resources mapping="/img/**" location="/img/" /> -->
	<!-- <mvc:resources mapping="/m/content/img/**" location="/img/" /> -->
	<!-- <mvc:resources mapping="/a/img/**" location="/img/" /> -->

	<!-- <task:annotation-driven/> -->
	
	<bean
		class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
	<bean
		class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />

	<!-- Default ViewResolver -->
	<bean id="viewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass"
			value="org.springframework.web.servlet.view.JstlView" />
		<property name="prefix" value="/WEB-INF/views/" />
		<property name="suffix" value=".jsp" />
	</bean>
	

	<!-- 攔截器 -->
	<mvc:interceptors>
		<!-- 多個攔截器,順序執行 -->
		<mvc:interceptor>
			<mvc:mapping path="/m/**" />
			<bean class="com.rmyy.web.Interceptors.PermissionInterceptor"></bean>
		</mvc:interceptor>

		<!-- 會員中心攔截器 -->
		<mvc:interceptor>
			<mvc:mapping path="/u/**" />
			<bean class="com.rmyy.web.Interceptors.UserSecurityInterceptor">
				<property name="uncheckUrls"><!-- uncheckUrls配置的是不需攔截的頁面 -->
					<list>
						<value>/u/login</value>
						<value>/u/showLogin</value>
						<value>/u/showLoginMin</value>
						<value>/u/showRegStep1</value>
						<value>/u/showRegStep2</value>
						<value>/u/doRegist</value>
						<value>/u/existName</value>
						<value>/u/customer/validateLogin</value>
						<value>/u/product/list</value>
					</list>
				</property>
			</bean>
		</mvc:interceptor>
		<mvc:interceptor>
			<mvc:mapping path="/m/**"/>
			<bean class="com.rmyy.web.Interceptors.ParametersInterceptor"></bean>
		</mvc:interceptor>
	</mvc:interceptors>
	
</beans>

2.1.攔截未登入使用者:我們建立一個類名為UserSecurityInterceptor實現HandlerInterceptor介面用來攔截/m/路徑下未登入的頁面請求:

package com.rmyy.web.Interceptors;

import java.util.List;


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

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

import com.rmyy.web.model.Permission;
import com.rmyy.web.model.User;

public class PermissionInterceptor implements HandlerInterceptor{

	@Override
	public void afterCompletion(HttpServletRequest arg0,
			HttpServletResponse arg1, Object arg2, Exception arg3)
			throws Exception {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
			Object arg2, ModelAndView arg3) throws Exception {
		// TODO Auto-generated method stub
		
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
			Object arg2) throws Exception {
		//獲取 URL 相對於 Webapp 的路徑uri
		String uri = request.getServletPath();
		String pathInfo = request.getPathInfo();
		if (pathInfo != null && pathInfo.length() > 0) {
		    uri = uri + pathInfo;
		}  
		request.setAttribute("uri", uri);
		if(uri.indexOf("/m/login")==0 || uri.indexOf("/m/logout")==0 ){
			return true;
		}
		if(uri.indexOf("/m/home")==0){
			return true;
		}
		User user =(User) request.getSession().getAttribute("user");
		if(user == null){
			response.sendRedirect(request.getContextPath()+"/m/login");
		}
		List<Permission> list = (List<Permission>) request.getSession().getAttribute("perm");
		if(list != null){
			for (Permission perm : list) {
				if(uri.indexOf(perm.getUrl())==0){
					return true;
				}
			}
			//臨時加的
			if(uri.indexOf("/m/user/upPassword")==0){
				return true;
			}
		}
		
		return false;
	}

}

2.2會員中心攔截器:

package com.rmyy.web.Interceptors;

import java.net.URLEncoder;
import java.util.List;


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;

import com.rmyy.web.model.Customer;
import com.rmyy.web.util.StringUtil;

/**
 * @title 前臺使用者Session 安全攔截
 * @author xiegongmiao
 * @version 1.0 Jul 3, 2016 4:18:28 PM
 */
public class UserSecurityInterceptor implements HandlerInterceptor {

	private List<String> uncheckUrls; // 不需要被攔截的請求url

	public void setUncheckUrls(List<String> uncheckUrls) {
		this.uncheckUrls = uncheckUrls;
	}

	/**
	 * preHandle方法是進行處理器攔截用的,顧名思義,該方法將在Controller處理之前進行呼叫的
	 * SpringMVC中的Interceptor攔截器是鏈式的,可以同時存在
	 * 多個Interceptor,然後SpringMVC會根據宣告的前後順序一個接一個的執行
	 * 而且所有的Interceptor中的preHandle方法都執行
	 * Controller方法呼叫之前呼叫。SpringMVC的這種Interceptor鏈式結構也是可以進行中斷的
	 * ,這種中斷方式是令preHandle的返 回結果為false,當preHandle的返回結果為false的時候整個請求就結束了
	 */
	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		HttpSession session = request.getSession();
		/*
		 * if(session == null){ response.sendRedirect(request.getContextPath() +
		 * "/u/login"); return false; }
		 */
		//獲取請求的url
		String uri = request.getServletPath();
		String pathInfo = request.getPathInfo();
		String queryString = request.getQueryString();
		if (pathInfo != null && pathInfo.length() > 0) {
			uri = uri + pathInfo;
		}
		String callBackUrl = uri+(!StringUtil.isEmpty(queryString) ? "?" + queryString : "");
		String pid = "";
		String path = request.getContextPath() + "/u/showLogin?callBackUrl="+URLEncoder.encode(URLEncoder.encode(callBackUrl, "utf-8"),"utf-8");
		if(uri.indexOf("/u/order/buy") != -1){ //點選產品訂閱時,如果沒有登入時,記錄請求的產品ID到Cookie中
			  //獲取產品ID
			pid = request.getParameter("pid");
			//設定點選的訂閱產品編號
			request.getSession().setAttribute("productId", pid);
		}

		if (validateRequestUrl(uri)) { // 判斷請求URL是否被攔截
			return true;
		}

		request.setAttribute("user_uri", uri);

		// 從session沒有獲取到會員登入資訊
		Customer customer = (Customer) session
				.getAttribute("loginCustomer");
		if (customer == null) {
			response.sendRedirect(path);
			return false;
		}
		return true;
	}

	/**
	 * 這個方法只會在當前這個Interceptor的preHandle方法返回值為true的時候才會執行,postHandle是進行處理器攔截用的.
	 * 它的執行時間是在處理器進行處理之
	 * 後,也就是在Controller的方法呼叫之後執行,但是它會在DispatcherServlet進行檢視的渲染之前執行
	 * ,也就是說在這個方法中你可以對ModelAndView進行修改。
	 * 這個方法的鏈式結構跟正常訪問的方向是相反的,也就是說先宣告的Interceptor攔截器該方法反而會後呼叫
	 * ,這跟Struts2裡面的攔截器的執行過程有點像。
	 * 只是Struts2裡面的intercept方法中要手動的呼叫ActionInvocation的invoke方法
	 * ,Struts2中呼叫ActionInvocation的invoke方法就是呼叫下一個Interceptor
	 * 或者是呼叫action,然後要在Interceptor之前呼叫的內容都寫在呼叫invoke之前
	 * ,要在Interceptor之後呼叫的內容都寫在呼叫invoke方法之後。
	 */
	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
	}

	/**
	 * 該方法也是需要當前對應的Interceptor的preHandle方法的返回結果為true時才會執行,該方法將在整個請求完成之後,
	 * 也就是DispatcherServlet渲染了檢視執行,
	 * 這個方法的主要作用是用於清理資源的,當然這個方法也只能在當前這個Interceptor的preHandle方法的返回結果為true時才會執行。
	 */
	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
	}

	/**
	 * 驗證請求URL 是否需要攔截
	 * 
	 * @param url
	 * @return true 不攔截   false 攔截
	 */
	private boolean validateRequestUrl(String url) {
		if (uncheckUrls == null || uncheckUrls.isEmpty()) {
			return false;
		}

		for (int i = 0; i < uncheckUrls.size(); i++) {
			String path = uncheckUrls.get(i);
			if (url.indexOf(path) != -1) {
				return true;
			}
		}
		return false;
	}
}
2.3
package com.rmyy.web.Interceptors;

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

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

public class ParametersInterceptor implements HandlerInterceptor {

	@Override
	public void afterCompletion(HttpServletRequest arg0,
			HttpServletResponse arg1, Object arg2, Exception arg3)
			throws Exception {
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse arg1,
			Object arg2, ModelAndView arg3) throws Exception {
		request.setAttribute("parameterMap", request.getParameterMap());
	}

	@Override
	public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
			Object arg2) throws Exception {
		return true;
	}

}