SpringMVC

SpringMVC環(huán)境的基本搭建

Spring MVC 是目前主流的實(shí)現(xiàn) MVC 設(shè)計(jì)模式的企業(yè)級開發(fā)框架,Spring 框架的一個(gè)子模塊譬重,無需整合拒逮,開發(fā)起來更加便捷讯檐。

什么是 MVC 設(shè)計(jì)模式工三?

將應(yīng)用程序分為 Controller汗盘、Model挖息、View 三層,Controller 接收客戶端請求独榴,調(diào)用 Model 生成業(yè)務(wù)數(shù)據(jù)谍失,傳遞給 View琼了。

Spring MVC 就是對這套流程的封裝谨究,屏蔽了很多底層代碼恩袱,開放出接口,讓開發(fā)者可以更加輕松胶哲、便捷地完成基于 MVC 模式的 Web 開發(fā)畔塔。

Spring MVC 的核心組件

  • DispatcherServlet:前置控制器,是整個(gè)流程控制的核心纪吮,控制其他組件的執(zhí)行,進(jìn)行統(tǒng)一調(diào)度萎胰,降低組件之間的耦合性碾盟,相當(dāng)于總指揮。
  • Handler:處理器技竟,控制器在SpringMVC中由其實(shí)現(xiàn),完成(處理)具體的業(yè)務(wù)邏輯冰肴,相當(dāng)于 Servlet 或 Action。
  • HandlerMapping:DispatcherServlet 接收到請求之后榔组,通過 HandlerMapping 將不同的請求映射到不同的 Handler熙尉。相當(dāng)于DispatcherServlet和Handler之間映射的組件.
  • HandlerInterceptor:處理器攔截器,是一個(gè)接口搓扯,如果需要完成一些攔截處理检痰,可以實(shí)現(xiàn)該接口。
  • HandlerExecutionChain:處理器執(zhí)行鏈锨推,包括兩部分內(nèi)容:Handler 和 HandlerInterceptor(系統(tǒng)會(huì)有一個(gè)默認(rèn)的 HandlerInterceptor铅歼,如果需要額外設(shè)置攔截,可以添加攔截器)换可。
  • HandlerAdapter:處理器適配器椎椰,Handler 執(zhí)行業(yè)務(wù)方法之前,需要進(jìn)行一系列的操作沾鳄,包括表單數(shù)據(jù)的驗(yàn)證慨飘、數(shù)據(jù)類型的轉(zhuǎn)換、將表單數(shù)據(jù)封裝到 JavaBean 等译荞,這些操作都是由 HandlerApater 來完成瓤的,開發(fā)者只需將注意力集中在業(yè)務(wù)邏輯的處理上休弃,不需要去關(guān)注一些比較瑣碎的工作了,DispatcherServlet 通過 HandlerAdapter 執(zhí)行不同的 Handler。
  • ModelAndView:裝載了模型數(shù)據(jù)和視圖信息堤瘤,作為 Handler 的處理結(jié)果玫芦,返回給 DispatcherServlet。
  • ViewResolver:視圖解析器本辐,DispatcherServlet 通過它將邏輯視圖(ModelAndView)解析為物理視圖(比如jsp,html)桥帆,最終將渲染結(jié)果響應(yīng)給客戶端。

Spring MVC 的工作流程

  • 客戶端請求被 DisptacherServlet 接收慎皱。
  • 根據(jù) HandlerMapping 映射到 Handler老虫。
  • 生成 Handler 和 HandlerInterceptor。
  • Handler 和 HandlerInterceptor 以 HandlerExecutionChain 的形式一并返回給 DisptacherServlet茫多。
  • DispatcherServlet 通過 HandlerAdapter 調(diào)用 Handler 的方法完成業(yè)務(wù)邏輯處理祈匙。
  • Handler 返回一個(gè) ModelAndView 給 DispatcherServlet。
  • DispatcherServlet 將獲取的 ModelAndView 對象傳給 ViewResolver 視圖解析器天揖,將邏輯視圖解析為物理視圖 View夺欲。
  • ViewResovler 返回一個(gè) View 給 DispatcherServlet。
  • DispatcherServlet 根據(jù) View 進(jìn)行視圖渲染(將模型數(shù)據(jù) Model 填充到視圖 View 中)今膊。
  • DispatcherServlet 將渲染后的結(jié)果響應(yīng)給客戶端些阅。
image.png

Spring MVC 流程非常復(fù)雜,但實(shí)際開發(fā)中很簡單斑唬,因?yàn)榇蟛糠值慕M件不需要開發(fā)者創(chuàng)建市埋、管理,只需要通過配置文件的方式完成配置即可恕刘,相當(dāng)于框架已經(jīng)把需要的組件給你了,你只需要通過一個(gè)配置文件告訴工程怎么協(xié)同工作就可以了,真正需要開發(fā)者進(jìn)行處理的只有 Handler 缤谎、View。Model包括在Handler里了,Handler組件需要自己寫是因?yàn)镠andler里是寫業(yè)務(wù)的例如: 注冊,登錄,驗(yàn)證業(yè)務(wù)等等,都是跟項(xiàng)目實(shí)際相關(guān)的,而SpringMVC作為工具來講肯定不會(huì)幫你實(shí)現(xiàn),因?yàn)樗峁┑亩际峭ㄓ玫墓δ?同理View也是根據(jù)具體的業(yè)務(wù)和需求來決定怎么展示數(shù)據(jù)

如何使用褐着?

  • 創(chuàng)建 Maven 工程選擇webapp模板坷澡,配置 pom.xml
    web相關(guān)的組件都放在webapp包下,在main下添加java和resources資源包
<dependencies>
<!--    添加springmvc的依賴-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.0.11.RELEASE</version>
    </dependency>
  </dependencies>
  • 在 web.xml 中配置 DispatcherServlet。
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
<!--  添加Servlet配置-->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--  讓DispatcherServlet讀取springmvc.xml,添加初始化參數(shù)-->
    <init-param>
<!--      上下文配置的路徑-->
      <param-name>contextConfigLocation</param-name>
<!--      classpath: 表示resources包的根目錄,直接把springmvc的路徑寫進(jìn)來就行了-->
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
  </servlet>
  <!--  添加Servlet映射-->
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
<!--    攔截所有請求,所以寫斜杠就行-->
    <url-pattern>/</url-pattern>
  </servlet-mapping>
<!--  還需要把springmvc自己的文件加進(jìn)來,就是讓DispatcherServlet來讀取springmvc自己的配置文件-->
</web-app>
  • 配置springmvc.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"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">

<!--    配置springmvc的相關(guān)配置-->
<!--    自動(dòng)掃描: 會(huì)自動(dòng)地把相關(guān)組件掃到IOC中,所以在java包下寫的任何類的組件都交給ioc來管理-->
    <context:component-scan base-package="com.tiga"></context:component-scan>
<!--    配置視圖解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--    比如將"index"字符串解析成物理視圖,讓他與index.jsp聯(lián)系起來:結(jié)合前綴,后綴變成/index.jsp就是個(gè)完整路徑-->
<!--        配置頁面的前綴,value值是斜杠,表示webapp的根目錄-->
        <property name="prefix" value="/"></property>
<!--        配置頁面的后綴-->
        <property name="suffix" value=".jsp"></property>
    </bean>
    
</beans>
  • 創(chuàng)建 Handler類
