Spring MVC【入門】就這一篇!

MVC 設(shè)計(jì)概述

在早期 Java Web 的開發(fā)中,統(tǒng)一把顯示層、控制層、數(shù)據(jù)層的操作全部交給 JSP 或者 JavaBean 來進(jìn)行處理,我們稱之為 Model1:

  • 出現(xiàn)的弊端:
  • JSP 和 Java Bean 之間嚴(yán)重耦合,Java 代碼和 HTML 代碼也耦合在了一起
  • 要求開發(fā)者不僅要掌握 Java ,還要有高超的前端水平
  • 前端和后端相互依賴,前端需要等待后端完成,后端也依賴前端完成,才能進(jìn)行有效的測(cè)試
  • 代碼難以復(fù)用

正因?yàn)樯厦娴姆N種弊端,所以很快這種方式就被 Servlet + JSP + Java Bean 所替代了,早期的 MVC 模型(Model2)就像下圖這樣:

首先用戶的請(qǐng)求會(huì)到達(dá) Servlet,然后根據(jù)請(qǐng)求調(diào)用相應(yīng)的 Java Bean,并把所有的顯示結(jié)果交給 JSP 去完成,這樣的模式我們就稱為 MVC 模式。

  • M 代表 模型(Model)
    模型是什么呢? 模型就是數(shù)據(jù),就是 dao,bean
  • V 代表 視圖(View)
    視圖是什么呢? 就是網(wǎng)頁, JSP,用來展示模型中的數(shù)據(jù)
  • C 代表 控制器(controller)
    控制器是什么? 控制器的作用就是把不同的數(shù)據(jù)(Model),顯示在不同的視圖(View)上,Servlet 扮演的就是這樣的角色。

擴(kuò)展閱讀:Web開發(fā)模式

Spring MVC 的架構(gòu)

為解決持久層中一直未處理好的數(shù)據(jù)庫事務(wù)的編程,又為了迎合 NoSQL 的強(qiáng)勢(shì)崛起,Spring MVC 給出了方案:

傳統(tǒng)的模型層被拆分為了業(yè)務(wù)層(Service)和數(shù)據(jù)訪問層(DAO,Data Access Object)。 在 Service 下可以通過 Spring 的聲明式事務(wù)操作數(shù)據(jù)訪問層,而在業(yè)務(wù)層上還允許我們?cè)L問 NoSQL ,這樣就能夠滿足異軍突起的 NoSQL 的使用了,它可以大大提高互聯(lián)網(wǎng)系統(tǒng)的性能。

  • 特點(diǎn):
    結(jié)構(gòu)松散,幾乎可以在 Spring MVC 中使用各類視圖
    松耦合,各個(gè)模塊分離
    與 Spring 無縫集成

Hello Spring MVC

讓我們來寫一下我們的第一個(gè) Spring MVC 程序:

第一步:在 IDEA 中新建 Spring MVC 項(xiàng)目

并且取名為 【HelloSpringMVC】,點(diǎn)擊【Finish】:

IDEA 會(huì)自動(dòng)幫我們下載好必要的 jar 包,并且為我們創(chuàng)建好一些默認(rèn)的目錄和文件,創(chuàng)建好以后項(xiàng)目結(jié)構(gòu)如下:

第二步:修改 web.xml

我們打開 web.xml ,按照下圖完成修改:

<url-pattern>元素的值改為 / ,表示要攔截所有的請(qǐng)求,并交由Spring MVC的后臺(tái)控制器來處理,改完之后:

<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

第三步:編輯 dispatcher-servlet.xml

這個(gè)文件名的開頭 dispatcher 與上面 web.xml 中的 <servlet-name> 元素配置的 dispatcher 對(duì)應(yīng),這是 Spring MVC 的映射配置文件(xxx-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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="simpleUrlHandlerMapping"
          class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <!-- /hello 路徑的請(qǐng)求交給 id 為 helloController 的控制器處理-->
                <prop key="/hello">helloController</prop>
            </props>
        </property>
    </bean>
    <bean id="helloController" class="controller.HelloController"></bean>
</beans>

第四步:編寫 HelloController

在 Package【controller】下創(chuàng)建 【HelloController】類,并實(shí)現(xiàn) org.springframework.web.servlet.mvc.Controller 接口:

package controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class HelloController implements Controller{
    @Override
    public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
        return null;
    }
}
  • 出現(xiàn)了問題: javax.servlet 包找不到
  • 解決: 將本地 Tomcat 服務(wù)器的目錄下【lib】文件夾下的 servlet-api.jar 包拷貝到工程【lib】文件夾下,添加依賴

