JavaWeb了解之SpringMVC篇1

目錄
  前言
    1. MVC架構模式
    2. 三層架構
    3. SpringMVC
  1. 第一個SpringMVC項目(Hello World)
  2. 獲取請求參數(shù)
  3. 在域?qū)ο螅╮equest碑幅、session走趋、application)中共享數(shù)據(jù)
  4. 視圖和視圖解析器
  5. RESTful(REST風格)
  6. Converter類型轉(zhuǎn)換器
  7. Formatter格式化器
  8. json數(shù)據(jù)轉(zhuǎn)換(Java對象<--轉(zhuǎn)換-->json數(shù)據(jù))

SpringMVC:Spring提供的基于MVC設計模式的輕量級Web開發(fā)框架(本質(zhì):對Servlet的進一步封裝)师逸。

前言

  1. MVC(Model-View-Controller奏司,模型-視圖-控制器)

是一種架構模式坷虑,將界面和業(yè)務邏輯分離卸察,使代碼具有更高的可擴展性既忆、可復用性柠座、可維護性以及靈活性邑雅。

1. Model(模型層)  應用的主體部分,由以下2部分組成:
  1. 實體類Bean(通常與數(shù)據(jù)庫中的某個表對應)
    用于存儲業(yè)務數(shù)據(jù)妈经。
  2. 業(yè)務處理Bean(Service淮野、Dao)
    用于處理業(yè)務邏輯、數(shù)據(jù)庫訪問吹泡。
2. View(視圖層)    
  (由HTML骤星、JSP、CSS荞胡、JavaScript等組成)頁面妈踊,負責用戶交互、展示數(shù)據(jù)泪漂。
3. Controller(控制器)  
  通常為Servlet廊营,負責接收用戶請求(讓模型層處理數(shù)據(jù),并將處理好的數(shù)據(jù)傳給視圖層萝勤,展示最終的頁面給用戶)露筒。 
  本身并不做任何業(yè)務處理,只負責調(diào)度View層和Model層敌卓。
基于MVC的Web應用
大致工作流程如下:
  1. 用戶發(fā)送請求到服務器慎式。若請求路徑與web.xml中配置的DispatcherServlet前端控制器的url-pattern相匹配,則該請求會被DispatcherServlet攔截趟径。
  2. DispatcherServlet會讀取SpringMVC.xml配置文件瘪吏,通過組件掃描獲取到所有的Controller控制器。將請求信息和所有控制器方法標識的@RequestMapping注解的value蜗巧、method等屬性值進行匹配掌眠,若匹配成功則將請求交給對應控制器方法進行處理。
  3. 控制器方法中調(diào)用相應的Model層處理請求幕屹,Model層處理完后將結果(模型數(shù)據(jù))返回到控制器方法蓝丙。
  5. 控制器方法返回一個字符串類型的邏輯視圖名级遭,會被視圖解析器轉(zhuǎn)為真正的視圖,并將模型數(shù)據(jù)渲染到視圖中返回給用戶渺尘。

優(yōu)點
  1. 降低代碼耦合性
    在MVC模式中挫鸽,三層之間相互獨立、各司其職鸥跟。
    一旦某一層的需求發(fā)生了變化丢郊,只需要更改相應層中的代碼即可,而不會對其他層中的代碼造成影響医咨。
  2. 有利于分工合作
    在MVC模式中蚂夕,將應用劃分成三層,可以更好地實現(xiàn)開發(fā)分工(前端專注于視圖層腋逆、熟悉業(yè)務的后臺開發(fā)Model層、不熟悉業(yè)務的后臺開發(fā)Controller層)侈贷。
  3. 提高可重用性
    在MVC模式中惩歉,多個視圖可以共享同一個模型。

缺點
  1. 增加了系統(tǒng)結構和實現(xiàn)的復雜性
    對于簡單的應用俏蛮,如果也嚴格遵循MVC模式撑蚌,按照模型、視圖與控制器對系統(tǒng)進行劃分搏屑,會增加系統(tǒng)結構的復雜性争涌,并可能產(chǎn)生過多的更新操作,降低運行效率辣恋。因此亮垫,并不適合中小型項目。
  2. 視圖與控制器間的聯(lián)系過于緊密
    雖然視圖與控制器是相互分離的伟骨,但它們之間聯(lián)系卻是十分緊密的饮潦。視圖沒有控制器的存在,其應用是很有限的携狭,反之亦然继蜡,這樣就妨礙了它們的獨立重用。
  3. 視圖對模型數(shù)據(jù)的低效率訪問
    視圖可能需要多次調(diào)用才能獲得足夠的顯示數(shù)據(jù)逛腿。
    對未變化數(shù)據(jù)的不必要的頻繁訪問稀并,也將損害操作性能。
  1. 三層架構
1. 表示層(UI)相當于:MVC模式的View層+Controller層
  負責用戶交互单默、展示數(shù)據(jù)碘举、接收用戶請求,將請求交給業(yè)務邏輯層(BLL)和數(shù)據(jù)訪問層(DAL)進行處理雕凹,把處理好的數(shù)據(jù)傳給頁面并展示給用戶殴俱。

2. 業(yè)務邏輯層(BLL)相當于:MVC模式的Model層的一部分(不包含Dao和實體類)
  起到承上啟下的作用政冻,接收表示層傳遞來的請求,根據(jù)業(yè)務對數(shù)據(jù)進行處理线欲。

3. 數(shù)據(jù)訪問層(DAL)相當于:MVC模式的Model層的一部分(只包含了Dao接口及實現(xiàn))
  用于實現(xiàn)數(shù)據(jù)庫訪問(增刪改查等操作)明场。
基于三層架構的Web應用
  1. SpringMVC

Spring提供的基于MVC設計模式的輕量級Web開發(fā)框架(為表示層開發(fā)提供的一整套完備的解決方案)。

工作流程
  1. 用戶通過瀏覽器發(fā)起一個HTTP請求李丰,該請求會被DispatcherServlet(前端控制器)攔截苦锨;
  2. DispatcherServlet會調(diào)用HandlerMapping(處理器映射器);
  3. HandlerMapping負責找到具體的處理器(Handler)及攔截器趴泌,并以HandlerExecutionChain執(zhí)行鏈的形式返回給DispatcherServlet舟舒。
  4. DispatcherServlet將執(zhí)行鏈返回的Handler信息發(fā)送給HandlerAdapter(處理器適配器);
  5. HandlerAdapter根據(jù)Handler信息找到并執(zhí)行相應的Handler(即:控制器方法)對請求進行處理;
  6. Handler執(zhí)行完后會將一個ModelAndView對象(SpringMVC的底層對象沾乘,包括Model數(shù)據(jù)模型和View視圖信息)返回給HandlerAdapter歪架。
  7. HandlerAdapter接收到ModelAndView對象返回給DispatcherServlet。
  8. DispatcherServlet接收到ModelAndView對象后夺鲜,會請求ViewResolver(視圖解析器)對視圖進行解析;
  9. ViewResolver解析完成后呐舔,會將View視圖并返回給DispatcherServlet币励;
  10. DispatcherServlet接收到具體的View視圖后,進行視圖渲染珊拼,將Model中的模型數(shù)據(jù)填充到View視圖中的request域食呻,生成最終的View(視圖);
  11. 視圖負責將結果顯示到瀏覽器(客戶端)澎现。

特點
  1. SpringMVC是Spring框架的子框架(可以與IoC容器等Spring其他功能無縫對接)仅胞。
  2. SpringMVC支持各種視圖技術(如:JSP、Thymeleaf剑辫、FreeMaker等)饼问。 
  3. SpringMVC基于原生的Servlet實現(xiàn)(通過功能強大的前端控制器DispatcherServlet,對請求和響應進行統(tǒng)一處理)揭斧。
  4. SpringMVC對表示層各細分領域需要解決的問題全方位覆蓋莱革,并提供一整套全面的解決方案。
  5. 代碼簡潔讹开,提高開發(fā)效率盅视。
  6. 采用松耦合、可插拔的組件結構(即插即用:想使用什么功能就配置相應組件)旦万。高度可配置性闹击、擴展性、靈活性成艘。
  7. 性能卓著赏半,適合大型贺归、超大型互聯(lián)網(wǎng)項目的開發(fā)。
  8. 支持注解断箫、REST風格拂酣。
SpringMVC工作流程
常用組件 提供者 描述
DispatcherServlet 框架 前端控制器(最核心的組件,本質(zhì)是一個Servlet)仲义,負責統(tǒng)一處理和分發(fā)請求婶熬。SpringMVC的流程控制中心,控制整個流程的執(zhí)行埃撵,對各個組件進行統(tǒng)一調(diào)度(降低組件之間的耦合性赵颅,有利于組件之間的拓展)。
HandlerMapping 框架 處理器映射器暂刘,根據(jù)請求的url饺谬、method等信息查找相應的Handler(即控制器方法)。
Handler 開發(fā)員 處理器(Controller控制器方法)谣拣,對用戶的請求進行處理商蕴。
HandlerAdapter 框架 處理器適配器,調(diào)用(根據(jù)HandlerMapping找到的Handler處理器的)具體的控制器方法芝发。
ViewResolver 框架 視圖解析器(常用:ThymeleafViewResolver、InternalResourceViewResolver)苛谷,通過ModelAndView對象中的View信息將邏輯視圖名解析為真正的視圖View辅鲸。
View 開發(fā)員 視圖(View對象本身由框架提供,但視圖所對應的前端頁面需要開發(fā)員編寫)腹殿,將Model模型數(shù)據(jù)通過頁面展示給用戶独悴。