// 控制器
@Controller// 類似Component注解,也是可以把類交給ioc管理,只是多了控制器的功能
public class HelloHandler {
    // 業(yè)務(wù)方法
    // 讓客戶端地址欄的請求與業(yè)務(wù)方法關(guān)聯(lián)起來
    // 當(dāng)?shù)刂窓谳斎雐ndex就調(diào)用index方法
    @RequestMapping(value = "/index")// 當(dāng)訪問index的時(shí)候就映射到index方法
    public String index(){
        System.out.println("執(zhí)行了index..");
        // 返回一個(gè)邏輯視圖,然后再結(jié)合視圖解析器就可以找到index.jsp了
        return "index";
    }
}
  • 執(zhí)行流程(原理):

啟動(dòng)服務(wù)器后,通過客戶端(瀏覽器)地址欄發(fā)送index請求,會(huì)被服務(wù)器中映射的在web.xml中配置的DispatcherServlet捕獲,index請求是通過RequestMapping注解映射的,捕獲到index之后會(huì)根據(jù)HandlerMapping的參數(shù)映射找到對應(yīng)的Handler控制器類,然后進(jìn)到對應(yīng)Handler類的方法里,方法調(diào)用是由SpringMVC完成,他會(huì)實(shí)例化Handler類,然后調(diào)用映射方法,方法返回一個(gè)邏輯視圖,這個(gè)邏輯視圖會(huì)返回到DispatcherServlet中,然后DispatcherServlet再把邏輯視圖交給ViewResolver(視圖解析器)解析,解析規(guī)則已在springmvc.xml中定義好了,根據(jù)前綴和后綴解析,解析后從一個(gè)邏輯視圖路徑變成一個(gè)物理視圖路徑:/index.jsp,因?yàn)椴渴鸬絫omcat后web應(yīng)用程序是在target包下的,所以這時(shí)候他就會(huì)在target包的web應(yīng)用的根目錄下找到index.jsp對應(yīng)的物理視圖返回給客戶端,就能看到頁面內(nèi)容

Spring MVC 注解

  • @RequestMapping

Spring MVC 通過 @RequestMapping 注解將 URL 請求與業(yè)務(wù)方法進(jìn)行映射含蓉,在 Handler 的類定義處以及方法定義處都可以添加 @RequestMapping 洋访,在類定義處添加,相當(dāng)于客戶端多了一層訪問路徑谴餐。在方法處定義,就是把URL請求和方法綁定起來

  • @Controller

@Controller 在類定義處添加姻政,將該類交給 IoC 容器來管理(需要結(jié)合 springmvc.xml 的自動(dòng)掃描配置使用),同時(shí)使其成為一個(gè)控制器(必須要先自動(dòng)掃描再加注解才可以)岂嗓,可以接收客戶端請求汁展。控制器可理解為Handler

  • @RequestMapping 相關(guān)參數(shù)

1、value:指定客戶端你 URL 請求的實(shí)際地址食绿,是 @RequestMapping 的默認(rèn)值侈咕。可以省略.

@RequestMapping(value = "/index")// 當(dāng)訪問index的時(shí)候就映射到當(dāng)前添加注解的方法
// 等于@RequestMapping("/index")
    public String index(){
        System.out.println("執(zhí)行了index..");
        // 返回一個(gè)邏輯視圖,然后再結(jié)合視圖解析器就可以找到index.jsp了
        return "index";
    }

2器紧、method:指定請求的 method 類型(HTTP請求類型)耀销,常用的: GET、POST铲汪、PUT熊尉、DELET。不添加method,則可以放行大部分類型的請求

@RequestMapping(value = "/index",method = RequestMethod.GET)
public String index(){
    System.out.println("執(zhí)行了index...");
    return "index";
}

上述代碼表示 index 方法只能接收 GET 請求掌腰。

3狰住、params:指定請求中必須包含某些參數(shù),否則無法調(diào)用(訪問)該方法齿梁。

@RequestMapping(value = "/index",method = RequestMethod.GET,params = {"name","id=10"})
public String index(){
    System.out.println("執(zhí)行了index...");
    return "index";
}

上述代碼表示請求中必須包含 name 和 id 兩個(gè)參數(shù)催植,同時(shí) id 的值必須是 10。

  • 在業(yè)務(wù)方法中獲取到URL請求的參數(shù)
    在之前Servlet獲取參數(shù)需要通過request對象的getparameter方法獲取,現(xiàn)在不用手動(dòng)獲取,通過HandlerAdapter來完成數(shù)據(jù)處理,我們只需要在業(yè)務(wù)方法中添加想要的與params注解參數(shù)同名的形參,springmvc框架就會(huì)自動(dòng)把請求的的參數(shù)自動(dòng)賦給方法的形參

  • 體現(xiàn)HandlerAdapter的用途: 數(shù)據(jù)類型的轉(zhuǎn)換
    關(guān)于參數(shù)綁定勺择,在形參列表中通過添加 @RequestParam 注解完成 HTTP 請求參數(shù)與業(yè)務(wù)方法形參的映射创南。

  @RequestMapping(value = "/index",method = RequestMethod.GET,params = {"name","id=10"})// 當(dāng)訪問index的時(shí)候就映射到當(dāng)前添加注解的方法
    // 獲取的形參名必須要跟注解param屬性的參數(shù)一致,否則會(huì)報(bào)異常:給形參賦了null值,因?yàn)橹笆峭ㄟ^方法形參名與注解param屬性參數(shù)名一致來賦值的,而他們名字不一致的時(shí)候就不會(huì)完成賦值
    // 若非要名字不同,就可以通過給形參加RequestParam注解來映射,名字相同可以不加注解
    public String index(@RequestParam("name") String str,@RequestParam("id") Integer age){
        System.out.println("執(zhí)行了index..");
        System.out.println(age + ":" + str);
        // 返回一個(gè)邏輯視圖,然后再結(jié)合視圖解析器就可以找到index.jsp了
        return "index";
    }

上述代碼表示將請求的參數(shù) name 和 id 分別賦給了形參 str 和 age ,同時(shí)自動(dòng)完成了數(shù)據(jù)類型轉(zhuǎn)換省核,將 “10” 轉(zhuǎn)為了 int 類型的 10稿辙,再賦給 age,這些工作都是由 HandlerAdapter 來完成的芳撒。HandlerAdapter可以理解為你的助手或保姆,你希望在方法中用到哪些參數(shù),直接在形參里添加就行,添加之后HandlerAdapter就自動(dòng)幫你完成參數(shù)的賦值

Spring MVC 也支持 RESTful 風(fēng)格的 URL邓深。REST是互聯(lián)網(wǎng)軟件架構(gòu)的一種形式,通過這種形式就可以完成不同系統(tǒng)之間的數(shù)據(jù)交互,相當(dāng)于是統(tǒng)一的規(guī)則

傳統(tǒng)url類型:http://localhost:8080/hello/index?name=zhangsan&id=10

REST風(fēng)格url類型:http://localhost:8080/hello/index/zhangsan/10

SpringMVC中解析RESTful風(fēng)格的url參數(shù)類型

// RESTful風(fēng)格的URL請求類型參數(shù)解析
    // 如果要從url地址獲取參數(shù)就要通過下面的寫法解析,要在定義路徑的時(shí)候就要把參數(shù)按以下格式寫出來
    @RequestMapping("/rest/{name}/{id}")
    // 基于RESTful風(fēng)格形參的參數(shù)不會(huì)和注解參數(shù)直接映射,要手動(dòng)給形參加@PathVariable注解并給注解賦值為形參名才能映射
    // 因?yàn)镽ESTful風(fēng)格的URL地址沒有注明參數(shù)名
    public String rest(@PathVariable("name") String name,@PathVariable("id") int id){
        System.out.println(name);
        System.out.println(id);
        System.out.println("執(zhí)行了index...");
        return "index";
    }

