11 Spring MVC 訪問入?yún)@取和攔截器使用(@RequestParam 和 Interceptors)登錄模塊demo

轉(zhuǎn)載請注明來源 賴賴的博客

導(dǎo)語

核心思想明了悄泥,骨架已經(jīng)建立虏冻,就可以一點(diǎn)一點(diǎn)的豐滿細(xì)節(jié),反哺骨架和核心思想

前面介紹了Spring MVC 是怎么接受一個(gè)訪問的弹囚,想必你已經(jīng)明白了基本的訪問過程厨相,作為一個(gè)應(yīng)用系統(tǒng),登錄模塊都必不可少鸥鹉,不妨今天就來做一個(gè)簡單的登錄模塊蛮穿,順便熟悉一下Spring MVC的訪問入?yún)@取和攔截器的使用

實(shí)例

項(xiàng)目工程目錄結(jié)構(gòu)和代碼獲取地址

獲取地址(版本Log將會(huì)注明每一個(gè)版本對(duì)應(yīng)的課程)

https://github.com/laiyijie/SpringLearning

目錄結(jié)構(gòu)

目錄結(jié)構(gòu)

如圖所示,雖然目錄結(jié)構(gòu)看起來復(fù)雜了一些(就是文件夾深度深了一點(diǎn)兒而已)毁渗,其實(shí)最源文件只有五個(gè)践磅。所以不要緊張,這非常簡單祝蝠,而且相比上一課音诈,只多出了一個(gè)文件,和少量的配置

運(yùn)行工程

運(yùn)行方式
  • 右鍵整個(gè)項(xiàng)目
  • Run as
  • Run On Server
  • 在瀏覽器里依次輸入 (demo是工程的名稱绎狭,依照你的來替換)
    • http://localhost:8080/demo/user/hi
    • http://127.0.0.1:8080/demo/user/login?username=laiyijie&password=lailai
    • http://127.0.0.1:8080/demo/user/hi
運(yùn)行結(jié)果
1. /user/hi結(jié)果
  • http://127.0.0.1:8080/demo/user/login?username=laiyijie&password=lailai
2. /user/login結(jié)果
  • http://127.0.0.1:8080/demo/user/hi
3. 第二次/user/hi結(jié)果

第一次和最后一次的輸入是完全一樣的確實(shí)完全不同的兩個(gè)結(jié)果细溅?

由于第一次沒有登錄,然后返回的是403權(quán)限不足儡嘶,第二次是登錄以后訪問這個(gè)鏈接喇聊,可以正常返回。

項(xiàng)目詳解

依照上一章的知識(shí)蹦狂,訪問會(huì)被引流到由@RequestMapping注解的函數(shù)執(zhí)行誓篱,我們不妨直接找到UserController這個(gè)文件,訪問是由這個(gè)控制器進(jìn)行處理的

UserController.java(與上一課有變化)

package me.laiyijie.demo.controller;

import org.springframework.stereotype.Controller;
import javax.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/hi")
    @ResponseBody
    public String hello(@RequestParam(value = "name", defaultValue = "world") String name) {
        return "hello " + name;
    }

    @RequestMapping("/login")
    @ResponseBody
    public String login(@RequestParam("username") String username, @RequestParam("password") String password,
            HttpSession httpsession) {
        if ("laiyijie".equals(username) && "lailai".equals(password)) {
            httpsession.setAttribute("username", username);
            return "login success";
        }
        return "loging failed";
    }

}  