可以看到,開發(fā)人員只需負責創(chuàng)建:控制器(及控制器方法)锣尉、html頁面刻炒。

1. 第一個SpringMVC項目(Hello World)

1. 創(chuàng)建JavaWeb項目(Dynamic Web Project)
  選擇Target runtime選項:設置本地的Tomcat服務器版本和JDK版本。
Eclipse左側(cè)工具欄自沧,點右鍵->New->Dynamic Web Project

填寫項目名坟奥,點擊Target runtime選項

配置Target runtime

配置Target runtime之后

勾選自動生成web.xml,點擊Finish創(chuàng)建項目

項目結構
2. 添加依賴包(到webapp/WEB-INF/lib目錄下)
  Spring框架相關
    1. 核心容器模塊的4個依賴包(core拇厢、beans爱谁、context、expression)孝偎、commons-logging-xxx.jar
    2. AOP依賴包(spring-webmvc-aop.jar)
    3. SpringMVC依賴包(spring-web-xxx.jar访敌、spring-webmvc-xxx.jar)
  Thymeleaf(該技術用于取代jsp)相關
    1. attoparser-xxx.jar
    2. slf4j-api-xxx.jar
    3. thymeleaf-xxx.jar
    4. thymeleaf-spring5-xxx.jar
    5. unbescape-xxx.jar

下載attoparser-xxx.jarslf4j-api-xxx.jar衣盾、thymeleaf-xxx.jar寺旺、thymeleaf-spring5-xxx.jar爷抓、unbescape-xxx.jar

3. 配置DispatcherServlet(在web.xml配置文件中)
    <!-- 配置SpringMVC的前端控制器(攔截用戶的所有請求,進行統(tǒng)一處理) -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 
            配置SpringMVC配置文件的位置和名稱(當配置文件不在WEB-INF目錄下時需要配置)阻塑。項目啟動時默認會從WEB-INF目錄下尋找配置文件蓝撇,默認的命名規(guī)則為{servlet-name}-servlet.xml。
        -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springMVC.xml</param-value>
        </init-param>
        <!-- 
            如果希望項目啟動時就加載并初始化該Servlet時 配置叮姑。 默認情況下唉地,所有的Servlet(包括DispatcherServlet)都是在第一次調(diào)用時才會被加載(降低了項目啟動時間,但增加了用戶第一次請求所需的時間)传透。 
            load-on-startup元素取值規(guī)則如下: 
                1. 取值必須是一個整數(shù)耘沼; 
                2. 當值小于0或者沒有指定時,則表示容器在該Servlet被首次請求時才會被加載朱盐; 
                3. 當值大于0或等于0時群嗤,表示容器在項目啟動時就加載并初始化該Servlet,取值越小優(yōu)先級越高兵琳; 
                4. 當取值相同時狂秘,容器就會自行選擇順序進行加載。 
        -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <!--
            設置springMVC的前端控制器所能處理(攔截)的請求的請求路徑躯肌。 
            /會攔截所有請求(除了.jsp)者春。
        -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
4. 創(chuàng)建springMVC.xml配置文件(src目錄下)
  web.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
       https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 開啟組件掃描(會掃描包路徑下的所有控制器類清女,包括子包) -->
    <context:component-scan base-package="com.sst.cx"></context:component-scan>
    <!-- 配置Thymeleaf視圖解析器(配置為:映射到/WEB-INF/templates/目錄下的.html文件) -->
    <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="order" value="1"/>
        <property name="characterEncoding" value="UTF-8"/>
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                        <!-- 視圖前綴 -->
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        <!-- 視圖后綴 -->
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/>
                        <property name="characterEncoding" value="UTF-8"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
</beans>
5. 創(chuàng)建Controller
  在com.sst.cx.controller下創(chuàng)建HelloController.java

package com.sst.cx.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
    @RequestMapping("/")    
    public String sayHello() {
        // 邏輯視圖名钱烟,真正的視圖為:視圖前綴+index+視圖后綴(即:/WEB-INF/template/index.html)
        return "index";
    }
}

說明:
  1. @Controller注解:
    將一個普通類標識為Controller控制器類,類中的每一個處理請求的方法被稱為“控制器方法”嫡丙∷┫控制器方法在處理完請求后,通常會返回一個字符串類型的邏輯視圖名曙博,通過視圖解析器(在springMVC配置文件中設置視圖解析器)將邏輯視圖名解析為真正的視圖頁面拥刻,并響應給客戶端展示。
    SpringMVC的配置文件的<context:component-scan base-package="com.sst.cx"/>標簽會掃描包路徑下的所有使用@Controller注解標注的Controller控制器類父泳。
  2. @RequestMapping注解:
    1. 用來標注控制器方法時:將請求地址和處理請求的控制器方法建立映射關系般哼。DispatcherServelt攔截請求后會根據(jù)映射關系將請求分發(fā)給指定的控制器方法進行處理。
    2. 用來標注控制器類時:所有控制器方法的請求地址的父路徑惠窄。
    常用屬性:
      1. value屬性
        設置(控制器方法關聯(lián)的)請求地址(可匹配多個請求地址)逝她,會和控制器方法建立映射關聯(lián)。
        例: 
          @RequestMapping(value = "/") 只有該屬性時可簡寫為:@RequestMapping("/")  
          @RequestMapping(value = {"/register", "/login"})  
        支持Ant風格的通配符路徑:
          1. ?  表示任意的單個字符睬捶。
            例:@RequestMapping(value = "/testuser?")
          2. *  表示任意的 0 個或多個字符黔宛。
        例:@RequestMapping(value = "/testuser*")
          3. **  表示任意的一層或多層目錄(只能作為前綴)。
            例:@RequestMapping(value = "/**/testuser")
      2. name屬性
        設置控制器方法的功能描述(用來干什么)
      3. method屬性(沒有設置該屬性時,默認支持所有請求方式)
        設置控制器方法支持的請求方式(常用:GET臀晃、POST觉渴、DELETE、PUT)徽惋。
        例:
          @RequestMapping(value = "/toUser",method = RequestMethod.GET)
          @RequestMapping(value = "/toUser",method = {RequestMethod.GET,RequestMethod.POST})
      5. params屬性
        用于指定請求中的參數(shù)案淋,只有當請求中攜帶了符合條件的參數(shù)時,控制器方法才會對該請求進行處理险绘。4種方式:
        1. "param" 請求中必須攜帶名為param的參數(shù)踢京。
        2. "!param" 請求中不能攜帶名為param的參數(shù)。
        3. "param=value" 請求中必須攜帶名為param的參數(shù)宦棺,且參數(shù)值必須為:value瓣距。
        4. "param!=value" 請求中不能攜帶參數(shù):param=value(即攜帶參數(shù)param時,其值不能是value)代咸。
        例:
          @RequestMapping(value = "/testParam", params = {"name=張三", "age=12"})
      6. headers屬性
        用于設置請求中請求頭信息蹈丸,只有當請求中攜帶指定的請求頭信息時,控制器方法才會處理該請求呐芥。4種方式:
        1. "header" 請求中必須攜帶請求頭信息:header 逻杖。
        2. "!header" 請求中不能攜帶請求頭信息:header 。
        3. "header=value" 請求中必須攜帶請求頭信息:header=value思瘟。
        4. "header!=value" 請求中不能攜帶請求頭信息:header=value荸百。
        例
          @RequestMapping(value = "toUser",headers = {"Content-Type=application/json", "Referer=http://www.baidu.com"})
6. 在/WEB-INF/template/目錄下創(chuàng)建index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首頁</title>
</head>
<body>
    <h1 th:text="世界你好"></h1>
    <!-- <a th:href="@{/register}">注冊</a>   -->
</body>
</html>
7. 部署到Tomcat服務器中,并啟動Tomcat服務器滨攻。
在瀏覽器中訪問http://localhost:8080/HelloSpringMVC/
項目結構

運行結果

2. 獲取請求參數(shù)

可以通過設置控制器方法的形參來接收/獲取用戶請求中的參數(shù)(4種方式)够话。

