1. 程式人生 > >Spring--攔截器,字元編碼過濾器

Spring--攔截器,字元編碼過濾器

1. SpringMVC中的Interceptor

1.1. 練習目標

在主頁顯示的“使用者名稱”位置新增超連結,點選後進入“個人中心”。

通過/user/info.do路徑,可以顯示“個人資訊”頁面,該頁面需要登入後才允許訪問。

1.2. 分析問題

一個專案中,可能絕大部分的功能都是需要登入後才允許使用的,但是,在這些功能的處理中,可能都需要執行:

// 判斷Session中是否有username
if (session.getAttribute("username") == null) {
    // 沒有,則意味著沒有登入,則重定向到登入頁
    return "redirect:login.do";
}

而大量的複製並貼上以上程式碼的做法顯然是不可取的!

1.3. 解決方案

攔截器(Interceptor)是SpringMVC中的元件,它是執行在DispatcherServlet之後、每個Controller之前的元件,並且,執行時,可以選擇攔截放行,則會導致某些請求可以被處理或不被處理!然後,攔截器還可以執行在每個Controller處理完請求之後。

基於攔截器這樣的特點,可以在專案中新增“登入攔截器”,使得要求登入的請求都先經過“登入攔截器”進行判斷,在“登入攔截器”中將判斷Session是否有效,如果有效,則放行,如果沒有有效的Session,則直接攔截,並重定向到登入頁。

1.4. 使用方式

1.4.1. 建立攔截器

所有的自定義攔截器,都必須實現HandlerInterceptor介面,所以,在專案中建立cn.huang.spring.interceptor.LoginInterceptor,實現HandlerInterceptor

public class LoginInterceptor 
    implements HandlerInterceptor {

    public boolean preHandle(
            HttpServletRequest request, 
            HttpServletResponse response, 
            Object handler)
            throws Exception {
        System.out.println("LoginInterceptor.preHandle()");
        return false;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("LoginInterceptor.postHandle()");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("LoginInterceptor.afterCompletion()");
    }

}

1.4.2. 配置攔截器

springmvc.xml中新增攔截器的配置:

<!-- 配置攔截器鏈 -->
<mvc:interceptors>
    <!-- 配置第1個攔截器 -->
    <mvc:interceptor>
        <!-- 1. 攔截的路徑 -->
        <mvc:mapping path="/user/info.do" />
        <mvc:mapping path="/main/index.do" />
        <!-- 2. 指定攔截器類 -->
        <bean class="cn.huang.spring.interceptor.LoginInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>

1.4.3. 執行效果

當嘗試訪問以上攔截的路徑時,可以看到攔截器的preHandle()方法被執行,且介面上顯示一片空白,而沒有被攔截器路徑可以正常訪問,攔截器中的任何方法都沒有執行。

1.4.4. 完善登入攔截

在控制器中,成功登入時,會在Session中放入使用者名稱,且存入時使用的名稱是username,所以,判斷是否登入,就是檢查Session是否有名為username的值,如果值是存在的,即已經登入,如果值不存在,則沒有登入,所以,在攔截器的preHandle()方法中:

public boolean preHandle(
        HttpServletRequest request, 
        HttpServletResponse response, 
        Object handler)
        throws Exception {
    System.out.println("LoginInterceptor.preHandle()");
    // 獲取Session
    HttpSession session
        = request.getSession();
    // 判斷session中是否有登入資訊
    if (session.getAttribute("username") == null) {
        // 沒有登入資訊,則:重定向到登入頁
        response.sendRedirect("../user/login.do");
        // 執行攔截
        return false;
    } else {
        // 有登入資訊,則:允許正常訪問,直接放行
        return true;
    }
}

1.4.5. 攔截器的更多配置

在配置攔截器時,使用<mvc:mapping path="" />可以配置攔截哪些路徑,同一個攔截器的配置中,可以有多個這樣的節點。

在配置攔截路徑時,可以使用*作為萬用字元,例如:

<mvc:mapping path="/user/*" /> 

以上配置將表示攔截/user之下的所有路徑,例如:/user/login.do/user/reg.do/user/handler_login.do/user/handler_reg.do/user/inf.do等。

使用1個星號(*)只能通配1層路徑,即以上配置對於/user/info/change.do這樣的路徑是不起作用的!如果需要無視路徑的層級,應該使用2個星號(*),即配置為:

<mvc:mapping path="/user/**" />

使用以上配置,可適用於例如:/user/login.do/user/info/change.do/user/info/change/password.do等。

由於使用於萬用字元後,攔截的範圍可能過大,還可以使用<mvc:exclude-mapping />節點來配置例外

<mvc:interceptor>
    <!-- 1. 攔截的路徑 -->
    <mvc:mapping path="/user/**" />
    <mvc:mapping path="/main/index.do" />

    <!-- 2. 例外的路徑,不攔截的路徑,即白名單-->
    <mvc:exclude-mapping path="/user/reg.do" />
    <mvc:exclude-mapping path="/user/handle_reg.do" />
    <mvc:exclude-mapping path="/user/login.do" />
    <mvc:exclude-mapping path="/user/handle_reg.do" />

    <!-- 3. 指定攔截器類 -->
    <bean class="cn.huang.spring.interceptor.LoginInterceptor" />
</mvc:interceptor>

這些例外可以通俗的理解為白名單,即攔截器對於這些路徑的請求完全不受理。

注意:以上配置,必須先配置攔截路徑,再配置例外,最後配置攔截器類。

2. 字元編碼過濾器

使用SpringMVC框架時,預設並不支援中文,為了能夠支援中文,需要通過request.setCharacterEncoding("utf-8")這類的語法來指定使用的字元編碼!

這項任務不能夠在控制器(Controller)中來完成,因為,指定編碼必須在Servlet或其之前就執行,如果執行到Servlet時就已經亂碼,然後,在控制器中再來調整,就已經晚了!也就意味著,通過SpringMVC的攔截器是無法實現編碼的調整的!

解決方案是使用SpringMVC框架中自帶的CharacterEncodingFilter類,這個類是一個過濾器類,是執行在所有的Servlet之前的,所以,通過過濾器指定了編碼後,適用於所有的Servlet及後續的流程!

這個類並沒有明顯的指定使用的編碼,所以,在配置時,還需要通過初始化引數來確定所使用的編碼!

具體的配置是在web.xml中新增:

<!-- 配置字元編碼過濾器 -->
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>