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.3package 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;
}
}