Spring MVC 通過 ModelAndView 對(duì)象把模型和視圖結(jié)合在一起

ModelAndView mav = new ModelAndView("index.jsp");
mav.addObject("message", "Hello Spring MVC");

這里表示視圖的是index.jsp
模型數(shù)據(jù)的是 message,內(nèi)容是 “Hello Spring MVC”

package controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class HelloController implements Controller {

    public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
        ModelAndView mav = new ModelAndView("index.jsp");
        mav.addObject("message", "Hello Spring MVC");
        return mav;
    }
}

第五步:準(zhǔn)備 index.jsp

將 index.jsp 的內(nèi)容修改為:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" isELIgnored="false"%>
 
<h1>${message}</h1>

內(nèi)容很簡(jiǎn)單,用El表達(dá)式顯示 message 的內(nèi)容。

第六步:部署 Tomcat 及相關(guān)環(huán)境

在【Run】菜單項(xiàng)下找到【Edit Configurations】

配置 Tomcat 環(huán)境:

選擇好本地的 Tomcat 服務(wù)器,并改好名字:

在 Deployment 標(biāo)簽頁下完成如下操作:

點(diǎn)擊 OK 就好了,我們點(diǎn)擊右上角的三角形將 Tomcat 服務(wù)器運(yùn)行起來。

  • 出現(xiàn)的問題: Tomcat 服務(wù)器無法正常啟動(dòng)
  • 原因: Tomcat 服務(wù)器找不到相關(guān)的 jar 包
  • 解決方法: 將【lib】文件夾整個(gè)剪貼到【W(wǎng)EB-INF】下,并重新建立依賴:

第七步:重啟服務(wù)器

重啟服務(wù)器,輸入地址:localhost/hello

參考資料:Spring MVC 教程(how2j.cn)


跟蹤 Spring MVC 的請(qǐng)求

每當(dāng)用戶在 Web 瀏覽器中點(diǎn)擊鏈接或者提交表單的時(shí)候,請(qǐng)求就開始工作了,像是郵遞員一樣,從離開瀏覽器開始到獲取響應(yīng)返回,它會(huì)經(jīng)歷很多站點(diǎn),在每一個(gè)站點(diǎn)都會(huì)留下一些信息同時(shí)也會(huì)帶上其他信息,下圖為 Spring MVC 的請(qǐng)求流程:

第一站:DispatcherServlet

從請(qǐng)求離開瀏覽器以后,第一站到達(dá)的就是 DispatcherServlet,看名字這是一個(gè) Servlet,通過 J2EE 的學(xué)習(xí),我們知道 Servlet 可以攔截并處理 HTTP 請(qǐng)求,DispatcherServlet 會(huì)攔截所有的請(qǐng)求,并且將這些請(qǐng)求發(fā)送給 Spring MVC 控制器。

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <!-- 攔截所有的請(qǐng)求 -->
    <url-pattern>/</url-pattern>
</servlet-mapping>
  • DispatcherServlet 的任務(wù)就是攔截請(qǐng)求發(fā)送給 Spring MVC 控制器。

第二站:處理器映射(HandlerMapping)

  • 問題: 典型的應(yīng)用程序中可能會(huì)有多個(gè)控制器,這些請(qǐng)求到底應(yīng)該發(fā)給哪一個(gè)控制器呢?

所以 DispatcherServlet 會(huì)查詢一個(gè)或多個(gè)處理器映射來確定請(qǐng)求的下一站在哪里,處理器映射會(huì)根據(jù)請(qǐng)求所攜帶的 URL 信息來進(jìn)行決策,例如上面的例子中,我們通過配置 simpleUrlHandlerMapping 來將 /hello 地址交給 helloController 處理:

<bean id="simpleUrlHandlerMapping"
      class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <!-- /hello 路徑的請(qǐng)求交給 id 為 helloController 的控制器處理-->
            <prop key="/hello">helloController</prop>
        </props>
    </property>
</bean>
<bean id="helloController" class="controller.HelloController"></bean>

第三站:控制器