通過 @PathVariable 注解完成請求參數(shù)與形參的映射未桥。這就是SpringMVC對REST的支持

  • SpringMVC映射 Cookie

Spring MVC 通過映射可以直接在業(yè)務(wù)方法中獲取 Cookie 的值笔刹。

 @RequestMapping("/cookie")
    // 獲取客戶端的JSESSIONID的注解
    public String cookie(@CookieValue(value = "JSESSIONID") String sessionId) {
        System.out.println(sessionId);
        return "index";
    }
  • 使用 JavaBean(對象) 綁定參數(shù)

Spring MVC 會(huì)根據(jù)請求參數(shù)名和 JavaBean 屬性名進(jìn)行自動(dòng)匹配,自動(dòng)為對象填充屬性值冬耿,同時(shí)支持及聯(lián)屬性(對象里的屬性是對象)舌菜。

import lombok.Data;

@Data
public class Address {
    private String value;
}
import lombok.Data;

@Data
public class User {
    private long id;
    private String name;
    private Address address;
}
  • 頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/hello/save" method="post">
<%--    通過input標(biāo)簽的中的name屬性來給javabean屬性自動(dòng)映射--%>
    用戶id: <input type="text" name="id"><br>
    用戶名: <input type="text" name="name"><br>
<%--    這里的用戶地址是address對象的屬性值,不能直接寫address,
因?yàn)閍ddress是個(gè)對象不像name是個(gè)String類型的值,所以input標(biāo)簽只能添加給address對象里的屬性
所以標(biāo)簽name屬性寫成address.value就行,做一個(gè)級聯(lián)--%>
<%--    從User中的address屬性 找到Address中的value--%>
<%--這個(gè)表單添加數(shù)據(jù)的主體是User類,相當(dāng)于給user對象的address屬性添加值,
address屬性又是個(gè)對象,就相當(dāng)于把值加給了user對象的address對象屬性的value屬性--%>
    地址: <input type="text" name="address.value"><br>
    <input type="submit" value="注冊">
</form>
</body>
</html>
  • 業(yè)務(wù)方法
// 把注冊表單和業(yè)務(wù)方法關(guān)聯(lián)起來
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    // HandlerAdapter自動(dòng)封裝數(shù)據(jù),SpringMVC框架把注冊表單中用戶名和id分別賦給業(yè)務(wù)方法的形參
    // SpringMVC框架會(huì)根據(jù)請求參數(shù)名和 JavaBean 屬性名進(jìn)行自動(dòng)匹配,也就是這時(shí)候是要求把id和name賦值給形參user對象的屬性
    // 所以把表單的name分別賦值為user對象的屬性名就能完成映射
    public String save(User user){
        System.out.println(user);
        return "index";
    }

如果出現(xiàn)中文亂碼問題,只需在 web.xml 添加 Spring MVC 自帶的過濾器即可亦镶。

<!--    解決中文亂碼問題,使用springmvc提供的過濾器-->
    <filter>
<!--        過濾器名可自定義-->
        <filter-name>encodingFilter</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>encodingFilter</filter-name>
<!--        攔截所有請求-->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

這樣就完成java對象的綁定了

  • jsp頁面的轉(zhuǎn)發(fā)和重定向:
    轉(zhuǎn)發(fā): 服務(wù)器跳轉(zhuǎn),地址欄不變,同一次請求,在請求里傳數(shù)據(jù)在轉(zhuǎn)發(fā)的頁面可以取出
    重定向: 客戶端跳轉(zhuǎn),地址欄改變,相當(dāng)于兩次請求,在請求里傳數(shù)據(jù)在重定向頁面不能取出

Spring MVC 默認(rèn)是以轉(zhuǎn)發(fā)的形式響應(yīng) JSP日月。

1.以轉(zhuǎn)發(fā)形式響應(yīng)頁面

// 轉(zhuǎn)發(fā)形式響應(yīng)頁面(SpringMVC默認(rèn)形式)
    @RequestMapping("/forward")
    public String forward() {
        return "forward:/index.jsp";
        // 等價(jià)于
        // return "index";
    }

2..若想以重定向的形式響應(yīng)

// 重定向形式響應(yīng)頁面
    @RequestMapping("/redirect")
    public String redirect(){
        return "redirect:/index.jsp";
    }

Spring MVC 數(shù)據(jù)綁定

數(shù)據(jù)綁定:在后端的業(yè)務(wù)方法中直接獲取客戶端 HTTP 請求中的參數(shù)(String類型),將請求參數(shù)映射到業(yè)務(wù)方法的形參中缤骨,Spring MVC 中數(shù)據(jù)綁定的工作是由 HandlerAdapter 來完成的爱咬。

  • HTTP請求參數(shù)綁定到基本數(shù)據(jù)類型參數(shù)里
@Controller
@RequestMapping("/data")
public class DataBindHandler {
    @RequestMapping("/baseType")
    @ResponseBody// 不會(huì)把方法返回結(jié)果按照視圖解析器解析,不會(huì)把他映射成jsp頁面,而是把它的值直接返回到客戶端
    public String baseType(Integer id) {
        // 不希望返回的值按照視圖解析,而是把原本值返回到客戶端
        return id + "";
    }
}

添加@ResponseBody注解 表示 Spring MVC 會(huì)直接將業(yè)務(wù)方法的返回值響應(yīng)給客戶端,如果不加 @ResponseBody 注解绊起,Spring MVC 會(huì)將業(yè)務(wù)方法的放回值傳遞給 DispatcherServlet精拟,再由 DisptacherServlet 調(diào)用 ViewResolver 對返回值進(jìn)行解析,映射到一個(gè) JSP 資源。

  • 當(dāng)形參的類型是基本數(shù)據(jù)類型時(shí),但是客戶端發(fā)送請求時(shí)沒有給參數(shù)值,所以此時(shí)形參只能賦null,但是基本數(shù)據(jù)類型不能接收null,所以客戶端會(huì)拋出異常,用包裝類可以解決賦null值的問題,當(dāng)請求中沒傳值也不會(huì)報(bào)錯(cuò)

  • 包裝類

// 包裝類解決業(yè)務(wù)方法傳入null值的問題,解決客戶端拋異常
    @RequestMapping("/package")
    @ResponseBody
    public String packageType(Integer id) {
        return id + "";
    }
包裝類可以接收 null蜂绎,當(dāng) HTTP 請求沒有參數(shù)時(shí)栅表,使用包裝類定義形參的數(shù)據(jù)類型,程序不會(huì)拋出異常师枣。

@RequestParam注解中的幾個(gè)屬性

value = "num":將 HTTP 請求中名為 num 的參數(shù)賦給業(yè)務(wù)方法的形參 id怪瓶。

requried:設(shè)置 num 是否為必填項(xiàng),true 表示必填践美,false 表示非必填洗贰,默認(rèn)是true,可省略。

defaultValue = “0”:如果 HTTP 請求中沒有添加 num 參數(shù)拨脉,默認(rèn)值為0.

  • HTTP請求參數(shù)綁定到數(shù)組中
