1. 程式人生 > >Java框架-SpringMVC的應用(json資料互動、控制器方法返回值、檔案上傳)

Java框架-SpringMVC的應用(json資料互動、控制器方法返回值、檔案上傳)

1. 搭建SpringMVC開發環境

1.1 建立專案,新增依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <
modelVersion
>
4.0.0</modelVersion> <groupId>com.azure</groupId> <artifactId>day56project_SpringMVC_day2</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!--匯入spring核心包--> <dependency> <
groupId
>
org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--匯入springMVC支援包--> <dependency> <groupId>org.springframework</
groupId
>
<artifactId>spring-webmvc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--servlet支援包--> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> </dependency> <!--日誌包--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies> </project>

1.2 web.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://java.sun.com/xml/ns/javaee"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">

   <!--設定springMVC前端控制器-->
   <servlet>
      <servlet-name>DispatcherServlet</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <!--載入springMVC配置檔案-->
      <init-param>
         <param-name>contextConfigLocation</param-name>
         <param-value>classpath:springMVC.xml</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
   </servlet>
   <!--設定攔截規則-->
   <servlet-mapping>
      <!--
      攔截請求規則:
         1. *.do:攔截作為.do字尾得請求
            要求:請求路徑字尾必須以.do結尾;
              缺點:不方便,每個請求都要寫上.do的字尾;不支援restful風格的請求
         2./ 表示攔截所有的請求,但不包含jsp請求
              注意:此時靜態資源(如html、css等)無法訪問。
      -->
      <servlet-name>DispatcherServlet</servlet-name>
      <url-pattern>/</url-pattern>
   </servlet-mapping>
</web-app>

1.3 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.xsd">

    <!--1. 開啟註解掃描-->
    <context:component-scan base-package="com.azure"></context:component-scan>
    <!--2. 配置檢視解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
    <!--3. 開啟mvc註解-->
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>

1.4 測試頁面index.html

由於在web.xml中前端控制器的攔截規則是/,動態資源(jsp)不會被攔截,而靜態資源(如html、css、js等)預設不能訪問。

1.4.1 攔截路徑設為/時靜態資源無法訪問的原因分析

  • tomcat伺服器訪問任何資源都是通過servlet把資源返回到瀏覽器客戶端。

  • 而訪問靜態資源不是使用servlet程式,而是預設通過DefaultServlet(預設servlet)把靜態資源返回到客戶端中。該預設servlet在tomcat伺服器啟動時預設就建立:

    在這裡插入圖片描述

  • 而我們在專案中配置攔截的路徑是/,則所有的資源都會進入我們專案新建的dispatcherServlet,而不會經過DefaultServlet,從而導致靜態資源無法被返回。

  • 所以解決方式有兩種:修改放行資源路徑,重新配置DefaultServlet.