代碼有幾處變化:

  • 在類前面多了一個(gè)@RequestMapping注解凯楔,根據(jù)前面的執(zhí)行結(jié)果可以知道窜骄,如果@RequestMapping注解應(yīng)用到類上,那么這個(gè)類中的所有方法的URL都增加這個(gè)注解的前綴摆屯,在這個(gè)例子中邻遏,都增加了 /user,所以原來的/hi變成了/user/hi
  • 在方法參數(shù)中增加了由@RequestParam標(biāo)注的入?yún)⑴捌铮搮?shù)就是映射入?yún)?
    • 在第二次訪問的時(shí)候我們使用的URL為127.0.0.1/demo/user/login?username=laiyijie&password=lailai 而其對(duì)應(yīng)的函數(shù)聲明有如下兩個(gè)參數(shù)@RequestParam("username") String username, @RequestParam("password") String password
    • 顯而易見的准验,@RequestParam獲取了問號(hào)后面的鍵值對(duì)參數(shù)
    • hi這個(gè)函數(shù)中我們這樣使用@RequestParam(value = "name", defaultValue = "world") String name 設(shè)置了一個(gè)默認(rèn)值,這樣的話即使我們不傳這個(gè)參數(shù)也會(huì)返回 hello world(例如第三次訪問)
  • login函數(shù)中新增了一個(gè)HttpSession的入?yún)?
    • 首先廷没,這個(gè)入?yún)暮味鴣砗ィ窟@是SpringMVC在使用DispatcherServlet分配URL對(duì)應(yīng)控制器的時(shí)候會(huì)根據(jù)函數(shù)聲明自動(dòng)注入的一個(gè)參數(shù),相應(yīng)的還可以參考官方文檔
    • 作用很簡單就是獲取當(dāng)前的HttpSession從而可以操作Session中的屬性(Session在這個(gè)例子中是為了保存登錄狀態(tài))
  • login函數(shù)中颠黎,在用戶名和密碼正確以后除了會(huì)返回login success以外還會(huì)設(shè)置一個(gè)名為usernameSession屬性用來證明登錄成功

那么問題來了另锋,在第一次訪問/uesr/hi的時(shí)候是怎么會(huì)返回403錯(cuò)誤的呢滞项?

這就要引入Spring MVC的一個(gè)重要組件,攔截器(Interceptor)

LoginInterceptor.java(新增)

package me.laiyijie.demo.controller;

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

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

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        String username = (String) request.getSession().getAttribute("username");
        if (username != null) {
            return true;
        }else{
            response.sendError(403);
            return false;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {

    }

}