// 若當(dāng)前Handler類只是對外提供數(shù)據(jù)服務(wù),只返回model,則可以給類添加@RestController
// 若Handler類要返回model和view則只能用@Controller
@RestController// 表示把控制器里所有方法的返回值直接返回到客戶端
@RequestMapping("/data")
public class DataBindHandler {
@RequestMapping("/array")
    // @ResponseBody
    public String array(String[] name) {
        // 遍歷數(shù)組,拼成字符串
        String str = Arrays.toString(name);
        return str;
    }
}
  • @RestController 表示該控制器會(huì)直接將當(dāng)前類的所有業(yè)務(wù)方法的返回值響應(yīng)給客戶端哆姻,不進(jìn)行視圖解析。
  • @Controller 表示該控制器的每一個(gè)業(yè)務(wù)方法的返回值都會(huì)交給視圖解析器進(jìn)行解析玫膀,如果只需要將數(shù)據(jù)響應(yīng)給客戶端矛缨,而不需要進(jìn)行視圖解析,則需要在對應(yīng)的業(yè)務(wù)方法定義處添加 @ResponseBody帖旨。
@RestController// 表示把控制器里所有方法的返回值直接返回到客戶端
@RequestMapping("/data")
public class DataBindHandler {
@RequestMapping("/array")
    // @ResponseBody
    public String array(String[] name) {
        // 遍歷數(shù)組,拼成字符串
        String str = Arrays.toString(name);
        return str;
    }
}

等同于

@Controller// 表示把控制器里所有方法的返回值按視圖解析器解析再返回到客戶端
@RequestMapping("/data")
public class DataBindHandler {
@RequestMapping("/array")
    @ResponseBody
    public String array(String[] name) {
        // 遍歷數(shù)組,拼成字符串
        String str = Arrays.toString(name);
        return str;
    }
}
  • HTTP請求參數(shù)綁定到List集合中

Spring MVC 不支持 List 類型的直接轉(zhuǎn)換箕昭,需要對 List 集合進(jìn)行包裝。相當(dāng)于只能識別實(shí)體類,所以只能把List集合類型作為實(shí)體類的屬性封裝成一個(gè)類

  • 集合封裝類
package com.southwind.entity;

import lombok.Data;

import java.util.List;

@Data
public class UserList {
    private List<User> users;
}
  • JSP表單頁面
<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2021/7/25
  Time: 16:27
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/data/list">
    <%--name屬性不能直接與業(yè)務(wù)方法的userList對象直接映射,而是要和對象的屬性映射
    并且userList的屬性又是集合,所以不能直接與屬性映射,要把input的值賦給集合里的一個(gè)對象的屬性--%>
    用戶1編號: <input type="text" name="users[0].id"><br>
    用戶1名稱: <input type="text" name="users[0].name"><br>
<%--        address級聯(lián)屬性--%>
    用戶1地址: <input type="text" name="users[0].address.value"><br>
    用戶2編號: <input type="text" name="users[1].id"><br>
    用戶2名稱: <input type="text" name="users[1].name"><br>
    用戶3編號: <input type="text" name="users[2].id"><br>
    用戶3名稱: <input type="text" name="users[2].name"><br>
    <input type="submit" value="提交">
</form>

</body>
</html>
  • 業(yè)務(wù)方法
//http請求參數(shù)綁定到List集合中
    // 處理響應(yīng)中文亂碼問題: 通過修改response對象響應(yīng)的編碼,直接在形參里添加response對象,HandlerAdapter自動(dòng)幫你創(chuàng)建
    // Serlvet的jar包在tomcat里,在創(chuàng)建完web工程會(huì)自動(dòng)把tomcat的jar包依賴進(jìn)去,現(xiàn)在maven工程不會(huì)依賴進(jìn)來,所要手動(dòng)導(dǎo)入Servlet包
    // 參數(shù)2: 指定返回的內(nèi)容類型 解阅,僅當(dāng)request請求頭中的(Accept)類型中包含該指定類型才返回落竹;
    // @RequestMapping(value = "/list",produces = "text/html;charset=utf-8;")
    @RequestMapping("/list")
    public String list(UserList userList) {
        // Stringbuffer節(jié)省內(nèi)存資源空間,提高效率,String浪費(fèi)內(nèi)存空間
        StringBuffer str = new StringBuffer();
        for (User user : userList.getUsers()){
            str.append(user);
        }
        return str.toString();
    }
}
  • 處理 @ResponseBody 中文亂碼方式一,在 springmvc.xml 中配置消息轉(zhuǎn)換器货抄。
<!--    通過配置文件方式解決中文亂碼問題,開發(fā)者無需在每個(gè)業(yè)務(wù)方法中處理中文亂碼,
只需交給springmvc同一進(jìn)行管理,業(yè)務(wù)方法返回出去的數(shù)據(jù)會(huì)自動(dòng)在這里處理,相當(dāng)于有反向過濾器的功能-->
<!--    mvc注解驅(qū)動(dòng)-->
    <mvc:annotation-driven>
<!--        消息轉(zhuǎn)換器: 處理由@responseBody注解響應(yīng)頁面的中文亂碼問題,默認(rèn)注冊設(shè)為true-->
        <mvc:message-converters register-defaults="true">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes" value="text/html;charset=utf-8;"></property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

方式二: 直接在@RequestMapping注解添加produces參數(shù)

@RequestMapping(value = "/list",produces = "text/html;charset=utf-8;")
  • HTTP請求綁定數(shù)據(jù)都Map集合
  • 自定義Map集合封裝類
package com.tiga.entity;

import lombok.Data;

import java.util.Map;

/**
 * @author tiga
 */
@Data
public class UserMap {
    private Map<String, User> users;
}
  • 業(yè)務(wù)方法
// http請求參數(shù)綁定到map集合中
    @RequestMapping("/map")
    public String map(UserMap users) {
        StringBuffer str = new StringBuffer();
        for (String key : users.getUsers().keySet()) {
            User user = users.getUsers().get(key);
            str.append(user);// 等同于user.toString(),把user轉(zhuǎn)成String類型加入到str
        }
        return str.toString();
    }
  • jsp頁面
  <%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2021/7/26
  Time: 10:35
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/data/map">
    <%--map集合的value按照key來存儲(chǔ)而不是按照數(shù)組索引,
    也就是不能直接通過索引找到對應(yīng)的value值,
    這里的key值可以隨便定義,因?yàn)楹笈_(tái)會(huì)根據(jù)定義的key取對應(yīng)的value,key定義成什么都不影響取值--%>
    用戶:1 <input type="text" name="users['a'].id"><br>
    用戶:1 <input type="text" name="users['a'].name"><br>
    用戶:1 <input type="text" name="users['a'].address.value"><br>
    用戶:2 <input type="text" name="users['b'].id"><br>
    用戶:2 <input type="text" name="users['b'].name"><br>
    用戶:3 <input type="text" name="users['c'].id"><br>
    用戶:3 <input type="text" name="users['c'].name"><br>
    <input type="submit" value="提交">
</form>
</body>
</html>
  • HTTP請求參數(shù)綁定數(shù)據(jù)到JSON中

客戶端發(fā)送JSON 格式的數(shù)據(jù)述召,直接通過 Spring MVC 綁定到業(yè)務(wù)方法的形參中。
json相當(dāng)于以一個(gè)對象的形式傳過來,這是就需要借助ajax請求去處理

如何使用ajax請求:
1.導(dǎo)入jQuery.js文件到webapp工程下
2.測試jQuery環(huán)境是否能用
剛測試就報(bào)錯(cuò)

image.png

說明當(dāng)前jQuery文件沒有被識別出
通過網(wǎng)絡(luò)監(jiān)聽,發(fā)現(xiàn)jQuery文件找不到,所以加載不出來,這實(shí)際上是springmvc把它攔截了,因?yàn)樵趙eb.xml配置了前置控制器DispatcherSerlvet,而他會(huì)把所有請求攔截,包括加載jQuery.js靜態(tài)資源,但是我們希望只是攔截邏輯請求