1.4.2 指定放行路徑對靜態資源放行

  • 將資源放入包中,然後在springMVC.xml中指定放行資源路徑
  • 也可以單獨指定放行的資源,但是效率差
  • 注意:/pages/*/panges/**兩種寫法的差別
1.4.2.1 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.xsd">

    <!--1. 開啟註解掃描-->
    <context:component-scan base-package="com.azure"></context:component-scan>

    <!--2. 配置檢視解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!--3. 開啟mvc註解-->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!--4. 設定放行的靜態資源-->
    <!--使用mvc:resources標籤:
    屬性:
        mapping:指定對映路徑,即瀏覽器的訪問路徑
        location:表示對映路徑對應的實際物理路徑
    -->
    <!--放行指定的單個資源-->
    <mvc:resources mapping="/index.html" location="/index.html"/><!--表示放行根目錄下的index.html,之所以會報錯是idea不推薦這種配置方式-->

    <!--放行指定目錄下的所有資源-->
    <!--/pages/* :   表示pages目錄下的所有資源會被放行-->
    <!--/pages/**:   表示pages目錄及其子目錄下的所有資源會被放行-->
    <mvc:resources mapping="/pages/**" location="/pages/"/>
    <mvc:resources mapping="/css/**" location="/css/"/>
    <mvc:resources mapping="/js/**" location="/js/"/>
    <mvc:resources mapping="/image/**" location="/image/"/>

</beans>

1.4.3 使用tomcat的DefaultServlet處理靜態資源

  • 重新配置使用預設servlet處理靜態資源
1.4.3.1 web.xml配置調整
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://java.sun.com/xml/ns/javaee"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">

   <!--設定springMVC前端控制器-->
   <servlet>
      <servlet-name>DispatcherServlet</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <!--載入springMVC配置檔案-->
      <init-param>
         <param-name>contextConfigLocation</param-name>
         <param-value>classpath:springMVC.xml</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
   </servlet>
   <!--設定攔截規則-->
   <servlet-mapping>
      <!--
      攔截請求規則:
         1. *.do:攔截作為.do字尾得請求
            要求:請求路徑字尾必須以.do結尾;
              缺點:不方便,每個請求都要寫上.do的字尾;不支援restful風格的請求
         2./ 表示攔截所有的請求,但不包含jsp請求
              注意:此時靜態資源(如html、css等)無法訪問。
      -->
      <servlet-name>DispatcherServlet</servlet-name>
      <url-pattern>/</url-pattern>
   </servlet-mapping>
   
   <!--配置預設servlet處理指定靜態資源-->
   <servlet-mapping>
      <servlet-name>default</servlet-name>
      <url-pattern>*.html</url-pattern>
   </servlet-mapping>
   <servlet-mapping>
      <servlet-name>default</servlet-name>
      <url-pattern>*.js</url-pattern>
   </servlet-mapping>
</web-app>

2. 往域中存放資料

2.1 Model和ModelMap型別

  • 作用:作為方法引數時可以將資料儲存到request域中
  • 使用方法:Model和ModelMap作為控制器方法的引數

2.1.1 示例程式碼

2.1.1.1 控制類
@Controller
public class ModelController {

    /*Model作為方法引數*/
    @RequestMapping("/model")
    public String model(Model model) {
        model.addAttribute("JoJo","StarPlatinum" );
        return "success";
    }

    /*ModelMap作為方法引數*/
    @RequestMapping("/modelMap")
    public String modelMap(ModelMap modelMap) {
        modelMap.addAttribute("Dio","TheWorld" );
        return "success";
    }
}
2.1.1.2 success.jsp頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>success</title>
</head>
<body>
<h3>success!!</h3>
${requestScope.JoJo}<%--從request域中獲取資料--%>
${requestScope.Dio}
</body>
</html>

2.1.2 Model和ModelMap的異同

相同點:

  • 由於ModelMap的一個子類ExtendedModelMap實現Model介面,所以Model和ModelMap都是通過Model介面的子實現類BindingAwareModelMap實現儲存資料到域的功能;使用addAttribute方法時最終都是會呼叫request.setAttribute()方法;
  • 兩者從將資料儲存到request域中的角度上來看是一樣的。

不同點:

  • Model是介面,而ModelMap是類。它們有各自的功能,只是儲存資料到request域的功能上一致

2.2 SessionAttributes註解

  • 作用:自動把Model或ModelMap中的資料儲存到session域中,用於多次執行控制器方法間的引數共享。
  • 屬性:
    • names:用於存入Model或ModelMap中指定的屬性名稱的資料;
    • type:用於存入Model或ModelMap中指定型別的資料。該型別的所有資料都會存入session中。如果是基本資料型別,要使用對應包裝類的位元組碼物件

2.2.1 控制類

/**
 * 註解@SessionAttributes
 * 1.自動把Model或者ModelMap中的資料放入session
 * 2.屬性:
 *   names = {"JoJo","Dio"}, 把Model或者ModelMap中指定名稱的key的資料,自動放入session
 *   types = Integer.class 把Model或者ModelMap中指定型別的資料,自動放入session
 */