一旦選擇了合適的控制器, DispatcherServlet 會(huì)將請(qǐng)求發(fā)送給選中的控制器,到了控制器,請(qǐng)求會(huì)卸下其負(fù)載(用戶提交的請(qǐng)求)等待控制器處理完這些信息:

public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
    // 處理邏輯
    ....
}

第四站:返回 DispatcherServlet

當(dāng)控制器在完成邏輯處理后,通常會(huì)產(chǎn)生一些信息,這些信息就是需要返回給用戶并在瀏覽器上顯示的信息,它們被稱為模型(Model)。僅僅返回原始的信息時(shí)不夠的——這些信息需要以用戶友好的方式進(jìn)行格式化,一般會(huì)是 HTML,所以,信息需要發(fā)送給一個(gè)視圖(view),通常會(huì)是 JSP。

控制器所做的最后一件事就是將模型數(shù)據(jù)打包,并且表示出用于渲染輸出的視圖名(邏輯視圖名)。它接下來會(huì)將請(qǐng)求連同模型和視圖名發(fā)送回 DispatcherServlet。

public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
    // 處理邏輯
    ....
    // 返回給 DispatcherServlet
    return mav;
}

第五站:視圖解析器

這樣以來,控制器就不會(huì)和特定的視圖相耦合,傳遞給 DispatcherServlet 的視圖名并不直接表示某個(gè)特定的 JSP。(實(shí)際上,它甚至不能確定視圖就是 JSP)相反,它傳遞的僅僅是一個(gè)邏輯名稱,這個(gè)名稱將會(huì)用來查找產(chǎn)生結(jié)果的真正視圖。

DispatcherServlet 將會(huì)使用視圖解析器(view resolver)來將邏輯視圖名匹配為一個(gè)特定的視圖實(shí)現(xiàn),它可能是也可能不是 JSP

上面的例子是直接綁定到了 index.jsp 視圖

第六站:視圖

既然 DispatcherServlet 已經(jīng)知道由哪個(gè)視圖渲染結(jié)果了,那請(qǐng)求的任務(wù)基本上也就完成了。

它的最后一站是視圖的實(shí)現(xiàn),在這里它交付模型數(shù)據(jù),請(qǐng)求的任務(wù)也就完成了。視圖使用模型數(shù)據(jù)渲染出結(jié)果,這個(gè)輸出結(jié)果會(huì)通過響應(yīng)對(duì)象傳遞給客戶端。

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" isELIgnored="false"%>

<h1>${message}</h1>

使用注解配置 Spring MVC

上面我們已經(jīng)對(duì) Spring MVC 有了一定的了解,并且通過 XML 配置的方式創(chuàng)建了第一個(gè) Spring MVC 程序,我們來看看基于注解應(yīng)該怎么完成上述程序的配置:

第一步:為 HelloController 添加注解

package controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloController{

    @RequestMapping("/hello")
    public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
        ModelAndView mav = new ModelAndView("index.jsp");
        mav.addObject("message", "Hello Spring MVC");
        return mav;
    }
}

把實(shí)現(xiàn)的接口也給去掉。

  • 簡(jiǎn)單解釋一下:
  • @Controller 注解:
    很明顯,這個(gè)注解是用來聲明控制器的,但實(shí)際上這個(gè)注解對(duì) Spring MVC 本身的影響并不大。(Spring 實(shí)戰(zhàn)說它僅僅是輔助實(shí)現(xiàn)組件掃描,可以用 @Component 注解代替,但我自己嘗試了一下并不行,因?yàn)樯鲜隼記]有配置 JSP 視圖解析器我還自己配了一個(gè)仍沒有成功...)
  • @RequestMapping 注解:
    很顯然,這就表示路徑 /hello 會(huì)映射到該方法上

第二步:取消之前的 XML 注釋

在 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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="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.xsd">

    <!--<bean id="simpleUrlHandlerMapping"-->
                                        <!--class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">-->
    <!--<property name="mappings">-->
            <!--<props>-->
                <!--&lt;!&ndash; /hello 路徑的請(qǐng)求交給 id 為 helloController 的控制器處理&ndash;&gt;-->
                <!--<prop key="/hello">helloController</prop>-->
            <!--</props>-->
        <!--</property>-->
    <!--</bean>-->
    <!--<bean id="helloController" class="controller.HelloController"></bean>-->

    <!-- 掃描controller下的組件 -->
    <context:component-scan base-package="controller"/>