類似于:

image.png
image.png

而加載jQuery.js這種靜態(tài)資源,不希望去映射,直接讓他找對應(yīng)物理資源就行了,所以jQuery.js請求不需要被前置控制器攔截,直接在web.xml中單獨(dú)配置直接映射就行了

處理 Spring MVC 無法加載靜態(tài)資源蟹地,在 web.xml 中添加配置即可

<!--    處理springmvc無法加載靜態(tài)資源的問題,各種各樣的資源都這樣處理,jsp除外,他會(huì)自動(dòng)識別-->
    <!-- 手動(dòng)配置,單獨(dú)處理jQuery的請求的映射,默認(rèn)的方式,不交給前置控制器-->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.js</url-pattern>
    </servlet-mapping>

通過javascript發(fā)送json格式數(shù)據(jù),表單是發(fā)送不了的

JSP頁面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
<%--    導(dǎo)入jQuery環(huán)境--%>
    <script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
    <script type="text/javascript">
        // 寫初始化函數(shù)
        $(function (){
            // 發(fā)送json格式數(shù)據(jù),類似于對象的東西
            // 定義一個(gè)json對象
            var user = {
                "id":1,
                "name":"張三"
            };
                // 定義通過jQuery封裝的ajax請求
            $.ajax({
                // 要請求到達(dá)的地址
                url: "/data/json",
                // 把user變量轉(zhuǎn)成json格式
                data: JSON.stringify(user),
                // 請求方式
                type: "POST",
                // 設(shè)置編碼格式,處理中文亂碼
                contentType: "application/JSON;charset=utf-8",
                // ajax接收json數(shù)據(jù)之后轉(zhuǎn)成java對象,再json數(shù)據(jù)的形式再返回
                dataType: "JSON",
                // 回調(diào)函數(shù),形參:后臺(tái)返回的數(shù)據(jù)
                success: function (data) {
                    alert(data.id + "---" + data.name);
                }
            });
        });
    </script>
</head>
<body>

</body>
</html>

Spring MVC 中的 JSON 和 JavaBean 的轉(zhuǎn)換需要借助于 fastjson积暖,pom.xml 引入相關(guān)依賴。

<!--    添加解析json數(shù)據(jù)工具的依賴-->
<!--    把json數(shù)據(jù)轉(zhuǎn)成java對象-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.32</version>
    </dependency>

springmvc.xml 添加 fastjson 配置怪与。

<!--    mvc注解驅(qū)動(dòng)-->
    <mvc:annotation-driven>
<!--        消息轉(zhuǎn)換器: 處理由@responseBody注解響應(yīng)頁面的中文亂碼問題,默認(rèn)注冊設(shè)為true-->
        <mvc:message-converters register-defaults="true">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes" value="text/html;charset=utf-8;"></property>
            </bean>
<!--            在注解驅(qū)動(dòng)里配置fastjson工具-->
            <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"></bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
  • json數(shù)據(jù)轉(zhuǎn)換流程
    前端客戶端把json數(shù)據(jù)傳給后臺(tái),先通過fastjson工具把json數(shù)據(jù)轉(zhuǎn)成java對象傳入到業(yè)務(wù)方法形參,先把fastjson工具的依賴添加到pom.xml中,然后再在springmvc.xml中配置bean對象,配置完后,就可以在業(yè)務(wù)方法接收到j(luò)son數(shù)據(jù),json轉(zhuǎn)成user,方法結(jié)束再返回回前端,又通過fastjson工具把user對象轉(zhuǎn)成json數(shù)據(jù).

Spring MVC 模型數(shù)據(jù)解析

JSP 四大作用域?qū)?yīng)的內(nèi)置對象:pageContext(不常用)夺刑、request(最常用)、session分别、application遍愿。數(shù)據(jù)從后臺(tái)傳到前臺(tái),需要傳遞,所以pageContext基本失效

模型數(shù)據(jù)解析指的是 把模型數(shù)據(jù)綁定到域?qū)ο罄?再從域?qū)ο罄锇延驅(qū)ο髠鞯絡(luò)sp,再從jsp把它解析出來

模型數(shù)據(jù)的綁定是由 ViewResolver 來完成的,實(shí)際開發(fā)中耘斩,我們需要先添加模型數(shù)據(jù)沼填,再交給 ViewResolver 來綁定。

Spring MVC 提供了以下幾種方式添加模型數(shù)據(jù):
往里面添加

  • Map
  • Model
  • ModelAndView

上面三個(gè)都是往request里加

  • @SessionAttribute: 把模型數(shù)據(jù)直接加到Session里
  • @ModelAttribute: 向application添加

將模型數(shù)據(jù)綁定到 request 對象括授。

1.通過Map添加:

// 返回一個(gè)邏輯視圖
    @RequestMapping("/map")
    // 此時(shí)的形參不是用來接收數(shù)據(jù),而是往外傳數(shù)據(jù)的,
    // 這個(gè)map對象實(shí)際上是springmvc框架里BindingAwareModelMap類的map對象
    public String map(Map<String,User> map) {
        User user = new User();
        user.setId(1L);
        user.setName("張三");
        // 向用戶展示一個(gè)視圖,需要user在視圖進(jìn)行展示,這叫模型數(shù)據(jù)解析
        // user對象被傳到框架里的map,所以map里存的就是模型數(shù)據(jù)
        map.put("user", user);// key為 "key" value為 user對象
        // 對象會(huì)自動(dòng)放到request域?qū)ο罄?并會(huì)傳到視圖中,所以在request里取對象就行了
        // 把字符串傳給dispatcherServlet,然后dispatcherServlet再結(jié)合viewResolver就可以進(jìn)行解析了
        // 解析后就可以找到對應(yīng)字符串的jsp頁面,同時(shí)他還會(huì)把模型數(shù)據(jù)加進(jìn)來,他會(huì)把map里的數(shù)據(jù)取出來,通過調(diào)用setAttribute方法
        // 存到request域?qū)ο?jsp頁面存在的request的key和value分別與map的數(shù)據(jù)進(jìn)行對應(yīng),所以在jsp就能直接取出
        return "view";
    }
  • 對應(yīng)jsp頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--解析EL表達(dá)式--%>
<%@page isELIgnored="false" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    ${requestScope.user}
</body>
</html>

2.通過Model添加:

// model添加模型數(shù)據(jù)
    @RequestMapping("/model")
    public String model(Model model) {
        User user = new User();
        user.setId(2L);
        user.setName("李四");
        // 添加到model中
        model.addAttribute("user", user);
        // 返回視圖后會(huì)把model里的數(shù)據(jù)存到request對象對應(yīng)的值
        return "view";
    }
  • jsp頁面同上