不用看這么多代碼砰蠢,其實(shí)就兩點(diǎn):

  • 實(shí)現(xiàn)了HandlerInterceptor接口
  • 寫了preHandle方法(此方法用于在分配給Controller之前執(zhí)行蓖扑,當(dāng)同意繼續(xù)訪問的時(shí)候返回true否則返回false
    • 首先獲取了Sessionusername屬性
      • String username = (String) request.getSession().getAttribute("username");
    • 如果這個(gè)屬性設(shè)置了(代表處于登錄狀態(tài))返回true繼續(xù)執(zhí)行
      • return true;
    • 如果這個(gè)屬性沒有設(shè)置(代表沒有登錄)設(shè)置返回403錯(cuò)誤并且返回false
      • response.sendError(403);
      • return false;

是不是很簡單?看了這個(gè)接口其實(shí)就可以明白攔截器處于的位置:

  • /demo/user/hi訪問被/demo接受
  • 如果定義了攔截器則進(jìn)入攔截器處理(preHandel方法)
  • 返回true則繼續(xù)分發(fā)給/user/hi對(duì)應(yīng)的方法hi否則返回錯(cuò)誤

那么又有一個(gè)新問題來了台舱,/user/login為什么沒有被攔截律杠?為什么沒有返回403錯(cuò)誤?

那就要看Interceptor的配置了:

servlet-context.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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">


    <context:component-scan base-package="me.laiyijie.demo" />

    <mvc:annotation-driven />

    <bean
        class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"
        p:messageConverters-ref="stringHttpMessageConverter" />

    <bean id="stringHttpMessageConverter"
        class="org.springframework.http.converter.StringHttpMessageConverter" />

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**" />
            <mvc:exclude-mapping path="/user/login" />
            <bean class="me.laiyijie.demo.controller.LoginInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

</beans>

攔截器配置如下(相比上節(jié)課新增):

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**" />
        <mvc:exclude-mapping path="/user/login" />
        <bean class="me.laiyijie.demo.controller.LoginInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>
  • 首先配置了一個(gè)interceptors也就是攔截器組(對(duì)竞惋,里面可以有很多個(gè)攔截器)
  • 然后配置了里面的其中一個(gè)interceptor
    • 攔截所有進(jìn)入/demo的訪問
      • <mvc:mapping path="/**" />
      • 為何有兩個(gè)*柜去?因?yàn)橐粋€(gè)*不可以代表/xx/xx只能代表/xx
    • 排除不需要攔截的路徑(原來在這里排除了/user/login
      • <mvc:exclude-mapping path="/user/login" />
    • 設(shè)置對(duì)應(yīng)的實(shí)現(xiàn)類

簡單的兩個(gè)功能實(shí)現(xiàn)了一個(gè)簡單的登錄模塊。

小結(jié)

  • @RequstMapping可以在類前注釋拆宛,代表這個(gè)類中所有處理函數(shù)都要帶其標(biāo)注的一個(gè)前綴
  • @RequestParamController處理函數(shù)的入?yún)⑶白⑨屔ど荩梢詫⒗?code>?username=laiyijie&password=lailai這樣的參數(shù)綁定到對(duì)應(yīng)的入?yún)⒅?/li>
  • @RequestParam可以設(shè)置默認(rèn)值,這樣即使訪問不帶這個(gè)參數(shù)也可以有一個(gè)默認(rèn)的輸入浑厚,使用方式是@RequestParam(defaultValue="xxx")
  • Controller中的處理函數(shù)可以增加HttpSession的入?yún)⒐傻ⅲ?code>DispatcherServlet自動(dòng)注入,還有更多的屬性可以參考官方文檔
  • 攔截器通過繼承HandlerInterceptor接口钳幅,并使用<mvc:interceptor>配置實(shí)現(xiàn)
  • 攔截器有三個(gè)鉤子物蝙,其中一個(gè)是在訪問進(jìn)入Controller之前處理(preHandle),處理結(jié)果為false可以阻止其進(jìn)入Controller中處理
  • 攔截器可以配置其攔截的路徑(<mvc:mapping path="/**" />
  • 攔截器可以排除一些特殊的路徑不進(jìn)行攔截(<mvc:exclude-mapping path="/user/login" />

附:

pom.xml(新增一個(gè)依賴)

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>me.laiyijie</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
    </properties>

    <dependencies>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

新增一個(gè)依賴javax.servlet-api作用于為provided敢艰,由容器提供

web.xml(無變化)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee">

    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
</web-app>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诬乞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子钠导,更是在濱河造成了極大的恐慌震嫉,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件牡属,死亡現(xiàn)場離奇詭異票堵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)逮栅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門换衬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人证芭,你說我怎么就攤上這事〉S常” “怎么了废士?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蝇完。 經(jīng)常有香客問我官硝,道長矗蕊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任氢架,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘棚菊。我一直安慰自己柳洋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布孙援。 她就那樣靜靜地躺著害淤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拓售。 梳的紋絲不亂的頭發(fā)上窥摄,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音础淤,去河邊找鬼崭放。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鸽凶,可吹牛的內(nèi)容都是我干的币砂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼吱瘩,長吁一口氣:“原來是場噩夢啊……” “哼道伟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起使碾,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤蜜徽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后票摇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拘鞋,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年矢门,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盆色。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡祟剔,死狀恐怖隔躲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情物延,我是刑警寧澤宣旱,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站叛薯,受9級(jí)特大地震影響浑吟,放射性物質(zhì)發(fā)生泄漏笙纤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一组力、第九天 我趴在偏房一處隱蔽的房頂上張望省容。 院中可真熱鬧,春花似錦燎字、人聲如沸腥椒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寞酿。三九已至,卻和暖如春脱柱,著一層夾襖步出監(jiān)牢的瞬間伐弹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國打工榨为, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惨好,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓随闺,卻偏偏與公主長得像日川,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矩乐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理龄句,服務(wù)發(fā)現(xiàn),斷路器散罕,智...
    卡卡羅2017閱讀 134,599評(píng)論 18 139
  • 1分歇、Spring MVC請求流程 (1)初始化:(對(duì)DispatcherServlet和ContextLoderL...
    拾壹北閱讀 1,945評(píng)論 0 12
  • 本文包括:1、如何在 Struts2 中使用 Servlet 的相關(guān) API欧漱?2职抡、分析 <result> 結(jié)果頁面...
    廖少少閱讀 891評(píng)論 3 12
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,748評(píng)論 6 342
  • 你有沒有想過從記憶中到現(xiàn)在缚甩,什么事情是你持續(xù)不間斷過的事?這個(gè)問題我猛的一下想到就是好像沒有什么事是每天都做...
    鄭珍容閱讀 83評(píng)論 0 0