方式1. 為請求中的每個參數(shù)添加一個對應的(區(qū)分大小寫)同名形參(不適合參數(shù)過多的情況)
    SpringMVC會自動將請求參數(shù)封裝到對應的形參中。當請求中包含多個同名的請求參數(shù)時:以字符串形式(將參數(shù)值以,分隔铡买,如:"a,b")接收;或 以元素類型為字符串的數(shù)組形式(如:{"a","b"})接收霎箍。
    無視數(shù)據(jù)類型(可以使用String字符串類型的形參接收所有的請求參數(shù)奇钞;也可以使用對應數(shù)據(jù)類型的參數(shù)來接收請求參數(shù),無須進行數(shù)據(jù)類型轉(zhuǎn)換)漂坏。
    例(瀏覽器輸入http://localhost:8080/hello?name=zhangsan&age=12)
      @RequestMapping("/hello")
      public String requestParam(String name, Integer age) {
        System.out.println("nmae:" + name + "age: "+age);
        return "index";
      }
方式2. 使用@RequestParam注解為請求中的參數(shù)和控制器方法的形參建立映射關系景埃。
    SpringMVC會自動將請求參數(shù)封裝到對應的形參中(通常用于解決方式1中不一致的情況)。
    @RequestParam注解的常用屬性
      1. name屬性(value屬性的別名)等價于value屬性
        設置請求中的參數(shù)名顶别。
      2. value屬性
        設置請求中的參數(shù)名谷徙。
      3. required屬性
        設置請求參數(shù)名是否必須(默認為true),不包含時會報異常驯绎。只要求其設置參數(shù)名完慧,并未要求其設置參數(shù)值。
      4. defaultValue屬性
        設置請求參數(shù)的默認值剩失。
        注意: defaultValue屬性會使 required ="true" 失效(即將required屬性自動設置為false)屈尼。
    例
      @RequestMapping("/hello")
      public String requestParam(@RequestParam("name") String userName, @RequestParam("age") String userAge) {
        System.out.println("nmae:" + userName + "age: "+userAge);
        return "index";
      }
方式3. 添加一個HttpServletRequest類型的形參册着。
    SpringMVC會自動將請求參數(shù)封裝到HttpServletRequest對象中。
    例
      @RequestMapping("/hello")
      public String requestParam(HttpServletRequest request) {
        String name = request.getParameter("name");
        String age = request.getParameter("age");
        return "index";
      }
方式4. 添加一個實體類類型的形參(推薦)脾歧。
    SpringMVC會自動將請求參數(shù)封裝到該實體類對象的同名屬性中甲捏。
    例
      @RequestMapping("/hello")
      public String requestParam(User user) {
        String name = user.getName();
        Integer age = user.getAge();
        return "index";
      }

解決獲取請求參數(shù)的亂碼問題
  在post請求中傳遞的參數(shù)為中文時,控制器方法獲取到的參數(shù)值可能會出現(xiàn)亂碼鞭执。
  解決:
    在web.xml文件中司顿,添加(通常都會添加CharacterEncodingFilter來避免亂碼)
    <!-- 請求和響應的字符串過濾器 -->
    <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>
        <!-- 設置響應的編碼 -->
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

3. 在域?qū)ο螅╮equest、session兄纺、application)中共享數(shù)據(jù)

控制器方法處理請求時大溜,會交給Model層處理,Model層將處理完請求后的結果(模型數(shù)據(jù))返回給Controller囤热。Controller在接收到Model層返回的模型數(shù)據(jù)后猎提,將模型數(shù)據(jù)通過域?qū)ο螅ǚ掌髟趦?nèi)存上創(chuàng)建的一塊存儲空間,用于不同動態(tài)Web資源之間的數(shù)據(jù)傳遞和共享)共享的方式傳遞給View視圖進行渲染旁蔼,將最終的頁面返回給客戶端展示锨苏。

域?qū)ο笾泄蚕頂?shù)據(jù)的常用方式:
  方式1. 使用原生ServletAPI向request、session棺聊、application域?qū)ο笾泄蚕頂?shù)據(jù)伞租。
    會導致控制器與Servlet容器耦合度過高(不推薦)
    例(request)
      在控制器方法中添加一個HttpServletRequest類型的形參。
      @RequestMapping("/")
      public String testServletAPI(HttpServletRequest request) {
        request.setAttribute("name", "張三");
        return "index";
      }
    例(session)
      在控制器方法中添加一個HttpSession類型的形參限佩。
      @RequestMapping("/")
      public String testServletAPI(HttpSession session) {
        session.setAttribute("name", "張三");
        return "index";
      }
    例(application)
      在控制器方法中添加一個HttpSession類型的形參葵诈,通過它獲取到application域?qū)ο蟆?      @RequestMapping("/")
      public String testServletAPI(HttpSession session) {
        ServletContext application = session.getServletContext();
        application.setAttribute("name", "張三");
        return "index";
      }
  方式2. 使用Model、Map祟同、ModelMap向request域?qū)ο笾泄蚕頂?shù)據(jù)作喘。
    例(Model)
      在控制器方法中添加一個Model類型的形參。
      @RequestMapping("/")
      public String testModelMap(Model model) {
        model.addAttribute("name", "張三");
        return "index";
      }
    例(Map)
      在控制器方法中添加一個Map類型的形參晕城。
      @RequestMapping("/")
      public String testModelMap(Map<String, Object> map) {
        map.put("name", "張三");
        return "index";
      }
    例(ModelMap)
      在控制器方法中添加一個ModelMap類型的形參泞坦。
      @RequestMapping("/")
      public String testModelMap(ModelMap modelMap) {
        modelMap.addAttribute("name", "張三");
        return "index";
      }
  方式3. 使用ModelAndView向request域?qū)ο笾泄蚕頂?shù)據(jù)。
    控制器方法支持ModelAndView砖顷、ModelMap贰锁、View、String多種類型的返回值滤蝠,最終都會被SpringMVC封裝成一個ModelAndView對象豌熄。ModelAndView對象由model(模型數(shù)據(jù):需要渲染到視圖的數(shù)據(jù))和 view(視圖:通常為邏輯視圖名)組成。
    ModelAndView的常用方法:
      1. 添加Model模型數(shù)據(jù)
        ModelAndView addObject(String attributeName, @Nullable Object attributeValue)   
        ModelAndView addObject(Object attributeValue)
        ModelAndView addAllObjects(@Nullable Map<String, ?> modelMap)
      2. 設置視圖
        void setViewName(@Nullable String viewName)     
        void setView(@Nullable View view) 
    例
      在控制器方法中創(chuàng)建ModelAndView對象并返回物咳。
      @RequestMapping("/")
      public ModelAndView testModelAndView() {
          ModelAndView mav = new ModelAndView();
          // 設置Model(向請求域共享數(shù)據(jù))
          mav.addObject("name", "hello,張三");
          // 設置視圖(實現(xiàn)頁面跳轉(zhuǎn))
          mav.setViewName("index");
          return mav;
      }

4. 視圖和視圖解析器

SpringMVC的控制器方法支持ModelAndView锣险、ModelMap、View、String多種類型的返回值囱持,最終都會被封裝成一個ModelAndView對象(由model模型數(shù)據(jù)和view視圖組成)夯接。View是邏輯視圖名,需要通過視圖解析器解析為真正的視圖纷妆,并將model模型數(shù)據(jù)填入視圖中盔几。
SpringMVC的核心理念是將View視圖與Model模型進行解耦,其工作重心聚焦在Model模型數(shù)據(jù)上掩幢,并不關心最終究竟采用何種視圖技術(Thymeleaf逊拍、JSP、FreeMarker际邻、Velocity芯丧、Excel等,根據(jù)需求自由選擇)對模型數(shù)據(jù)進行渲染世曾。

視圖
  用于渲染頁面:將Model模型數(shù)據(jù)填入頁面中缨恒,最終生成HTML、JSP轮听、Excel表格骗露、Word文檔、PDF文檔血巍、JSON數(shù)據(jù)等形式的文件萧锉,并展示給用戶。

1. SpringMVC提供了一個View視圖接口述寡,接口中定義了以下2個方法:
  1. default String getContentType();   
    獲取HTTP響應文件的類型(如:HTML柿隙、JSON、PDF等)鲫凶。 
  2. void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;(視圖的核心方法)   
    負責將Model模型數(shù)據(jù)渲染到視圖中禀崖。
    參數(shù)說明:model(模型數(shù)據(jù))、request(請求對象)螟炫、response(響應對象)波附。
2. 常用的View接口實現(xiàn)類(視圖類)
  1. ThymeleafView(Thymeleaf視圖)     
    當項目中使用的視圖技術為Thymeleaf時,則需要使用該視圖類不恭。
  2. InternalResourceView(轉(zhuǎn)發(fā)視圖)
    實現(xiàn)請求的轉(zhuǎn)發(fā)跳轉(zhuǎn)叶雹。
  3. RedirectView(重定向視圖)
    實現(xiàn)請求的重定向跳轉(zhuǎn)财饥。
  4. FreeMarkerView(FreeMarker視圖)
  5. MappingJackson2JsonView(JSON視圖)
  6. AbstractPdfView(PDF視圖)

3. 視圖分類
  1. 邏輯視圖
    最大的特點:控制器方法返回的ModelAndView中的view不是真正的視圖對象换吧,而是一個字符串類型的邏輯視圖名,需要通過一個ViewResolver視圖解析器解析為真正的物理視圖對象钥星。
    方式1
      直接在控制器方法中返回字符串類型的邏輯視圖名沾瓦,然后通過Model、Map、ModelMap等對象攜帶Model模型數(shù)據(jù)到視圖中贯莺。
      例
        @RequestMapping("/testView")
        public String testView(Model model) {
            model.addAttribute("product","模型數(shù)據(jù)")
            return "success";
        }
    方式2
      在控制器方法中通過ModelAndView提供的setViewName()方法設置邏輯視圖名风喇,然后通過ModelAndView的addObject()方法攜帶Model模型數(shù)據(jù)到視圖中。
      例
        @RequestMapping("/testView")
        public ModelAndView testView() {
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.setViewName("productList");
            List<Product> productList = productService.getProductList();
            modelAndView.addObject(productList);
            return modelAndView;
        }
    注:對于Thymeleaf缕探、JSP等類型的邏輯視圖魂莫,其控制器方法返回的view并不是必須為字符串類型的邏輯視圖名,也可以是一個真正的View視圖對象(通過ModelAndView提供的方法構造)爹耗,此時這個視圖也不需要視圖解析器的解析 而是直接渲染耙考。
  2. 非邏輯視圖
    控制方法返回的是一個真正的視圖對象(不需要視圖解析器解析,可直接渲染)潭兽,而不是邏輯視圖名倦始。
    例(MappingJackson2JsonView將數(shù)據(jù)模型轉(zhuǎn)換為JSON視圖并展現(xiàn)給用戶)
      @RequestMapping("/testJsonView")
      public ModelAndView testJsonView(Integer productId) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("url", "www.baidu.com");
        // 設置ModelAndView的View對象
        modelAndView.setView(new MappingJackson2JsonView());
        return modelAndView;
      }