3.通過ModelAndView添加到request對象:

  // 上面之前的model和view是分開的,model是存到map或model對象里,view是直接返回的
    // 所謂modelandview就是把view和model裝到一塊,然后把這完整對象進(jìn)行返回
    // ModelAndView添加數(shù)據(jù)
    @RequestMapping("/modelAndView")
    public ModelAndView modelAndView() {
        User user = new User();
        user.setId(3L);
        user.setName("王五");
        // 創(chuàng)建一個(gè)modelAndview對象
        ModelAndView modelAndView = new ModelAndView();
        // 把model和view整合到對象中
        modelAndView.setViewName("view");
        modelAndView.addObject("user", user);
        // 直接返回對象
        return modelAndView;
    }

    // ModelAndView添加數(shù)據(jù)2
    @RequestMapping("/modelAndView2")
    public ModelAndView modelAndView2() {
        User user = new User();
        user.setId(4l);
        user.setName("孫七");
        // 創(chuàng)建modelAndView對象
        ModelAndView modelAndView = new ModelAndView();
        // 對象中添加模型
        modelAndView.addObject("user", user);
        // 創(chuàng)建一個(gè)View視圖對象,傳入視圖信息,形參傳入目標(biāo)物理視圖路徑
        View view = new InternalResourceView("/view.jsp");
        // 對象中添加視圖
        modelAndView.setView(view);
        return modelAndView;
    }

    // ModelAndView添加數(shù)據(jù)3
    @RequestMapping("/modelAndView3")
    public ModelAndView modelAndView3() {
        User user = new User();
        user.setId(5l);
        user.setName("周八");
        // 創(chuàng)建modelAndeView對象并傳入目標(biāo)物理視圖名字
        ModelAndView modelAndView = new ModelAndView("view");
        // 只需要給對象添加模型就行
        modelAndView.addObject("user", user);
        return modelAndView;
    }

    // ModelAndView添加數(shù)據(jù)4
    @RequestMapping("/modelAndView4")
    public ModelAndView modelAndView4() {
        User user = new User();
        user.setId(5l);
        user.setName("周八");
        // 創(chuàng)建view對象,添加目標(biāo)物理視圖路徑
        View view = new InternalResourceView("/view.jsp");
        // 把view對象傳入到modelAndView對象中
        ModelAndView modelAndView = new ModelAndView(view);
        // modelAndView添加模型
        modelAndView.addObject("user", user);
        return modelAndView;
    }

    // ModelAndView添加數(shù)據(jù)5
    @RequestMapping("/modelAndView5")
    public ModelAndView modelAndView5() {
        User user = new User();
        user.setId(5l);
        user.setName("周八");
        // 創(chuàng)建一個(gè)map集合,把model存到map集合中
        Map<String, User> map = new HashMap<>();
        map.put("user", user);
        ModelAndView modelAndView = new ModelAndView("view", map);
        return modelAndView;
    }

    // ModelAndView添加數(shù)據(jù)6
    @RequestMapping("/modelAndView6")
    public ModelAndView modelAndView6() {
        User user = new User();
        user.setId(5l);
        user.setName("周八");
        Map<String, User> map = new HashMap<>();
        map.put("user", user);
        View view = new InternalResourceView("/view.jsp");
        ModelAndView modelAndView = new ModelAndView(view, map);
        return modelAndView;
    }

    // ModelAndView添加數(shù)據(jù)7
    @RequestMapping("/modelAndView7")
    public ModelAndView modelAndView7() {
        User user = new User();
        user.setId(5l);
        user.setName("周八");
        // 創(chuàng)建modelAndView對象,構(gòu)造器傳入視圖名,model的key,model的value
        ModelAndView modelAndView = new ModelAndView("view", "user", user);
        return modelAndView;
    }

    // ModelAndView添加數(shù)據(jù)8
    @RequestMapping("/modelAndView8")
    public ModelAndView modelAndView8() {
        User user = new User();
        user.setId(5l);
        user.setName("周八");
        View view = new InternalResourceView("/view.jsp");
        ModelAndView modelAndView = new ModelAndView(view, "user", user);
        return modelAndView;     
    }

4.可以向原生的HttpServletRequest直接添加:

直接向HttpServletRequest添加數(shù)據(jù),上面都是間接向視圖里的request域?qū)ο筇砑訑?shù)據(jù)
// 直接向HttpServletRequest添加數(shù)據(jù),上面都是間接向視圖里的request域?qū)ο筇砑訑?shù)據(jù)
    @RequestMapping("/request")
    // 要用什么對象,直接在形參中寫出來,springmvc框架會(huì)自動(dòng)幫我們創(chuàng)建
    public String request(HttpServletRequest request) {
        User user = new User();
        user.setId(5l);
        user.setName("周八");
        // 把模型數(shù)據(jù)裝到視圖里的request域?qū)ο笾?        request.setAttribute("user", user);
        return "view";
    }

5.@ModelAttribute

  • 定義一個(gè)方法坞笙,該方法專門用來返回要填充到模型數(shù)據(jù)中的對象轧邪。
// @ModelAttribute注解添加模型數(shù)據(jù)
    @ModelAttribute// 這個(gè)注解描述的方法會(huì)優(yōu)先業(yè)務(wù)方法的執(zhí)行,這時(shí)候就不需要在業(yè)務(wù)方法里處理模型數(shù)據(jù)
    // 無論在調(diào)用哪個(gè)業(yè)務(wù)方法之前一定會(huì)執(zhí)行@ModelAttribute描述的方法
    public User getUser() {
        User user = new User();
        user.setId(1l);
        user.setName("張三");
        // 若要框架處理模型數(shù)據(jù),就必須return,若不return,
        // 就要手動(dòng)處理,方法返回值為void,通過給方法添加形參,
        // 在方法中處理模型數(shù)據(jù)
        return user;
    }
  • 方式2:在方法中處理模型數(shù)據(jù),沒有返回值,給方法添加形參
@ModelAttribute
    public void getUser(Map<String, User> map) {
        User user = new User();
        user.setId(1l);
        user.setName("張三");
        map.put("user", user);
    }
@ModelAttribute
    public void getUser(Model model) {
        User user = new User();
        user.setId(1l);
        user.setName("張三");
        model.addAttribute("user", user);
    }
  • 業(yè)務(wù)方法中無需再處理模型數(shù)據(jù),只需返回視圖即可羞海。
// 只需返回視圖.無需處理模型數(shù)據(jù)
    @RequestMapping("/modelAttribute")
    // 調(diào)用業(yè)務(wù)方法之前,會(huì)先執(zhí)行@ModelAttribute描述的方法并返回對象,
    // 返回的對象作為當(dāng)前業(yè)務(wù)方法的模型數(shù)據(jù),所以在業(yè)務(wù)方法中就無需處理模型了,只需返回視圖即可
    public String modelAttribute() {
        return "view";
    }

將模型數(shù)據(jù)綁定到 session 對象

1.直接向Session域?qū)ο筇砑訑?shù)據(jù)

// 原生方式向session里添加數(shù)據(jù),和向request類似,session對象是從request對象中取出
    // 由于上面方法@ModelAttribute注解的原因,執(zhí)行業(yè)務(wù)方法之前,request域?qū)ο缶鸵呀?jīng)先獲取到模型數(shù)據(jù)了,
    // 所以session域?qū)ο笫橇硗庵匦芦@取模型數(shù)據(jù)的
    @RequestMapping("/session")
    public String session(HttpServletRequest request) {
        HttpSession session = request.getSession();
        User user = new User();
        user.setId(1l);
        user.setName("張三");
        session.setAttribute("user", user);
        return "view";
    }

    // 直接讓框架創(chuàng)建好session域?qū)ο?直接獲取session,不通過request間接獲取session
    // 直接在方法形參添加session對象,
    @RequestMapping("/session2")
    public String session2(HttpSession session) {
        User user = new User();
        user.setId(1l);
        user.setName("張三");
        session.setAttribute("user", user);
        return "view";
    }

2.@SessionAttributes注解添加模型數(shù)據(jù)到session域?qū)ο?br> 支持同時(shí)添加多個(gè)value值

// 對所有業(yè)務(wù)方法生效,只要是業(yè)務(wù)方法中對注解參數(shù)值進(jìn)行操作模型數(shù)據(jù)添加到request域?qū)ο笾?他就會(huì)自動(dòng)把模型數(shù)據(jù)加到session域?qū)ο笾?// 注解的value值與添加到模型里的key值對應(yīng)
// @SessionAttributes(value = "user")
@SessionAttributes(value = {"user","address"})
public class ViewHandler {
}

