今天回頭看之前發的javaweb學習路線圖,發現把路線圖中的也學的有一半多了,不過還是路漫漫。在前面的博客中有學習過spring的aop,它利用動態代理實現,在springmvc中也是一樣,今天使用HandlerInterceptor來實現登錄權限驗證。我們平時在做系統時有些頁面是需要先登錄才能訪問的,一種方法是在每個請求方法中都做登錄判斷,這樣頂多是把登錄功能封裝起來,以后沒新增一個代碼都要加上,這樣很不方便。其實這里我們可以使用攔截器進行登錄驗證,判斷是否有session,如果有session就斷定已經登錄。攔截器不僅僅可以做登錄,它做登錄完成之后可能還有根據用戶角色限制頁面或工具的權限,我們還可以再增加一個攔截器,來判斷用戶權限等。還可以使用它做防盜鏈,這個防盜鏈的之前博客中也有類似的實現,今天就只演示下登錄。
一、創建控制器
1.這里創建了LoginIntercepter類實現HandlerInterceptor來創建控制器.HandlerInterceptor它有3個方法,preHandle,postHandle,afterCompletion,3個方法在之前學習springmvc工作流程的時候也有介紹。我們做登錄驗證主要是在preHandle方法中來做校驗。這里判斷是不是登錄頁面,登錄頁面不能被攔截,不然它始終登錄不上.然后判斷是否有session,如果有則當做登錄成功,沒有則跳轉到登錄頁面.

package com.cyw.web.Intercepter; 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; public class LoginIntercepter implements HandlerInterceptor{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // TODO Auto-generated method stub String requestURI = request.getRequestURI(); if(requestURI.indexOf("/login")<=0){ //說明處在編輯的頁面 HttpSession session = request.getSession(); String username = (String) session.getAttribute("username"); if(username!=null){ //登陸成功的用戶 return true; }else{ //沒有登陸,轉向登陸界面 request.getRequestDispatcher("../view/Login.jsp").forward(request,response); // response.sendRedirect("../login/login.action"); return false; } }else{ return true; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } }
2.攔截器配置 在spring-mvc.xml中進行配置

<mvc:interceptors> <mvc:interceptor><mvc:mapping path="/**"/><bean class="com.cyw.web.Intercepter.LoginIntercepter"/></mvc:interceptor> <mvc:interceptor><mvc:mapping path="/**"/><bean class="com.cyw.web.Intercepter.LoginWebRequestInterceptor"/></mvc:interceptor> </mvc:interceptors>
這里配置了兩個攔截器,LoginWebRequestInterceptor這個也是一攔截器.
二、創建jsp頁面
這里創建了一個login.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>Insert title here</title> </head> <body> <form action="../login/login.action" method="post"> 姓名:<input type="text" name="username"> <br><br> 密碼: <input type="text" name="password"> <br><br> <input type="submit" value="登陸"> </form> </body> </html>
三、創建LoginController
這里創建了LoginController用來接收登錄的post請求.

package com.cyw.web.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; @Controller @RequestMapping("/login") public class LoginController { @RequestMapping(value = "/login.action",method = RequestMethod.GET) public ModelAndView login(HttpServletRequest request,HttpServletResponse response){ ModelAndView modelAndView = new ModelAndView("Login"); return modelAndView; } @RequestMapping(value = "login.action",method = RequestMethod.POST) public String clientLogin(HttpServletRequest request,HttpServletResponse response){ String username=request.getParameter("username"); String password=request.getParameter("password"); if(username.equals("cuiyw")&&password.equals("123456")){ //登陸成功 request.getSession().setAttribute("username",username); return "forward:/hello/testModelAndView"; }else{ //登陸失敗 return "forward:/login/login.action"; } } }
但是上面的代碼就會出現問題HTTP Status 405 – Method Not Allowed ,Request method 'POST' not supported。
為什么會出現這個錯誤呢?我開始以為是LoginController中的@RequestMapping配置有問題,但找了好久也沒找到,而且再次輸入頁面時顯示的是登錄成功的,意思是session也是設置上的,抱着嘗試的心態把return中的forward改成redirect,沒想到成功了。這就尷尬了,這就涉及到forward與redirect的區別。
四、forward與redirect的區別
forward過程
轉發,服務器端行為。web服務器把接受的請求,調用內部的方法在容器內部完成請求處理和轉發動作,然后響應客戶端,在這里,轉發的路徑必須是同一個web容器下的url,其不能轉向到其他的web路徑上去,中間傳遞的是自己的容器內的request。
redirect過程
重定向,客戶端行為。客戶端發送http請求,web服務器接受后發送3**狀態碼響應及對應新的location給客客戶端,客戶端發現是3**響應,則自動再發送一個新的http請求,請求url是新的location地址,在這里location可以重定向到任意URL,既然是瀏覽器重新發出了請求,則就沒有什么request傳遞的概念了。重定向行為是瀏覽器做了至少兩次的訪問請求。
五、問題原因
上面的forward與redirect的區別也有介紹它們兩個的區別,forward用的還是同一個請求,只是把這個請求轉給另一個方法處理,redirect是響應給客戶端3開頭的狀態碼,然后客戶端再次請求,這里我們登錄的是post請求,而/hello/testModelAndView對應的testModelAndView方法設置的method = RequestMethod.GET,就沒有post,所以報405的錯誤。
六、WebRequestInterceptor攔截器
springmvc中還可以使用WebRequestInterceptor來做攔截器,用法和HandlerInterceptor差不多,也是現實WebRequestInterceptor,然后重寫父類的方法,配置到spring-mvc.xml中。實現的方法名是一樣的,只是HandlerInterceptor中使用的HttpServletRequest,WebRequestInterceptor中使用的是WebRequest.
七.小結
其實原本不打算寫攔截器呢,因為springmvc的參數傳遞還沒寫完,所以下篇還是要接着寫參數傳遞,json與Controller的交互.