</beans>

第三步:重啟服務(wù)器

當(dāng)配置完成,重新啟動(dòng)服務(wù)器,輸入 localhost/hello 地址仍然能看到效果:

@RequestMapping 注解細(xì)節(jié)

如果 @RequestMapping 作用在類上,那么就相當(dāng)于是給該類所有配置的映射地址前加上了一個(gè)地址,例如:

@Controller
@RequestMapping("/wmyskxz")
public class HelloController {
    @RequestMapping("/hello")
    public ModelAndView handleRequest(....) throws Exception {
        ....
    }
}
  • 則訪問地址: localhost/wmyskxz/hello

配置視圖解析器

還記得我們 Spring MVC 的請(qǐng)求流程嗎,視圖解析器負(fù)責(zé)定位視圖,它接受一個(gè)由 DispaterServlet 傳遞過來的邏輯視圖名來匹配一個(gè)特定的視圖。

  • 需求: 有一些頁面我們不希望用戶用戶直接訪問到,例如有重要數(shù)據(jù)的頁面,例如有模型數(shù)據(jù)支撐的頁面。
  • 造成的問題:
    我們可以在【web】根目錄下放置一個(gè)【test.jsp】模擬一個(gè)重要數(shù)據(jù)的頁面,我們什么都不用做,重新啟動(dòng)服務(wù)器,網(wǎng)頁中輸入 localhost/test.jsp 就能夠直接訪問到了,這會(huì)造成數(shù)據(jù)泄露...
    另外我們可以直接輸入 localhost/index.jsp 試試,根據(jù)我們上面的程序,這會(huì)是一個(gè)空白的頁面,因?yàn)椴]有獲取到 ${message} 參數(shù)就直接訪問了,這會(huì)影響用戶體驗(yàn)

解決方案

我們將我們的 JSP 文件配置在【W(wǎng)EB-INF】文件夾中的【page】文件夾下,【W(wǎng)EB-INF】是 Java Web 中默認(rèn)的安全目錄,是不允許用戶直接訪問的(也就是你說你通過 localhost/WEB-INF/ 這樣的方式是永遠(yuǎn)訪問不到的)

但是我們需要將這告訴給視圖解析器,我們?cè)?dispatcher-servlet.xml 文件中做如下配置:

<bean id="viewResolver"
      class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/page/" />
    <property name="suffix" value=".jsp" />
</bean>

這里配置了一個(gè) Spring MVC 內(nèi)置的一個(gè)視圖解析器,該解析器是遵循著一種約定:會(huì)在視圖名上添加前綴和后綴,進(jìn)而確定一個(gè) Web 應(yīng)用中視圖資源的物理路徑的。讓我們實(shí)際來看看效果:

第一步:修改 HelloController

我們將代碼修改一下:

第二步:配置視圖解析器:

按照上述的配置,完成:

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="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.xsd">

    <!--<bean id="simpleUrlHandlerMapping"-->
                                        <!--class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">-->
    <!--<property name="mappings">-->
            <!--<props>-->
                <!--&lt;!&ndash; /hello 路徑的請(qǐng)求交給 id 為 helloController 的控制器處理&ndash;&gt;-->
                <!--<prop key="/hello">helloController</prop>-->
            <!--</props>-->
        <!--</property>-->
    <!--</bean>-->
    <!--<bean id="helloController" class="controller.HelloController"></bean>-->

    <!-- 掃描controller下的組件 -->
    <context:component-scan base-package="controller"/>
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/page/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

第三步:剪貼 index.jsp 文件

在【W(wǎng)EB-INF】文件夾下新建一個(gè)【page】文件夾,并將【index.jsp】文件剪貼到里面:

第四步:更新資源重啟服務(wù)器

訪問 localhost/hello 路徑,看到正確效果:

  • 原理:

我們傳入的邏輯視圖名為 index ,再加上 “/WEB-INF/page/” 前綴和 “.jsp” 后綴,就能確定物理視圖的路徑了,這樣我們以后就可以將所有的視圖放入【page】文件夾下了!

  • 注意:此時(shí)的配置僅是 dispatcher-servlet.xml 下的

控制器接收請(qǐng)求數(shù)據(jù)