對于 ViewHandler 中的所有業(yè)務(wù)方法忌愚,只要向 request 對象中添加了 key = "user"、key = "address" 的對象時(shí)却邓,Spring MVC 會(huì)自動(dòng)將該數(shù)據(jù)添加到 session 中硕糊,保存 key 不變。

// 在任何業(yè)務(wù)方法里,只要注解參數(shù)對應(yīng)類型的對象添加到域?qū)ο罄?就自動(dòng)加到session域?qū)ο笾?//@SessionAttributes(types = User.class) // 針對全局的,盡量不用,因?yàn)榇蠖嗲闆r下只需向request添加而不需向session添加數(shù)據(jù)
@SessionAttributes(types = {User.class,Address.class})
public class ViewHandler {
}

對于 ViewHandler 中的所有業(yè)務(wù)方法腊徙,只要向 request 對象中添加了數(shù)據(jù)類型是 User 简十、Address 的對象時(shí),Spring MVC 會(huì)自動(dòng)將該數(shù)據(jù)添加到 session 中撬腾,保存 key 不變螟蝙。

將模型數(shù)據(jù)綁定到 application 對象,通過request間接綁定

// 向application添加模型數(shù)據(jù)
    @RequestMapping("/application")
    // 因?yàn)镾ervletContext類沒有提供無參構(gòu)造器,所以HandlerAdapter不能創(chuàng)建application對象
    public String application(HttpServletRequest request) {
        ServletContext application = request.getSession().getServletContext();
        User user = new User();
        user.setId(1l);
        user.setName("張三");
        application.setAttribute("user", user);
        return "view";
    }

Spring MVC 自定義數(shù)據(jù)轉(zhuǎn)換器

數(shù)據(jù)轉(zhuǎn)換器是指將客戶端 HTTP 請求中的參數(shù)轉(zhuǎn)換為業(yè)務(wù)方法中定義的形參,自定義表示開發(fā)者可以自主設(shè)計(jì)轉(zhuǎn)換的方式民傻,HandlerApdter 已經(jīng)提供了通用的轉(zhuǎn)換胰默,String 轉(zhuǎn) int,String 轉(zhuǎn) double漓踢,表單數(shù)據(jù)的封裝等牵署,但是在特殊的業(yè)務(wù)場景下,HandlerAdapter 無法進(jìn)行轉(zhuǎn)換喧半,就需要開發(fā)者自定義轉(zhuǎn)換器奴迅。

  • 比如把String類型轉(zhuǎn)換成日期類型

客戶端輸入 String 類型的數(shù)據(jù) "2020-03-03",自定義轉(zhuǎn)換器將該數(shù)據(jù)轉(zhuǎn)為 Date 類型的對象挺据。

  • 創(chuàng)建 DateConverter 轉(zhuǎn)換器取具,實(shí)現(xiàn) Conveter 接口。實(shí)現(xiàn)接口就變成了控制器,若不實(shí)現(xiàn)就只是普通類.
// 如何做到,傳入數(shù)據(jù)為String類型,傳出類型為Date類型
// 直接在實(shí)現(xiàn)接口處指定傳入傳出泛型來規(guī)定轉(zhuǎn)換和被轉(zhuǎn)換類型
public class DataConverter implements Converter<String, Date> {
    // 定義要轉(zhuǎn)換日期的格式的變量
    String pattern = null;// 按照怎么樣的格式轉(zhuǎn)換
    // 需要通過框架傳入到構(gòu)造方法中,SpringIOC容器實(shí)例DataConverter的對象,就把在springmvc.xml中配置的日期格式傳入,通過有參構(gòu)造器來創(chuàng)建
    // 規(guī)定要轉(zhuǎn)換前日期的格式
    public DataConverter(String pattern) {
        // 從外面?zhèn)魅胍D(zhuǎn)換的日期格式,通過bean配置property傳入
        this.pattern = pattern;
    }
    // 轉(zhuǎn)換方法
    @Override
    public Date convert(String s) {
        // 創(chuàng)建數(shù)據(jù)轉(zhuǎn)換工具對象,把日期轉(zhuǎn)換前的格式類型傳入轉(zhuǎn)換工具對象
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(this.pattern);
        Date date = null;
        try {
            // 調(diào)用工具類的解析方法把要轉(zhuǎn)換的字符串傳入,生成一個(gè)日期對象
            date = simpleDateFormat.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        // 返回日期對象
        return date;
    }
}
  • springmvc.xml 配置轉(zhuǎn)換器扁耐。
<!--    配置自定義轉(zhuǎn)換器 bean 對象-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<!--        定義屬性 name屬性是converters,因?yàn)樽远x轉(zhuǎn)換不僅僅是一個(gè),可以配置多個(gè)-->
        <property name="converters">
<!--            因?yàn)榭梢耘渲枚鄠€(gè),所以一集合形式配合-->
            <list>
<!--                配置的轉(zhuǎn)換器的bean就是我們自定義的轉(zhuǎn)換器類-->
                <bean class="com.tiga.converter.DataConverter">
<!--                    配置有參構(gòu)造器參數(shù),配置日期轉(zhuǎn)換前的格式,value: 要轉(zhuǎn)換的日期格式-->
                    <constructor-arg type="java.lang.String" value="YYYY-MM-DD"></constructor-arg>
                </bean>
            </list>
        </property>
    </bean>
<!--    在mvc注解驅(qū)動(dòng)中注冊轉(zhuǎn)換器服務(wù),配置轉(zhuǎn)換器的id-->
    <mvc:annotation-driven conversion-service="conversionService">
<!--        消息轉(zhuǎn)換器: 處理由@responseBody注解響應(yīng)頁面的中文亂碼問題,默認(rèn)注冊設(shè)為true-->
        <mvc:message-converters register-defaults="true">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes" value="text/html;charset=utf-8;"></property>
            </bean>
<!--            在注解驅(qū)動(dòng)里配置fastjson工具-->
            <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"></bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

也可以不配置轉(zhuǎn)換,直接

寫成simpledataformat sd=new simple data format(“yyyy-MM-dd”) 這樣就不用配置了

  • jsp頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/converter/date" method="post">
<%--    name屬性和轉(zhuǎn)換數(shù)據(jù)業(yè)務(wù)方法的形參名對應(yīng)--%>
    轉(zhuǎn)換日期: <input type="text" name="date">(yyyy-MM-dd)
    <br>
    <input type="submit" value="提交">
</form>
</body>
</html>

控制器類

@RestController// 直接返回?cái)?shù)據(jù)不通過視圖解析器解析
@RequestMapping("/converter")
public class ConverterHandler {
    @RequestMapping("/date")
    public String date(Date date) {
        return date.toString();
    }
}
  • String轉(zhuǎn)成自定義類型
String轉(zhuǎn)Student

StudentConverter(學(xué)生轉(zhuǎn)換類)

public class StudentConverter implements Converter<String, Student> {
    @Override
    public Student convert(String s) {
        // 通過參數(shù)中給定的字符將字符串分割成數(shù)組
        String[] args = s.split("-");
        // 創(chuàng)建學(xué)生對象
        Student student = new Student();
        // 把jsp獲取到的參數(shù)添加到學(xué)生對象中
        student.setId(Long.parseLong(args[0]));
        student.setName(args[1]);
        student.setAge(Integer.parseInt(args[2]));
        return student;
    }
}
  • 配置springmvc.xml