4. 視圖控制器標簽
  如果控制器方法中只是簡單返回一個邏輯視圖名,而沒有返回Model數(shù)據(jù)山卦,則可使用<mvc:view-controller>視圖控制器標簽代替該方法鞋邑。
  注意:在springMVC.xml中添加了視圖控制器標簽后,必須添加<mvc:annotation-driven />標簽開啟注解驅(qū)動账蓉,否則其他控制器方法的請求映射將全部失效枚碗。
  例:
    @RequestMapping("/addPage")
    public String addPage() {
        return "base/add";
    }
    等價于
    在springMVC.xml中使用<mvc:view-controller path="/addPage" view-name="base/add"></mvc:view-controller>
視圖解析器(ViewResolver)
  提供了邏輯視圖名與實際視圖的映射關系,并負責將邏輯視圖名解析為一個具體的視圖對象剔猿。
  1. SpringMVC提供了ViewResolver視圖解析器接口(視圖解析器必須實現(xiàn)該接口)视译。
    public interface ViewResolver {
      @Nullable
      View resolveViewName(String viewName, Locale locale) throws Exception;
    }
  2. ViewResolver接口的常用實現(xiàn)類(視圖解析器)每一個解析器都對應一個視圖技術
    1. BeanNameViewResolver     
      將邏輯視圖名解析為 一個Bean(視圖的名稱就是Bean的id)。
    2. InternalResourceViewResolver     
      將邏輯視圖名解析為 一個資源文件归敬。
      如:"success.jsp" 會被映射為success.jsp文件酷含。
    3. FreeMarkerViewResolver   
      將邏輯視圖名解析為 一個FreeMarker模板文件。
    4. ThymeleafViewResolver    
      將邏輯視圖名解析為 一個Thymeleaf模板文件汪茧。
  3. 使用某個視圖解析器時
    只需在SpringMVC.xml配置文件中椅亚,將它以Bean組件的形式注入到Ioc容器中。否則SpringMVC會使用默認的InternalResourceViewResolver進行解析舱污。
  4. 配置多個視圖解析器
    對于不同類型的視圖對象玩郊,需要在springMVC.xml中配置不同的視圖解析器(根據(jù)order屬性來指定解析優(yōu)先級順序,order越小優(yōu)先級越高)來完成視圖的實例化工作挽鞠。
    SpringMVC會遍歷所有視圖解析器闹究,并按照其優(yōu)先級依次對邏輯視圖名進行解析,直到解析成功并返回視圖對象為止珠插。

示例(同時配置Thymeleaf惧磺、JSP視圖解析器):
<?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
       https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 開啟組件掃描 -->
    <context:component-scan base-package="com.sst.cx"></context:component-scan>
    <!-- 配置 Thymeleaf 視圖解析器 -->
    <bean id="viewResolver"
          class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <!-- 邏輯視圖名的規(guī)則,以 th捻撑、base/ 開頭的邏輯視圖名才會被該解析器解析 -->
        <property name="viewNames" value="th*,base/*"/>
        <!-- 視圖解析器的優(yōu)先級磨隘,值越小缤底,優(yōu)先級越高 -->
        <property name="order" value="2"/>
        <!-- 定義視圖文件的字符集 -->
        <property name="characterEncoding" value="UTF-8"/>
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                        <!-- 設置視圖前綴  -->
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        <!-- 設置視圖后綴 -->
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/>
                        <property name="characterEncoding" value="UTF-8"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
    <!-- 配置 JSP 視圖解析器 -->
    <bean id="viewResolver1" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 邏輯視圖名的規(guī)則 -->
        <property name="viewNames" value="jsp/*"/>
        <!-- 視圖解析器的優(yōu)先級,值越小番捂,優(yōu)先級越高 -->
        <property name="order" value="1"/>
        <property name="viewClass"
                  value="org.springframework.web.servlet.view.InternalResourceView"/>
        <!-- 視圖前綴 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 視圖后綴 -->
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

靜態(tài)資源映射