使用控制器接收參數(shù)往往是 Spring MVC 開發(fā)業(yè)務(wù)邏輯的第一步,為探索 Spring MVC 的傳參方式,為此我們先來創(chuàng)建一個(gè)簡(jiǎn)單的表單用于提交數(shù)據(jù):

<!DOCTYPE html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" import="java.util.*" isELIgnored="false"%>
<html>
<head>
    <meta charset="utf-8">
    <title>Spring MVC 傳參方式</title>
</head>
<body>
<form action="/param" role="form">
    用戶名:<input type="text" name="userName"><br/>
    密碼:<input type="text" name="password"><br/>
    <input type="submit" value="提  交">
</form>
</body>
</html>

丑就丑點(diǎn)兒吧,我們就是來測(cè)試一下:

使用 Servlet 原生 API 實(shí)現(xiàn):

我們很容易知道,表單會(huì)提交到 /param 這個(gè)目錄,我們先來使用 Servlet 原生的 API 來看看能不能獲取到數(shù)據(jù):

@RequestMapping("/param")
public ModelAndView getParam(HttpServletRequest request,
                         HttpServletResponse response) {
    String userName = request.getParameter("userName");
    String password = request.getParameter("password");

    System.out.println(userName);
    System.out.println(password);
    return null;
}

測(cè)試成功:

使用同名匹配規(guī)則

我們可以把方法定義的形參名字設(shè)置成和前臺(tái)傳入?yún)?shù)名一樣的方法,來獲取到數(shù)據(jù)(同名匹配規(guī)則):

@RequestMapping("/param")
public ModelAndView getParam(String userName,
                             String password) {
    System.out.println(userName);
    System.out.println(password);
    return null;
}

測(cè)試成功:

  • 問題: 這樣又會(huì)和前臺(tái)產(chǎn)生很強(qiáng)的耦合,這是我們不希望的
  • 解決: 使用 @RequestParam("前臺(tái)參數(shù)名") 來注入:
  • @RequestParam 注解細(xì)節(jié):
    該注解有三個(gè)變量:value、required、defaultvalue
  • value :指定 name 屬性的名稱是什么,value 屬性都可以默認(rèn)不寫
  • required :是否必須要有該參數(shù),可以設(shè)置為【true】或者【false】
  • defaultvalue :設(shè)置默認(rèn)值

使用模型傳參

  • 要求: 前臺(tái)參數(shù)名字必須和模型中的字段名一樣

讓我們先來為我們的表單創(chuàng)建一個(gè) User 模型:

package pojo;

public class User {
    
    String userName;
    String password;

    /* getter and setter */
}

然后測(cè)試仍然成功:

中文亂碼問題

  • 注意: 跟 Servlet 中的一樣,該方法只對(duì) POST 方法有效(因?yàn)槭侵苯犹幚淼?request)

我們可以通過配置 Spring MVC 字符編碼過濾器來完成,在 web.xml 中添加:

<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <!-- 設(shè)置編碼格式 -->
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

控制器回顯數(shù)據(jù)

通過上面,我們知道了怎么接受請(qǐng)求數(shù)據(jù),并能解決 POST 亂碼的問題,那么我們?cè)趺椿仫@數(shù)據(jù)呢?為此我們?cè)凇緋age】下創(chuàng)建一個(gè)【test2.jsp】:

<!DOCTYPE html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" import="java.util.*" isELIgnored="false" %>
<html>
<head>
    <title>Spring MVC 數(shù)據(jù)回顯</title>
</head>
<body>
<h1>回顯數(shù)據(jù):${message}</h1>
</body>
</html>

使用 Servlet 原生 API 來實(shí)現(xiàn)

我們先來測(cè)試一下 Servlet 原生的 API 是否能完成這個(gè)任務(wù):

@RequestMapping("/value")
public ModelAndView handleRequest(HttpServletRequest request,
                                  HttpServletResponse response) {
    request.setAttribute("message","成功!");
    return new ModelAndView("test1");
}

在瀏覽器地址欄中輸入:localhost/value 測(cè)試

使用 Spring MVC 所提供的 ModelAndView 對(duì)象

使用 Model 對(duì)象

在 Spring MVC 中,我們通常都是使用這樣的方式來綁定數(shù)據(jù),

  • 使用 @ModelAttribute 注解:
@ModelAttribute
public void model(Model model) {
    model.addAttribute("message", "注解成功");
}