@Controller
@SessionAttributes(names = {"JoJo","Dio"},types = Integer.class)
public class SessionAttributesController {
    @RequestMapping("/sessionModel")
    public String sessionModel(Model model) {
        model.addAttribute("JoJo","StarPlatinum");
        model.addAttribute("Dio","TheWorld");
        model.addAttribute("num1",831143);
        model.addAttribute("num2","12345");//不滿足存入的條件,該條資料不會存入session
        return "success";
    }
    @RequestMapping("/sessionModelMap")
    public String sessionModelMap(ModelMap modelMap) {
        modelMap.addAttribute("JoJo","StarPlatinum");
        modelMap.addAttribute("Dio","TheWorld");
        return "success";
    }

    /*清除session的資料
    * 1.使用原始的session.setAttribute方法存入的,只能使用原始的方法清除;
    * 2.使用springMVC提供的方法自動存入的(即上面程式碼),只能使用@SessionAttributes註解清除.
    *   注意:方法的引數是SessionStatus,這個物件提供setComplete()方法清空自動存入session的資料,
    *        而原始方法存入的不會被清除
    */
    @RequestMapping("/del")
    public String del(SessionStatus sessionStatus){
        // 清空通過@SessionAttributes註解自動放入session中的資料
        sessionStatus.setComplete();
        return "success";
    }
}

2.2.2 success.jsp頁面

<body>
<h3>success!!</h3>

<h4>從request域中獲取資料</h4>
${requestScope.JoJo}
${requestScope.Dio}

<h4>從session域中獲取資料</h4>
${sessionScope.JoJo}
${sessionScope.Dio}
${sessionScope.num1}
${sessionScope.num2}

</body>

3. json資料的互動

3.1 使用的註解

3.1.1 @RequestBody

  • 作用:在處理器方法的形參上使用。把請求的json格式資料轉換為java物件

3.1.2 @ResponseBody

  • 在處理器方法返回值上使用,或在方法上使用。需要jackson支援包
  • 作用:將響應的java物件轉換為json格式的資料

3.2 新增依賴

  • 需要在pom.xml中匯入jackson支援包
<!--jackson支援包-->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.9.0</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.9.0</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.0</version>
</dependency>

3.3 引入jquery檔案,在springMVC.xml中配置

  • 由於上面已經在springMVC中設定放行/js/**的資源

3.4 在pages目錄下新建測試用html頁面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ajax</title>
    <script src="../js/jquery-3.3.1.min.js" type="text/javascript"></script>
    <script>
        $(function(){
            $("#ajaxPost").click(function(){
                $.ajax({
                    // 請求型別,這裡必須為post,否則無法使用requestBody
                    type : "post",
                    // 請求地址
                    url : "/responseBodyJson",
                    // 傳送給後臺的ajax請求資料
                    data:'{"id":100,"name":"jack","money":9.9}',
                    dataType:"json",
                    // 請求格式與編碼,避免亂碼
                    contentType:"application/json;charset=utf-8",
                    success : function(jsn){
                        alert("jsn="+jsn+"; jsn.id="+jsn.id+"; jsn.name="+jsn.name+"; jsn.money="+jsn.money);
                    }
                });
            });
        });
    </script>
</head>
<body>
<h2>RequestBody獲取請求JSON格式資料 & ResponseBody自動把物件轉json並響應</h2>
<button id="ajaxPost">測試ajax請求json與響應json</button>
</body>
</html>

3.5 建立Account實體類用來封裝資料

public class Account {
    private int id;
    private String name;
    private double money;

3.6 控制器類

@Controller
public class JsonController {

    @RequestMapping("/responseBodyJson")    //注意與頁面的ajax中的url保持一致
    @ResponseBody   //表示方法返回json格式(自動把返回物件轉json格式)