在SpringMVC.xml配置文件中个唧,實現(xiàn)靜態(tài)資源的映射(訪問靜態(tài)資源)。
  方式1
    <!-- 
      靜態(tài)資源映射(用于配置靜態(tài)資源的訪問路徑)
        location屬性:本地靜態(tài)資源文件所在目錄设预。/js/**表示js目錄及js子目錄徙歼。
        mapping屬性:訪問靜態(tài)資源的路徑前綴。
    -->
    <mvc:resources mapping="/js/" location="/js/**"></mvc:resources>
  方式2
    <!--
      將靜態(tài)資源交給Tomcat提供的默認Servlet進行處理鳖枕。
      使用此標簽時鲁沥,必須設置<mvc:annotation-driven/>,否則只能訪問靜態(tài)資源耕魄,無法再訪問其他請求画恰。
    -->
    <mvc:default-servlet-handler/>

請求轉(zhuǎn)發(fā)與重定向

請求轉(zhuǎn)發(fā)
  在控制器方法中返回邏輯視圖名時,使用"forward:"關鍵字進行請求轉(zhuǎn)發(fā)操作(不會被SpringMVC配置的視圖解析器解析吸奴,而是會將前綴“forward:”去掉允扇,以剩余部分作為最終路徑,經(jīng)過相應的控制器方法處理后则奥,交由視圖解析器解析為最終顯示的頁面 展示到客戶端)考润。
  方式1. 在控制器方法中返回: "forward:"關鍵字作為前綴的字符串。
    @RequestMapping("/testDispatcher")
    public String testDispatcher() {
        return "forward:/login";
    }
  方式2. 在控制器方法中返回:ModelAndView(邏輯視圖名為: "forward:"關鍵字作為前綴的字符串)读处。
    @RequestMapping("/testDispatcher")
    public ModelAndView testDispatcher() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("forward:/login");  // 設置邏輯視圖名
        return modelAndView;
    }

重定向
  在控制器方法中返回邏輯視圖名時糊治,使用"redirect:"關鍵字進行重定向操作。(不會被SpringMVC配置的視圖解析器解析罚舱,而是會將前綴“redirect:”去掉井辜,以剩余部分作為最終路徑從客戶端重新請求,經(jīng)過相應的控制器方法處理后管闷,交由視圖解析器解析為最終顯示的頁面 展示到客戶端)粥脚。
  方式1. 在控制器方法中返回: "redirect:"關鍵字作為前綴的字符串。
    @RequestMapping("/testDispatcher")
    public String testDispatcher() {
        return "redirect:/login";
    }
  方式2. 在控制器方法中返回:ModelAndView(邏輯視圖名為: "redirect:"關鍵字作為前綴的字符串)包个。
    @RequestMapping("/testRedirect")
    public ModelAndView testDispatcher() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("redirect:/login");  // 設置邏輯視圖名
        return modelAndView;
    }

5. RESTful(REST風格)

REST(Resource Representational State Transfer)表現(xiàn)層資源狀態(tài)轉(zhuǎn)移
  描述了服務器與客戶端進行交互時資源的狀態(tài)轉(zhuǎn)換刷允。REST本身并不是一個實用的概念,真正實用的是如何設計RESTFul接口(即:通過什么樣的手段讓資源在服務器端發(fā)生狀態(tài)轉(zhuǎn)移)碧囊。
  1. Resource(資源)
    把Web項目部署到Tomcat服務器后树灶,項目中的所有內(nèi)容(類、html文件糯而、css文件天通、js文件、數(shù)據(jù)庫表歧蒋、文本土砂、圖片、音頻等)在都可以被稱為這個服務器中的資源谜洽。而服務器則可以看作是由許許多多離散的資源組成的萝映。
    這些資源都可以通過一個URI(統(tǒng)一資源標識符) 進行標識,任何對于該資源的操作都不能改變其URI阐虚。想要獲取這個資源序臂,只需訪問它的URI即可。
  2. Representation(資源的表述)
    資源在某個特定時刻的狀態(tài)的描述(資源的具體表現(xiàn)形式)实束,可以有多種格式(如:html奥秆、xml、json咸灿、純文本构订、圖片、視頻避矢、音頻等)悼瘾。
    通常情況下,服務端與客戶端資源的表述所有使用的格式往往是不同的(如:在服務端資源可能是數(shù)據(jù)庫中的一段純文本审胸、一個xml文件亥宿、數(shù)據(jù)庫中的一張表,而客戶端則可能是表現(xiàn)為html頁面砂沛、json烫扼、音頻、視頻)碍庵。
  3. State Transfer(資源狀態(tài)轉(zhuǎn)換)
    客戶端與服務端進行交互時映企,資源從一種表現(xiàn)形式轉(zhuǎn)換到另一種表現(xiàn)形式的過程。但是 HTTP協(xié)議是一種無狀態(tài)協(xié)議(無法保存任何狀態(tài))静浴,因此如果客戶端想要獲取服務器上的某個資源卑吭,就必須通過某種手段讓資源在服務器端發(fā)生“狀態(tài)轉(zhuǎn)化”,而這種狀態(tài)轉(zhuǎn)化又是建立在應用的UI表現(xiàn)層上的马绝。這就是【表現(xiàn)層資源狀態(tài)轉(zhuǎn)移】的含義豆赏。

RESTful(REST風格)
  在傳統(tǒng)的項目開發(fā)中,通常會將 操作資源的動詞(由開發(fā)員定義富稻、沒有統(tǒng)一規(guī)范) 寫進URL中掷邦。例(通過用戶ID獲取用戶信息的請求,不同的開發(fā)員定義的URL不同):
    1. http://localhost:8080/helloSpringMVC/getUserById?id=1
    2. http://localhost:8080/helloSpringMVC/user/getById?id=1
    3. http://localhost:8080/helloSpringMVC/getUserInfo?id=1
    4. http://localhost:8080/helloSpringMVC/a/b?id=1
  RESTFul提倡使用統(tǒng)一的風格來設計URL椭赋,規(guī)則如下:
    RESTFul是當前比較流行的互聯(lián)網(wǎng)軟件架構模式抚岗,利用HTTP協(xié)議的特性規(guī)定了一套統(tǒng)一的資源獲取方式,以實現(xiàn)客戶端與服務端的數(shù)據(jù)訪問與交互哪怔。
    使用RESTful的Web服務稱為REST服務(RESTful Web Services)宣蔚。
    1. URL只用來標識和定位資源向抢,不得包含任何與操作相關的動詞。
      例(訪問和用戶相關的資源)
        http://localhost:8080/helloSpringMVC/user
    2. 當請求中需要攜帶參數(shù)時胚委,RESTFul允許將參數(shù)通過斜杠/拼接到URL中挟鸠,而不是以前那樣使用問號?拼接鍵值對的方式來攜帶參數(shù)。
      例
        http://localhost:8080/helloSpringMVC/user/1
    3. 客戶端通過HTTP協(xié)議提供的四個表示操作資源方式的動詞:GET(獲取資源)亩冬、POST(新建資源)艘希、PUT(更新資源) 和 DELETE(刪除資源),從而實現(xiàn)對服務器端資源狀態(tài)轉(zhuǎn)移硅急。

在SpringMVC項目中覆享,通過@RequestMapping+@PathVariable注解的方式 使用RESTful。
  1. 通過@RequestMapping注解 設置路徑中的參數(shù)营袜。
    通過占位符{xxx}表示傳遞的參數(shù)撒顿。占位符的位置要與請求URL中參數(shù)的位置保持一致,否則會傳錯參數(shù)荚板。
  2. 通過@PathVariable注解 綁定參數(shù)
    將占位符{xxx}所表示的參數(shù)綁定到控制器方法的形參核蘸。
  3. 通過HiddenHttpMethodFilter對請求進行過濾
    瀏覽器默認只支持發(fā)送GET和POST請求。在web.xml中使用SpringMVC提供的HiddenHttpMethodFilter對請求進行過濾(將POST請求轉(zhuǎn)換為PUT或DELETE請求)后則可處理PUT和DELETE請求啸驯。當為POST請求且存在_method參數(shù)值時客扎,會將POST請求轉(zhuǎn)換為_method參數(shù)指定的方法(PUT/DELETE)。
  例
    1. 在web.xml中罚斗,添加:
        <!-- 同時存在時徙鱼,必須先配置CharacterEncodingFilter,再配置HiddenHttpMethodFilter -->
    <!-- 處理PUT和DELETE請求的過濾器 -->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    2. 控制器方法:
      // 新增商品
      @RequestMapping(value = "/product", method = RequestMethod.POST)
      public String addProduct(Product product) {
        productDao.addProduct(product);
        return "redirect:/products";
      }
      // 刪除商品
      @RequestMapping(value = "/product", method = RequestMethod.DELETE)
      public String deleteProduct(String productId) {
        productDao.deleteProduct(productId);
        return "redirect:/products";
      }
      // 修改商品
      @RequestMapping(value = "/product", method = RequestMethod.PUT)
      public String updateProduct(Product product) {
        productDao.updateProduct(product);
        return "redirect:/products";
      }
      // 查看/回顯商品信息(action參數(shù)為get時為查看针姿;action參數(shù)為update時為修改頁中回顯數(shù)據(jù))
      @RequestMapping("/product/{action}/{productId}")
      public String getProductList(@PathVariable("action") String action, @PathVariable("productId") String productId, Model model) {
        Product product = productDao.getProductById(productId);
        model.addAttribute("product", product);
        // 根據(jù)參數(shù)action判斷跳轉(zhuǎn)到商品詳細信息頁還是商品修改頁
        if (action.equals("get")) {
            return "product_info";
        } else {
            return "product_update";
        }
      }
    3. html
      增
      <form th:action="@{/product}" method="post">
        ...
        <input type="submit" value="新增商品">
      </form>
      刪
      <form th:action="@{/product}" method="post">
        <input type="hidden" name="_method" value="delete">
        ...
        <input type="submit" value="刪除商品">
      </form>
      改
      <form th:action="@{/product}" method="post">
        <input type="hidden" name="_method" value="put">
        ...
        <input type="submit" value="修改商品">
      </form>
      查
      <a th:href="@{|/product/get/${product.getProductId()}|}">查看商品</a>
資源操作 傳統(tǒng)方式的URL RESTFul的URL HTTP請求方式
獲取資源 SELECT http://localhost:8080/helloSpringMVC/getUserById?id=1 http://localhost:8080/helloSpringMVC/user/1 GET
新增資源 INSERT http://localhost:8080/helloSpringMVC/saveUser http://localhost:8080/helloSpringMVC/user POST
更新資源 UPDATE http://localhost:8080/helloSpringMVC/updateUser http://localhost:8080/helloSpringMVC/user PUT
刪除資源 DELETE http://localhost:8080/helloSpringMVC/deleteUser?id=1 http://localhost:8080/helloSpringMVC/user/1 DELETE

6. Converter類型轉(zhuǎn)換器

通過一些注解袱吆,控制器方法就能得到各種類型的請求參數(shù),這要歸功于SpringMVC的類型轉(zhuǎn)換機制距淫。Spring提供了Converter類型轉(zhuǎn)換器绞绒,在SpringMVC中 它的作用是在控制器方法對請求進行處理前,先將請求中的參數(shù)轉(zhuǎn)為指定的數(shù)據(jù)類型再傳給控制器方法的形參榕暇。
SpringMVC會自動使用內(nèi)置類型轉(zhuǎn)換器對基本類型(int蓬衡、long、float彤枢、double狰晚、boolean、char 等)缴啡、集合/數(shù)組類型 進行轉(zhuǎn)換(請求參數(shù)類型要和接收參數(shù)類型必須相兼容壁晒,否則會報400錯誤)。

內(nèi)置類型轉(zhuǎn)換器---標量轉(zhuǎn)換器

名稱 作用
StringToBooleanConverter String 轉(zhuǎn) boolean
ObjectToStringConverter Object 轉(zhuǎn) String(調(diào)用對象的toString方法進行轉(zhuǎn)換业栅,可覆寫該方法來自定義)
StringToNumberConverterFactory String 轉(zhuǎn) 數(shù)字(如:Integer秒咐、Long等)
NumberToNumberConverterFactory 數(shù)字子類型(基本類型)轉(zhuǎn) 數(shù)字類型(包裝類型)
StringToCharacterConverter String 轉(zhuǎn) Character(取字符串中的第一個字符)
NumberToCharacterConverter 數(shù)字子類型 轉(zhuǎn) Character
CharacterToNumberFactory Character 轉(zhuǎn) 數(shù)字子類型
StringToEnumConverterFactory String 轉(zhuǎn) 枚舉類型(通過Enum.valueOf方法)
EnumToStringConverter 枚舉類型 轉(zhuǎn) String(返回枚舉對象的name值)
StringToLocaleConverter String 轉(zhuǎn) java.util.Locale
PropertiesToStringConverter java.util.Properties 轉(zhuǎn) String(默認使用ISO-8859-1解碼)
StringToPropertiesConverter String 轉(zhuǎn) java.util.Properties(默認使用ISO-8859-1編碼)

內(nèi)置類型轉(zhuǎn)換器---集合谬晕、數(shù)組相關轉(zhuǎn)換器

名稱 作用
ArrayToCollectionConverter 任意數(shù)組 轉(zhuǎn) 任意集合(List、Set)
CollectionToArrayConverter 任意集合 轉(zhuǎn) 任意數(shù)組
ArrayToArrayConverter 任意數(shù)組 轉(zhuǎn) 任意數(shù)組
CollectionToCollectionConverter 集合之間的類型轉(zhuǎn)換
MapToMapConverter Map之間的類型轉(zhuǎn)換
ArrayToStringConverter 任意數(shù)組 轉(zhuǎn) String
StringToArrayConverter 字符串 轉(zhuǎn) 數(shù)組(默認以,分割携取,且去除字符串兩邊的空格)
ArrayToObjectConverter 任意數(shù)組 轉(zhuǎn) Object(如果目標類型和源類型兼容攒钳,直接返回源對象;否則返回數(shù)組的第一個元素并進行類型轉(zhuǎn)換)
ObjectToArrayConverter Object 轉(zhuǎn) 單元素數(shù)組
CollectionToStringConverter 任意集合(List歹茶、Set) 轉(zhuǎn) String
StringToCollectionConverter String 轉(zhuǎn) 集合(默認以,分割,且去除字符串兩邊的空格)
CollectionToObjectConverter 任意集合 轉(zhuǎn) 任意Object(如果目標類型和源類型兼容你弦,直接返回源對象惊豺;否則返回集合的第一個元素并進行類型轉(zhuǎn)換)
ObjectToCollectionConverter Object 轉(zhuǎn) 單元素集合

自定義類型轉(zhuǎn)換器

對于復雜類型的轉(zhuǎn)換(如:String轉(zhuǎn)Date)和自定義格式數(shù)據(jù)的轉(zhuǎn)換,則需要根據(jù)需求開發(fā)自定義類型轉(zhuǎn)換器來進行轉(zhuǎn)換禽作。

步驟:
  1. 創(chuàng)建自定義類型轉(zhuǎn)換器類(實現(xiàn)Spring提供的3個轉(zhuǎn)換器接口中的任意一個)尸昧。
    1. Converter<S,T>接口     
      使用了泛型(S表示原類型,T表示目標類型)旷偿。
      接口中定義了一個convert()方法烹俗,將原類型對象作為參數(shù)傳入,進行轉(zhuǎn)換之后返回目標類型對象萍程。
    2. ConverterFactory<S,R>接口
      用于將同系列的多個Converter封裝在一起幢妄。  
      如果希望將一種類型的對象轉(zhuǎn)換為另一種類型及其子類對象(如:將String轉(zhuǎn)為Number及Number的子類Integer、Double等類型)茫负,則需要一系列的Converter(如:StringToInteger蕉鸳、StringToDouble等)。
    3. GenericConverter接口   
      根據(jù)源類對象及目標類對象的上下文信息進行類型轉(zhuǎn)換忍法。
    例(實現(xiàn)Converter<S,T>接口潮尝,將String類型的參數(shù)轉(zhuǎn)換為Date類型):
      // 自定義日期轉(zhuǎn)換器
      public class MyDateConverter implements Converter<String, Date> {
        private String datePatten = "yyyy-MM-dd";
        @Override
        public Date convert(String source) {
            System.out.println("前端頁面?zhèn)鬟f過來的時間為:" + source);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePatten);
            try {
                return simpleDateFormat.parse(source);
            } catch (ParseException e) {
                throw new IllegalArgumentException("無效的日期格式,請使用正確的日期格式" + datePatten);
            }
        }
      }
  2. 配置自定義類型轉(zhuǎn)換器
    創(chuàng)建自定義類型轉(zhuǎn)換器類后饿序,需要在SpringMVC.xml配置文件中進行配置才能生效勉失。
    例:
      <!-- 注冊自定義類型轉(zhuǎn)換器,會覆蓋默認注冊的ConversionService(FormattingConversionServiceFactoryBean類型) -->
      <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
      <!-- 配置自定義類型轉(zhuǎn)換器 -->
      <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.sst.cx.converter.MyDateConverter"></bean>
            </set>
        </property>
      </bean>

<mvc:annotation-driven/>(通常都需要在SpringMVC.xml配置文件中添加)說明:
  開啟注解驅(qū)動來簡化SpringMVC的相關配置:
    1. 自動向SpringMVC中注冊3個Bean:RequestMappingHandlerMapping原探、RequestMappingHandlerAdapter(這2個組件:請求分發(fā)給控制器方法的必須組件乱凿;為讀寫json數(shù)據(jù)提供支持),ExceptionHandlerExceptionResolver(異常處理組件)咽弦。
    2. 默認注冊了一個ConversionService(項目啟動時會自動通過FormattingConversionServiceFactoryBean類創(chuàng)建并初始化一個FormattingConversionService類型的實例:ConversionService告匠,給@DateTimeFormat、@NumberFormat注解提供支持)滿足大多數(shù)的類型轉(zhuǎn)換需求离唬。

7. Formatter格式化器

開發(fā)中經(jīng)常會涉及到一些需要進行格式化的數(shù)據(jù)(金額:¥100需要處理為100后专,日期:需要按需求處理為指定格式,如:yyyy-MM-dd格式)输莺,這些數(shù)據(jù)都要經(jīng)過一定的格式化處理才能正常使用戚哎。
雖然Formatter與Converter存在一定的差異(Formatter的源類型必須是String類型裸诽,而Converter的源類型可以是任意數(shù)據(jù)類型),但格式化轉(zhuǎn)換本質(zhì)上還是屬于“類型轉(zhuǎn)換”型凳,因此在SpringMVC中Formatter格式化轉(zhuǎn)換器實際上是委托給Converter機制實現(xiàn)的丈冬。

Spring提供了一個Formatter<T>接口(格式化轉(zhuǎn)換器,將String類型的字符串轉(zhuǎn)換為T任意類型)甘畅,該接口繼承了Printer<T>和Parser<T>接口(分別包含一個print方法和一個parse方法埂蕊,所有的格式化轉(zhuǎn)換器實現(xiàn)類都必須重寫這兩個方法)。
  public interface Formatter<T> extends Printer<T>, Parser<T> {}
  1. Printer<T>接口中定義了print方法
    String print(T object, Locale locale); 
      將對象轉(zhuǎn)為String類型的(按照一定的格式)字符串并返回疏唾。
      該方法中包含一個Locale類型的形參蓄氧,可根據(jù)國家/語言進行定制。
  2. Parser<T>接口中定義了parse方法     
    T parse(String text, Locale locale) throws ParseException;  
      將滿足一定格式的字符串轉(zhuǎn)為對象槐脏。
      該方法中包含一個Locale類型的形參喉童,可根據(jù)國家/語言進行定制。

內(nèi)置格式化轉(zhuǎn)換器(用來格式化 日期Date類型顿天、數(shù)值Number類型的數(shù)據(jù))【存疑】
  1. NumberFormatter    
    實現(xiàn)Number與String之間的解析與格式化堂氯。
  2. CurrencyFormatter  
    實現(xiàn)Number與String之間的解析與格式化(帶貨幣符號)。
  3. PercentFormatter   
    實現(xiàn)Number與String之間的解析與格式化(帶百分數(shù)符號)牌废。
  4. DateFormatter  
    實現(xiàn)Date與String之間的解析與格式化咽白。

  1. SpringMVC提供了一個FormattingConversionService類(ConversionService類型轉(zhuǎn)換器接口的實現(xiàn)類),它與其他的類型轉(zhuǎn)換器實現(xiàn)類不同鸟缕,它不僅具有類型轉(zhuǎn)換功能局扶,還具有格式化轉(zhuǎn)換功能。SpringMVC為FormattingConversionService類提供了一個FormattingConversionServiceFactroyBean工廠類(用于在Spring上下文中構造FormattingConversionService的實例叁扫,并且為@DateTimeFormat注解三妈、@NumberFormat注解提供了支持)。
  2. 在SpringMVC.xml配置文件中添加了<mvc:annotation-driven/>標簽(項目啟動時會自動通過FormattingConversionServiceFactoryBean類創(chuàng)建并初始化一個FormattingConversionService類型的實例:ConversionService)莫绣,才能使用@DateTimeFormat注解畴蒲、@NumberFormat注解 對 Date類型、Number類型的數(shù)據(jù)進行格式化轉(zhuǎn)換对室。
1. @DateTimeFormat注解(日期格式化)
  用于標注java.util.Date模燥、java.util.Calendar、java.long.Long等時間類型的數(shù)據(jù)掩宜。
  常用屬性      
    1. pattern屬性(String類型)  
      用于指定解析或格式化日期時間的模式(常用取值: yyyy-MM-dd蔫骂、yyyy-MM-dd hh:mm:ss)。
    2. iso屬性(DateTimeFormat.ISO類型)  
      用于指定解析或格式化日期時間的ISO模式牺汤,其取值有4種:
        DATE:yyyy-MM-dd
        TIME:hh:mm:ss:SSSZ
        DATE_TIME:yyyy-MM-dd hh:mm:ss:SSSZ
        NONE:無
    3. style屬性(String類型)    
      用于指定日期時間的格式(默認值為SS)辽旋。
      該屬性由兩個字符組成,分別表示日期和時間的格式。
        S:短日期/時間格式
        M:中日期/時間格式
        L:長日期/時間格式
        F:完整日期/時間格式
  例:
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date date;

2. @NumberFormat注解(數(shù)值格式化)
  用于標注數(shù)字基本類型(如:int补胚、long等)码耐、java.lang.Number類型的實例(如:BigDecimal、Integer等)溶其。
  擁有兩個互斥的屬性:
    1. style屬性(NumberFormat.Style類型)    
      用于指定數(shù)值的樣式類型骚腥,其取值有以下4種:
        DEFAULT:默認類型
        NUMBER:正常數(shù)值類型
        PERCENT:百分數(shù)類型
        CURRENCY:貨幣數(shù)值類型
    2. pattern屬性(String類型)  
      用于自定義數(shù)值的樣式,如: #,###
  例:
    @NumberFormat(style = NumberFormat.Style.CURRENCY)
    private BigDecimal money;

8. json數(shù)據(jù)轉(zhuǎn)換(Java對象<--轉(zhuǎn)換-->json數(shù)據(jù))

1. json(全稱:JavaScript Object Notation)簡介
  與xml相似瓶逃,也是用來存儲數(shù)據(jù)的(基于純文本的數(shù)據(jù)格式)束铭。但相比于xml,數(shù)據(jù)占用空間更小厢绝、解析速度更快契沫。因此,使用json數(shù)據(jù)來進行前后臺的數(shù)據(jù)交互代芜。
  不僅能夠傳遞String埠褪、Number浓利、Boolean等簡單類型的數(shù)據(jù)挤庇,還可以傳遞數(shù)組、Object對象等復雜類型的數(shù)據(jù)贷掖。
  支持2種數(shù)據(jù)結構(可相互嵌套):
    1. 對象結構
      以“{”開始嫡秕,以“}”結束,中間則由0個或多個以英文的逗號,分隔的key:value對構成苹威。
      key必須為String類型昆咽,value可以是String、Number牙甫、Object掷酗、Array等數(shù)據(jù)類型。
      語法格式:
        {  
          key1:value1,
          key2:value2,
          ...
        }
      例:
        一個person對象包含姓名窟哺、密碼泻轰、年齡等信息,使用json的表示形式如下:
        {
          "pname":"張三",
          "password":"123456",
          "page":12
        }
    2. 數(shù)組結構且轨。 
      以“[”開始浮声、以“]”結束,中間部分由0個或多個以英文的逗號,分隔的值列表組成旋奢。
      語法格式:
        [
          value1,
          value2,
          ...
        ]
      例:
        一個數(shù)組中包含了String泳挥、Number、Boolean至朗、null多種類型的數(shù)據(jù)屉符,使用json的表示形式如下:
        [
          "張三",
          123456789,
          true,
          null
        ]

2. json數(shù)據(jù)轉(zhuǎn)換(Java對象和json數(shù)據(jù)的相互轉(zhuǎn)換)
  SpringMVC提供了一個默認的MappingJackson2HttpMessageConverter類,來處理瀏覽器與控制器類之間的json數(shù)據(jù)轉(zhuǎn)換。
  使用步驟:
    1. 導入Jackson依賴包
      1. jackson-annotations-x.x.x.jar(json轉(zhuǎn)換的注解包)
      2. jackson-core-x.x.x.jar(json轉(zhuǎn)換的核心包)
      3. jackson-databind-x.x.x.jar(json轉(zhuǎn)換的數(shù)據(jù)綁定包)
    2. springMVC.xml配置文件中筑煮,需要添加<mvc:annotation-driven/>開啟注解驅(qū)動(會自動注冊RequestMappingHandlerMapping辛蚊、RequestMappingHandlerAdapter兩個組件,為讀寫json數(shù)據(jù)提供支持)真仲。
    3. json轉(zhuǎn)換注解
      1. @RequestBody注解     
        標注控制器方法的形參袋马。
        用于將請求體中的數(shù)據(jù)綁定到控制器方法的形參上(json轉(zhuǎn)對象)。
      2. @ResponseBody注解    
        標注控制器方法秸应。
        用于將控制器方法的返回值虑凛,直接作為響應報文的響應體響應到瀏覽器上(對象轉(zhuǎn)json)。
  例:
    @ResponseBody
    @RequestMapping(value = "/product", method = RequestMethod.POST)
    public Product addProduct(@RequestBody Product product) {
        productDao.addProduct(product);
        return product;
    }
    @ResponseBody
    @RequestMapping("/getProductList1")
    public List<Product> getProductList1() {
        List productList = productDao.getProductList();
        return productList;
    }

下載Jackson依賴包软啼,搜索包->選擇版本->點擊bundle按鈕

示例

===》控制器
@Controller
public class ProductController {
    @Resource
    private ProductDao productDao;
    // 查看或回顯商品信息桑谍,get:查看商品信息  update:為修改頁回顯的商品信息
    @ResponseBody
    @RequestMapping("/product/{productId}")
    public Product getProduct(@PathVariable("productId") String productId) {
        Product product = productDao.getProductById(productId);
        return product;
    }
    // 新增商品
    @ResponseBody
    @RequestMapping(value = "/product", method = RequestMethod.POST)
    public Product addProduct(@RequestBody Product product) {
        productDao.addProduct(product);
        return product;
    }
    // 刪除指定的商品
    @RequestMapping(value = "/product", method = RequestMethod.DELETE)
    public String deleteProduct(String productId) {
        productDao.deleteProduct(productId);
        return "redirect:/products";
    }
    // 獲取商品列表
    @ResponseBody
    @RequestMapping("/getProductList1")
    public List<Product> getProductList1() {
        List productList = productDao.getProductList();
        return productList;
    }
    // 修改商品信息
    @RequestMapping(value = "/edit-product")
    public String updateProduct(Product product) {
        productDao.updateProduct(product);
        return "redirect:/products";
    }
}

===》product_list.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--引入 jquery-->
    <script type="text/javaScript"
            src="../../js/jquery-3.6.0.min.js " th:src="@{/js/jquery-3.6.0.min.js}"></script>
</head>
<body>
<table th:border="1" th:cellspacing="0" th:cellpadding="0" style="text-align: center;">
    <thead>
    <th>商品id</th>
    <th>商品名</th>
    <th>商品價格</th>
    <th>商品庫存</th>
    <th>操作</th>
    </thead>
    <tbody th:id="tb">
    </tbody>
</table>
<br>
<!-- 作用:通過超鏈接控制表單的提交,將post請求轉(zhuǎn)換為delete請求 -->
<form id="delete_form" method="post" th:action="@{/product}">
    <!-- HiddenHttpMethodFilter要求:必須傳輸_method請求參數(shù)祸挪,并且值為最終的請求方式 -->
    <input type="hidden" name="_method" value="delete"/>
    <input type="hidden" name="productId" th:id="form-id"/>
</form>
<button id="btn">新增商品</button>
<div id="addWindow">
    <label id="x" style="position: absolute;top:2px;left: 95%;font-size: 25px;">x</label>
    <h4>新增商品</h4>
    <form th:action="@{/product}" method="post">
        <table id="table-box" style="margin: auto">
            <tr>
                <td>商品 ID:</td>
                <td><input type="text" id="productId" name="productId" required></td>
            </tr>
            <tr>
                <td>商品名稱:</td>
                <td><input type="text" id="productName" name="productName" required></td>
            </tr>
            <tr>
                <td>商品價格:</td>
                <td><input type="text" id="price" name="price" required></td>
            </tr>
            <tr>
                <td>商品庫存:</td>
                <td><input type="text" id="stock" name="stock" required></td>
            </tr>
            <tr>
                <td>商品簡介:</td>
                <td><textarea id="introduction" name="introduction" rows="10" cols="30"></textarea><br></td>
            </tr>
            <tr>
                <td colspan="2" align="center"><input id="addPro" type="submit" value="新增商品">
                    <input type="reset" id="reset" value="重置">
                </td>
            </tr>
        </table>
    </form>
</div>
<div id="backGround"></div>
<div id="editWindow">
    <label id="ex" style="position: absolute;top:2px;left: 95%;font-size: 25px;">x</label>
    <h4>修改商品</h4>
    <form th:action="@{/edit-product}" id="edit-form" method="post">
        <table id="edit-form-table" style="margin: auto">
            <tr>
                <td>商品 ID:</td>
                <td><input id="e-productId" type="text" name="productId" readonly></td>
            </tr>
            <tr>
                <td>商品名稱:</td>
                <td><input id="e-productName" type="text" name="productName" required></td>
            </tr>
            <tr>
                <td>商品價格:</td>
                <td><input id="e-price" type="text" name="price" required></td>
            </tr>
            <tr>
                <td>商品庫存:</td>
                <td><input id="e-stock" type="text" name="stock" required></td>
            </tr>
            <tr>
                <td>商品簡介:</td>
                <td><textarea id="e-introduction" name="introduction" rows="10" cols="30"></textarea>
                </td>
            </tr>
            <tr>
                <td colspan="2" align="center"><input type="submit" value="修改商品信息"></td>
            </tr>
        </table>
    </form>
</div>
<div id="edit-backGround"></div>
<div id="lookWindow">
    <label id="lx" style="position: absolute;top:2px;left: 95%;font-size: 25px;">x</label>
    <h4>商品詳情</h4>
    <table style="margin: auto">
        <tr>
            <td>商品 ID:</td>
            <td id="l-productId"></td>
        </tr>
        <tr>
            <td>商品名稱:</td>
            <td id="l-productName"></td>
        </tr>
        <tr>
            <td>商品價格:</td>
            <td id="l-price"></td>
        </tr>
        <tr>
            <td>商品庫存:</td>
            <td id="l-stock"></td>
        </tr>
        <tr>
            <td>商品簡介:</td>
            <td id="l-introduction"></td>
        </tr>
    </table>
</div>
<div id="look-backGround"></div>
<script type="text/javaScript">
    $(document).ready(function () {
        // 點擊新增商品锣披,彈出新增商品彈窗
        $("#btn").click(function () {
            $("#addWindow").slideDown(300);
            $("#backGround").show();
        });
        $("#x").click(function () {
            $("#addWindow").slideUp(300);
            $("#backGround").hide();
            $("#reset").trigger("click")
        });
        $("#ex").click(function () {
            $("#editWindow").slideUp(300);
            $("#edit-backGround").hide();
        });
        $("#lx").click(function () {
            $("#lookWindow").slideUp(300);
            $("#look-backGround").hide();
        });
        $("#look-close").click(function () {
            $("#lookWindow").slideUp(300);
            $("#look-backGround").hide();
        });
        /**
         * 填完數(shù)據(jù)后,點擊新增商品彈窗中的 新增商品 按鈕贿条,執(zhí)行新增商品操作
         */
        $("#addPro").click(function () {
            add();
            $("#addWindow").slideUp(300);
            $("#backGround").hide();
            $("#reset").trigger("click")
        });
        $("#editPro").click(function () {
            $("#edit-form").submit();
            $("#editWindow").slideUp(300);
            $("#edit-backGround").hide();
            $("#e-reset").trigger("click")
        });
    });
    $(function () {
        $.ajax({
            // 請求路徑
            url: "http://localhost:8080/helloSpringMVC/getProductList1",
            // 請求類型
            type: "get",
            // 定義發(fā)送請求的數(shù)據(jù)格式為JSON字符串
            contentType: "application/json;charset=utf-8",
            // 定義回調(diào)響應的數(shù)據(jù)格式為JSON字符串雹仿,該屬性可以省略
            dataType: "json",
            // 成功響應的結果
            success: function (data) {
                if (data != null) {
                    var html = "";
                    for (var i = 0; i < data.length; i++) {
                        var product = data[i];
                        html += "<tr>" +
                            "<td>" + product.productId + "</td>" +
                            "<td>" + product.productName + "</td>" +
                            "<td>" + product.price + "</td>" +
                            "<td>" + product.stock + "</td>" +
                            "<td><button  onclick='lookPage(" + product.productId + ")'>查看商品</button>" +
                            "<button  onclick='editPage(" + product.productId + ")';>修改商品</button>" +
                            "<button  onclick='deletePro(" + product.productId + ")';>刪除商品</button></td>" +
                            "</tr>"
                    }
                    $("#tb").html(html);
                }
            }
        });
    })
    function deletePro(productId) {
        var b = confirm("確認刪除id 為" + productId + " 的商品?");
        if (b) {
            var delete_form = $("#delete_form");
            $("#form-id").val(productId);
            delete_form.submit();
        }
    }
    // 執(zhí)行新增商品操作
    function add() {
        var productId = $("#productId").val();
        var productName = $("#productName").val();
        var price = $("#price").val();
        var introduction = $("#introduction").val();
        var stock = $("#stock").val();
        $.ajax({
            // 請求路徑
            url: "http://localhost:8080/springmvc-json-demo/product",
            // 請求類型
            type: "post",
            data: JSON.stringify({
                productId: productId,
                productName: productName,
                price: price,
                stock: stock,
                introduction: introduction
            }), // 定義發(fā)送請求的數(shù)據(jù)格式為JSON字符串
            contentType: "application/json;charset=utf-8",
            // 定義回調(diào)響應的數(shù)據(jù)格式為JSON字符串整以,該屬性可以省略
            dataType: "json",
            // 成功響應的結果
            success: function (data) {
                if (data != null) {
                    var product = data;
                    var html = "<tr>" +
                        "<td>" + product.productId + "</td>" +
                        "<td>" + product.productName + "</td>" +
                        "<td>" + product.price + "</td>" +
                        "<td>" + product.stock + "</td>" +
                        "<td><button onclick='lookPage(" + product.productId + ")'>查看商品</a>" +
                        "<button onclick='editPage(" + product.productId + ")';>修改商品</a>" +
                        "<button onclick='deletePro(" + product.productId + ")';>刪除商品</a></td>" +
                        "</tr>";
                    $("#tb").append(html);
                }
            }
        });
    }
    function lookPage(productId) {
        $("#lookWindow").slideDown(300);
        $("#look-backGround").show();
        $.ajax({
            // 請求路徑
            url: "http://localhost:8080/springmvc-json-demo/product/" + productId,
            // 請求類型
            type: "get",
            // 定義發(fā)送請求的數(shù)據(jù)格式為JSON字符串
            contentType: "application/json;charset=utf-8",
            // 定義回調(diào)響應的數(shù)據(jù)格式為JSON字符串胧辽,該屬性可以省略
            dataType: "json",
            // 成功響應的結果
            success: function (data) {
                if (data != null) {
                    $("#l-productId").html(data.productId);
                    $("#l-productName").html(data.productName);
                    $("#l-price").html(data.price);
                    $("#l-stock").html(data.stock);
                    $("#l-introduction").html(data.introduction);
                }
            }
        });
    }
    // 打開商品修改頁,并將商品信息回顯到彈窗中
    function editPage(productId) {
        $("#editWindow").slideDown(300);
        $("#edit-backGround").show();
        $.ajax({
            // 請求路徑
            url: "http://localhost:8080/springmvc-json-demo/product/" + productId,
            // 請求類型
            type: "get",
            // 定義發(fā)送請求的數(shù)據(jù)格式為JSON字符串
            contentType: "application/json;charset=utf-8",
            // 定義回調(diào)響應的數(shù)據(jù)格式為JSON字符串公黑,該屬性可以省略
            dataType: "json",
            // 成功響應的結果
            success: function (data) {
                if (data != null) {
                    var product = data;
                    $("#e-productId").val(data.productId);
                    $("#e-productName").val(data.productName);
                    $("#e-price").val(data.price);
                    $("#e-stock").val(data.stock);
                    $("#e-introduction").val(data.introduction);
                }
            }
        });
    }