<!--    配置自定義轉(zhuǎn)換器 bean 對象-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<!--        定義屬性 name屬性是converters,因?yàn)樽远x轉(zhuǎn)換不僅僅是一個(gè),可以配置多個(gè)-->
        <property name="converters">
<!--            因?yàn)榭梢耘渲枚鄠€(gè),所以一集合形式配合-->
            <list>
<!--                配置的轉(zhuǎn)換器的bean就是我們自定義的轉(zhuǎn)換器類-->
                <bean class="com.tiga.converter.DataConverter">
<!--                    配置有參構(gòu)造器參數(shù),配置日期轉(zhuǎn)換前的格式,value: 要轉(zhuǎn)換的日期格式-->
                    <constructor-arg type="java.lang.String" value="YYYY-MM-DD"></constructor-arg>
                </bean>
<!--                配置Student轉(zhuǎn)換器,通過空參構(gòu)造器創(chuàng)建StudentConverter對象,無需配置構(gòu)造器參數(shù)-->
                <bean class="com.tiga.converter.StudentConverter">
                </bean>
            </list>
        </property>
    </bean>

<!--    在mvc注解驅(qū)動(dòng)中注冊轉(zhuǎn)換器服務(wù),配置轉(zhuǎn)換器的id-->
    <mvc:annotation-driven conversion-service="conversionService">
<!--        消息轉(zhuǎn)換器: 處理由@responseBody注解響應(yīng)頁面的中文亂碼問題,默認(rèn)注冊設(shè)為true-->
        <mvc:message-converters register-defaults="true">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes" value="text/html;charset=utf-8;"></property>
            </bean>
<!--            在注解驅(qū)動(dòng)里配置fastjson工具-->
            <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"></bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
  • jsp頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%--    按照規(guī)定格式輸入學(xué)生信息,轉(zhuǎn)成Student類型--%>
<form action="/converter/student" method="post">
<%--    name屬性和轉(zhuǎn)換數(shù)據(jù)業(yè)務(wù)方法的形參名對應(yīng)--%>
    請輸入學(xué)生信息: <input type="text" name="student">(id-name-age)
    <input type="submit" value="提交">
</form>
</body>
</html>
  • Handler
@RestController// 直接返回?cái)?shù)據(jù)不通過視圖解析器解析
@RequestMapping("/converter")
public class ConverterHandler {
@RequestMapping("/student")
    public String student(Student student) {
        return student.toString();
    }

Spring MVC REST

REST:Representational State Transfer暇检,資源表現(xiàn)層狀態(tài)轉(zhuǎn)換,是目前比較主流的一種互聯(lián)網(wǎng)軟件架構(gòu)做葵,它結(jié)構(gòu)清晰占哟、標(biāo)準(zhǔn)規(guī)范心墅、易于理解酿矢、便于擴(kuò)展。指的是不同服務(wù)之間相互訪問的一種方式,兩個(gè)不同的服務(wù)之間訪問,只需要給他規(guī)定一個(gè)統(tǒng)一標(biāo)準(zhǔn),兩個(gè)服務(wù)按照這種標(biāo)準(zhǔn)就可以進(jìn)行交互了

  • 資源(Resource)

網(wǎng)絡(luò)上的一個(gè)實(shí)體怎燥,或者說網(wǎng)絡(luò)中存在的一個(gè)具體信息瘫筐,一段文本、一張圖片铐姚、一首歌曲策肝、一段視頻等等肛捍,總之就是一個(gè)具體的存在≈冢可以用一個(gè) URI(統(tǒng)一資源定位符)指向它拙毫,每個(gè)資源都有對應(yīng)的一個(gè)特定的 URI,要獲取該資源時(shí)棺禾,只需要訪問對應(yīng)的 URI 即可缀蹄。

  • 表現(xiàn)層(Representation)

資源具體呈現(xiàn)出來的形式,比如文本可以用 txt 格式表示膘婶,也可以用 HTML缺前、XML、JSON等格式來表示悬襟。同一個(gè)資源可以用不同形式來表示.

  • 狀態(tài)轉(zhuǎn)換(State Transfer)
    每發(fā)出一次請求就表示客戶端和服務(wù)器進(jìn)行的一次交互,http協(xié)議是無狀態(tài)的協(xié)議,所以所有的狀態(tài)都保存在服務(wù)端,因此,若客戶端想操作服務(wù)端,就必須通過某種手段,讓服務(wù)端發(fā)生狀態(tài)轉(zhuǎn)換

客戶端如果希望操作服務(wù)器中的某個(gè)資源衅码,就需要通過某種方式讓服務(wù)端發(fā)生狀態(tài)轉(zhuǎn)換,而這種轉(zhuǎn)換是建立在表現(xiàn)層之上的脊岳,所有叫做"表現(xiàn)層狀態(tài)轉(zhuǎn)換"逝段。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市割捅,隨后出現(xiàn)的幾起案子惹恃,更是在濱河造成了極大的恐慌,老刑警劉巖棺牧,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巫糙,死亡現(xiàn)場離奇詭異,居然都是意外死亡颊乘,警方通過查閱死者的電腦和手機(jī)参淹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乏悄,“玉大人浙值,你說我怎么就攤上這事¢菪。” “怎么了开呐?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長规求。 經(jīng)常有香客問我筐付,道長,這世上最難降的妖魔是什么阻肿? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任瓦戚,我火速辦了婚禮,結(jié)果婚禮上丛塌,老公的妹妹穿的比我還像新娘较解。我一直安慰自己畜疾,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布印衔。 她就那樣靜靜地躺著啡捶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪奸焙。 梳的紋絲不亂的頭發(fā)上届慈,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機(jī)與錄音忿偷,去河邊找鬼金顿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鲤桥,可吹牛的內(nèi)容都是我干的揍拆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼茶凳,長吁一口氣:“原來是場噩夢啊……” “哼嫂拴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起贮喧,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤筒狠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后箱沦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辩恼,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年谓形,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了灶伊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寒跳,死狀恐怖聘萨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情童太,我是刑警寧澤米辐,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站书释,受9級特大地震影響翘贮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜征冷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一择膝、第九天 我趴在偏房一處隱蔽的房頂上張望誓琼。 院中可真熱鬧检激,春花似錦肴捉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至饺律,卻和暖如春窃页,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背复濒。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工脖卖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人巧颈。 一個(gè)月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓畦木,卻偏偏與公主長得像,于是被迫代替她去往敵國和親砸泛。 傳聞我的和親對象是個(gè)殘疾皇子十籍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

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

  • SpringMVC的工作原理圖: SpringMVC原理 用戶發(fā)送請求至前端控制器DispatcherServle...
    4553675200ad閱讀 785評論 0 4
  • SpringMVC的工作原理圖: SpringMVC流程 1、 用戶發(fā)送請求至前端控制器DispatcherSer...
    怪瘦Java閱讀 200評論 0 0
  • springmvc是什么 Spring Web MVC是一種基于Java的實(shí)現(xiàn)了Web MVC設(shè)計(jì)模式的請求驅(qū)動(dòng)類...
    無量散人閱讀 696評論 0 1
  • 三層架構(gòu) 和 MVC模型 三層架構(gòu):我們在Servlet 學(xué)習(xí)筆記講過唇礁,當(dāng)前 Web 應(yīng)用體系主要為 C/S架構(gòu) ...
    Whyn閱讀 514評論 0 0
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月勾栗,有人笑有人哭,有人歡樂有人憂愁盏筐,有人驚喜有人失落围俘,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,528評論 28 53