@RequestMapping("/value")
public String handleRequest() {
    return "test1";
}

這樣寫就會(huì)在訪問控制器方法 handleRequest() 時(shí),會(huì)首先調(diào)用 model() 方法將 message 添加進(jìn)頁面參數(shù)中去,在視圖中可以直接調(diào)用,但是這樣寫會(huì)導(dǎo)致該控制器所有的方法都會(huì)首先調(diào)用 model() 方法,但同樣的也很方便,因?yàn)榭梢约尤敫鞣N各樣的數(shù)據(jù)。


客戶端跳轉(zhuǎn)

前面不管是地址 /hello 跳轉(zhuǎn)到 index.jsp 還是 /test 跳轉(zhuǎn)到 test.jsp,這些都是服務(wù)端的跳轉(zhuǎn),也就是 request.getRequestDispatcher("地址").forward(request, response);

那我們?nèi)绾芜M(jìn)行客戶端跳轉(zhuǎn)呢?我們繼續(xù)在 HelloController 中編寫:

@RequestMapping("/hello")
public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
    ModelAndView mav = new ModelAndView("index");
    mav.addObject("message", "Hello Spring MVC");
    return mav;
}

@RequestMapping("/jump")
public ModelAndView jump() {
    ModelAndView mav = new ModelAndView("redirect:/hello");
    return mav;
}

我們使用 redirect:/hello 就表示我們要跳轉(zhuǎn)到 /hello 這個(gè)路徑,我們重啟服務(wù)器,在地址欄中輸入:localhost/jump ,會(huì)自動(dòng)跳轉(zhuǎn)到 /hello 路徑下:

也可以這樣用:

@RequestMapping("/jump")
public String jump() {
    return "redirect: ./hello";
}

文件上傳

我們先來回顧一下傳統(tǒng)的文件上傳和下載:這里

我們?cè)賮砜匆幌略?Spring MVC 中如何實(shí)現(xiàn)文件的上傳和下載

  • 注意: 需要先導(dǎo)入 commons-io-1.3.2.jarcommons-fileupload-1.2.1.jar 兩個(gè)包

第一步:配置上傳解析器

在 dispatcher-servlet.xml 中新增一句:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>

開啟對(duì)上傳功能的支持

第二步:編寫 JSP

文件名為 upload.jsp,仍創(chuàng)建在【page】下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>測(cè)試文件上傳</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="picture">
    <input type="submit" value="上 傳">
</form>
</body>
</html>

第三步:編寫控制器

在 Package【controller】下新建【UploadController】類:

package controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class UploadController {

    @RequestMapping("/upload")
    public void upload(@RequestParam("picture") MultipartFile picture) throws Exception {
        System.out.println(picture.getOriginalFilename());
    }

    @RequestMapping("/test2")
    public ModelAndView upload() {
        return new ModelAndView("upload");
    }

}

第四步:測(cè)試

在瀏覽器地址欄中輸入:localhost/test2 ,選擇文件點(diǎn)擊上傳,測(cè)試成功:


參考資料:

  • 《Java EE 互聯(lián)網(wǎng)輕量級(jí)框架整合開發(fā)》
  • 《Spring 實(shí)戰(zhàn)》
  • How2j Spring MVC 系列教程
  • 全能的百度和萬能的大腦

歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明出處!
簡(jiǎn)書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關(guān)注公眾微信號(hào):wmyskxz
分享自己的學(xué)習(xí) & 學(xué)習(xí)資料 & 生活
想要交流的朋友也可以加qq群:3382693

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,285評(píng)論 6 342
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,695評(píng)論 19 139
  • 本章內(nèi)容: 映射請(qǐng)求到Spring控制器 透明地綁定表單參數(shù) 校驗(yàn)表單提交 狀態(tài)管理、工作流以及驗(yàn)證都是Web 開...
    謝隨安閱讀 8,779評(píng)論 0 4
  • Spring MVC一、什么是 Spring MVCSpring MVC 屬于 SpringFrameWork 的...
    任任任任師艷閱讀 3,551評(píng)論 0 32
  • 《我的眼里沒有你》 文/白傳英 也許是天意 我不能和你在一起 或許是老天的有意安排 在你我之間增加了距離...
    白清風(fēng)閱讀 270評(píng)論 0 0

友情鏈接更多精彩內(nèi)容