</script>
<style type="text/css">
    #addWindow, #editWindow {
        display: none;
        position: absolute;
        top: 25%;
        left: 25%;
        width: 30%;
        height: 40%;
        padding: 20px;
        border: 3px solid #ccc;
        background-color: white;
        z-index: 2;
        overflow: auto;
    }
    #lookWindow {
        display: none;
        position: absolute;
        top: 25%;
        left: 25%;
        width: 30%;
        height: 30%;
        padding: 20px;
        border: 3px solid #ccc;
        background-color: white;
        z-index: 2;
        overflow: auto;
    }
    #backGround, #edit-backGround, #look-backGround {
        display: none;
        position: absolute;
        top: 0%;
        left: 0%;
        width: 100%;
        height: 1100px;
        background-color: black;
        z-index: 1;
        -moz-opacity: 0.8;
        opacity: .80;
        filter: alpha(opacity=88);
    }
    #x:hover, #lx:hover, #ex:hover {
        cursor: pointer;
        color: rgb(55, 198, 192);
    }
</style>
</body>
</html>
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末邑商,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子凡蚜,更是在濱河造成了極大的恐慌人断,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件朝蜘,死亡現(xiàn)場離奇詭異恶迈,居然都是意外死亡,警方通過查閱死者的電腦和手機芹务,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門蝉绷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人枣抱,你說我怎么就攤上這事熔吗。” “怎么了佳晶?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵桅狠,是天一觀的道長。 經(jīng)常有香客問我,道長中跌,這世上最難降的妖魔是什么咨堤? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮漩符,結果婚禮上一喘,老公的妹妹穿的比我還像新娘。我一直安慰自己嗜暴,他們只是感情好慢逾,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布携丁。 她就那樣靜靜地躺著,像睡著了一般揖膜。 火紅的嫁衣襯著肌膚如雪材部。 梳的紋絲不亂的頭發(fā)上授药,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天荆秦,我揣著相機與錄音背捌,去河邊找鬼。 笑死路狮,一個胖子當著我的面吹牛虫啥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播览祖,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼孝鹊,長吁一口氣:“原來是場噩夢啊……” “哼炊琉!你這毒婦竟也來了展蒂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤苔咪,失蹤者是張志新(化名)和其女友劉穎锰悼,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體团赏,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡箕般,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了舔清。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丝里。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖体谒,靈堂內(nèi)的尸體忽然破棺而出杯聚,到底是詐尸還是另有隱情,我是刑警寧澤抒痒,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布幌绍,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏傀广。R本人自食惡果不足惜颁独,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伪冰。 院中可真熱鬧誓酒,春花似錦、人聲如沸贮聂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寂汇。三九已至病往,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間骄瓣,已是汗流浹背停巷。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留榕栏,地道東北人畔勤。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像扒磁,于是被迫代替她去往敵國和親庆揪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355

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

  • 1妨托、什么是MVC 2缸榛、什么是SpringMVC 3、SpringMVC的特點 1兰伤、開發(fā)環(huán)境 2内颗、創(chuàng)建maven工程...
    小茅同學閱讀 278評論 0 0
  • SpringMVC原理分析 Spring Boot學習 5、Hello World探究 1敦腔、POM文件 1均澳、父項目...
    jack_jerry閱讀 1,296評論 0 1
  • 入門 介紹 Spring Boot Spring Boot 使您可以輕松地創(chuàng)建獨立的、生產(chǎn)級的基于 Spring ...
    Hsinwong閱讀 16,890評論 2 89
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,823評論 6 342
  • 1.spring集成web環(huán)境基本三層架構搭建 (1)在pom文件中需要添加兩個坐標 <dependency> <...
    安然如斯_d308閱讀 533評論 0 1