主頁 > 軟體設計 > 狂神說SpringMVC課堂筆記

狂神說SpringMVC課堂筆記

2021-02-13 12:11:36 軟體設計

文章目錄

  • SpringMVC
    • 1、回顧MVC
      • 1.1、什么是MVC
      • 1.2、Model1時代
      • 1.3、Model2時代
      • 1.4、回顧Servlet
    • 2、什么是SpringMVC
      • 2.1、概述
      • 2.2、中心控制器
      • 2.3、SpringMVC執行原理
    • 3、第一個MVC程式
      • 3.1、配置版
      • 3.2、注解版
      • 小結
    • 4、RestFul和控制器
      • 4.1、控制器Controller
      • 4.2、實作Controller介面
      • 使用注解@Controller
      • RequestMapping
      • RestFul 風格
      • 擴展:小黃鴨除錯法
    • 5、結果跳轉方式
      • 5.1、ModelAndView
      • 5.2、ServletAPI
      • 5.3、SpringMVC
    • 6、資料處理
      • 6.1、處理提交資料
      • 6.2、資料顯示到前端
      • 6.3、對比
    • 7、亂碼問題
    • 8、Json互動處理
      • 8.1、什么是JSON?
      • 8.2、**JSON 和 JavaScript 物件互轉**
      • 8.3、Controller回傳JSON資料
      • 8.4代碼優化
      • 8.5、測驗集合輸出
      • 8.6、輸出時間物件
      • 8.7、FastJson
    • 9、Ajax研究
      • 9.1、簡介
      • 9.2、偽造Ajax
      • 9.3、jQuery.ajax
      • 9.4、**Springmvc實作**
      • 9.5、注冊提示效果
      • 9.6、獲取baidu介面Demo
    • 10、攔截器
      • 10.1、概述
      • 10.2、自定義攔截器
      • 10.3、驗證用戶是否登錄 (認證用戶)
    • 11、檔案上傳和下載
      • 11.1、準備作業
      • 11.2、檔案上傳
      • 11.3、檔案下載
      • 11.3、檔案下載

SpringMVC

1、回顧MVC

1.1、什么是MVC

  • MVC是模型(Model)、視圖(View)、控制器(Controller)的簡寫,是一種軟體設計規范,
  • 是將業務邏輯、資料、顯示分離的方法來組織代碼,
  • MVC主要作用是降低了視圖與業務邏輯間的雙向偶合
  • MVC不是一種設計模式,MVC是一種架構模式,當然不同的MVC存在差異,

**Model(模型):**資料模型,提供要展示的資料,因此包含資料和行為,可以認為是領域模型或JavaBean組件(包含資料和行為),不過現在一般都分離開來:Value Object(資料Dao) 和 服務層(行為Service),也就是模型提供了模型資料查詢和模型資料的狀態更新等功能,包括資料和業務,

**View(視圖):**負責進行模型的展示,一般就是我們見到的用戶界面,客戶想看到的東西,

**Controller(控制器):**接收用戶請求,委托給模型進行處理(狀態改變),處理完畢后把回傳的模型資料回傳給視圖,由視圖負責展示,也就是說控制器做了個調度員的作業,

最典型的MVC就是JSP + servlet + javabean的模式,[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-RvIA8L7I-1613122851049)(SpringMVC課堂筆記.assets/640.png)]
在這里插入圖片描述

1.2、Model1時代

  • 在web早期的開發中,通常采用的都是Model1,
  • Model1中,主要分為兩層,視圖層和模型層,

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iqOBGDEs-1613122851051)(SpringMVC課堂筆記.assets/641.png)]
在這里插入圖片描述

Model1優點:架構簡單,比較適合小型專案開發;

Model1缺點:JSP職責不單一,職責過重,不便于維護;

1.3、Model2時代

Model2把一個專案分成三部分,包括視圖、控制、模型,

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-rdEwr6nt-1613122851052)(SpringMVC課堂筆記.assets/642.webp)]
在這里插入圖片描述

  1. 用戶發請求
  2. Servlet接收請求資料,并呼叫對應的業務邏輯方法
  3. 業務處理完畢,回傳更新后的資料給servlet
  4. servlet轉向到JSP,由JSP來渲染頁面
  5. 回應給前端更新后的頁面

職責分析:

Controller:控制器

  1. 取得表單資料
  2. 呼叫業務邏輯
  3. 轉向指定的頁面

Model:模型

  1. 業務邏輯
  2. 保存資料的狀態

View:視圖

  1. 顯示頁面

Model2這樣不僅提高的代碼的復用率與專案的擴展性,且大大降低了專案的維護成本,Model 1模式的實作比較簡單,適用于快速開發小規模專案,Model1中JSP頁面身兼View和Controller兩種角色,將控制邏輯和表現邏輯混雜在一起,從而導致代碼的重用性非常低,增加了應用的擴展性和維護的難度,Model2消除了Model1的缺點,

1.4、回顧Servlet

  1. 新建一個Maven工程當做父工程!pom依賴!

    <dependencies>
       <dependency>
           <groupId>junit</groupId>
           <artifactId>junit</artifactId>
           <version>4.12</version>
       </dependency>
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-webmvc</artifactId>
           <version>5.1.9.RELEASE</version>
       </dependency>
       <dependency>
           <groupId>javax.servlet</groupId>
           <artifactId>servlet-api</artifactId>
           <version>2.5</version>
       </dependency>
       <dependency>
           <groupId>javax.servlet.jsp</groupId>
           <artifactId>jsp-api</artifactId>
           <version>2.2</version>
       </dependency>
       <dependency>
           <groupId>javax.servlet</groupId>
           <artifactId>jstl</artifactId>
           <version>1.2</version>
       </dependency>
    </dependencies>
    
  2. 建立一個Moudle:springmvc-01-servlet , 添加Web app的支持!

  3. 匯入servlet 和 jsp 的 jar 依賴

    <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>servlet-api</artifactId>
       <version>2.5</version>
    </dependency>
    <dependency>
       <groupId>javax.servlet.jsp</groupId>
       <artifactId>jsp-api</artifactId>
       <version>2.2</version>
    </dependency>
    
  4. 撰寫一個Servlet類,用來處理用戶的請求

    package nuc.ss.servlet;
    
    //實作Servlet介面
    public class HelloServlet extends HttpServlet {
       @Override
       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
           //取得引數
           String method = req.getParameter("method");
           if (method.equals("add")){
               req.getSession().setAttribute("msg","執行了add方法");
          }
           if (method.equals("delete")){
               req.getSession().setAttribute("msg","執行了delete方法");
          }
           //業務邏輯
           //視圖跳轉
           req.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(req,resp);
      }
    
       @Override
       protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
           doGet(req,resp);
      }
    }
    
  5. 撰寫Hello.jsp,在WEB-INF目錄下新建一個jsp的檔案夾,新建hello.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
       <title>Kuangshen</title>
    </head>
    <body>
    ${msg}
    </body>
    </html>
    
  6. 在web.xml中注冊Servlet

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
            version="4.0">
       <servlet>
           <servlet-name>HelloServlet</servlet-name>
           <servlet-class>com.kuang.servlet.HelloServlet</servlet-class>
       </servlet>
       <servlet-mapping>
           <servlet-name>HelloServlet</servlet-name>
           <url-pattern>/user</url-pattern>
       </servlet-mapping>
    
    </web-app>
    
  7. 配置Tomcat,并啟動測驗

    • localhost:8080/user?method=add
    • localhost:8080/user?method=delete

MVC框架要做哪些事情

  1. 將url映射到java類或java類的方法 .
  2. 封裝用戶提交的資料 .
  3. 處理請求–呼叫相關的業務處理–封裝回應資料 .
  4. 將回應的資料進行渲染 . jsp / html 等表示層資料 .

說明:

? 常見的服務器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF;常見前端MVC框架:vue、angularjs、react、backbone;由MVC演化出了另外一些模式如:MVP、MVVM 等等…

2、什么是SpringMVC

2.1、概述

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-AKI5UwOn-1613122851052)(SpringMVC課堂筆記.assets/1594598769272.png)]
在這里插入圖片描述

Spring MVC是Spring Framework的一部分,是基于Java實作MVC的輕量級Web框架,

查看官方檔案:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/web.html#spring-web

我們為什么要學習SpringMVC呢?

Spring MVC的特點:

  1. 輕量級,簡單易學
  2. 高效 , 基于請求回應的MVC框架
  3. 與Spring兼容性好,無縫結合
  4. 約定優于配置
  5. 功能強大:RESTful、資料驗證、格式化、本地化、主題等
  6. 簡潔靈活

Spring的web框架圍繞DispatcherServlet [ 調度Servlet ] 設計,

DispatcherServlet的作用是將請求分發到不同的處理器,從Spring 2.5開始,使用Java 5或者以上版本的用戶可以采用基于注解形式進行開發,十分簡潔;

正因為SpringMVC好 , 簡單 , 便捷 , 易學 , 天生和Spring無縫集成(使用SpringIoC和Aop) , 使用約定優于配置 . 能夠進行簡單的junit測驗 . 支持Restful風格 .例外處理 , 本地化 , 國際化 , 資料驗證 , 型別轉換 , 攔截器 等等…所以我們要學習 .

最重要的一點還是用的人多 , 使用的公司多 .

2.2、中心控制器

  • Spring的web框架圍繞DispatcherServlet設計,DispatcherServlet的作用是將請求分發到不同的處理器,從Spring 2.5開始,使用Java 5或者以上版本的用戶可以采用基于注解的controller宣告方式,

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5C6IBAho-1613122851053)(SpringMVC課堂筆記.assets/1594600307868.png)]
    在這里插入圖片描述

    Spring MVC框架像許多其他MVC框架一樣, 以請求為驅動 , 圍繞一個中心Servlet分派請求及提供其他功能DispatcherServlet是一個實際的Servlet (它繼承自HttpServlet 基類)

  • SpringMVC的原理如下圖所示:

    當發起請求時被前置的控制器攔截到請求,根據請求引數生成代理請求,找到請求對應的實際控制器,控制器處理請求,創建資料模型,訪問資料庫,將模型回應給中心控制器,控制器使用模型與視圖渲染視圖結果,將結果回傳給中心控制器,再將結果回傳給請求者,

    原圖

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-1LcJHSqU-1613122851055)(SpringMVC課堂筆記.assets/mvc.png)]
    在這里插入圖片描述

中文圖

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-wNm8ZtOs-1613122851056)(SpringMVC課堂筆記.assets/1594603929224.png)]
在這里插入圖片描述

2.3、SpringMVC執行原理

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-l77Lx03H-1613122851057)(SpringMVC課堂筆記.assets/1594606134497.png)]
在這里插入圖片描述

圖為SpringMVC的一個較完整的流程圖,實線表示SpringMVC框架提供的技術,不需要開發者實作,虛線表示需要開發者實作,

簡要分析執行流程

  1. DispatcherServlet表示前置控制器,是整個SpringMVC的控制中心,用戶發出請求,DispatcherServlet接收請求并攔截請求,

    • 我們假設請求的url為 : http://localhost:8080/SpringMVC/hello

    • 如上url拆分成三部分:

    • http://localhost:8080 ------> 服務器域名

    • SpringMVC ------> 部署在服務器上的web站點

    • hello ------> 表示控制器

    • 通過分析,如上url表示為:請求位于服務器localhost:8080上的SpringMVC站點的hello控制器,

  2. HandlerMapping為處理器映射,DispatcherServlet呼叫HandlerMapping,HandlerMapping根據請求url查找Handler,

  3. HandlerExecution表示具體的Handler,其主要作用是根據url查找控制器,如上url被查找控制器為:hello,

  4. HandlerExecution將決議后的資訊傳遞給DispatcherServlet,如決議控制器映射等,

  5. HandlerAdapter表示處理器配接器,其按照特定的規則去執行Handler,

  6. Handler讓具體的Controller執行,

  7. Controller將具體的執行資訊回傳給HandlerAdapter,如ModelAndView,

  8. HandlerAdapter將視圖邏輯名或模型傳遞給DispatcherServlet,

  9. DispatcherServlet呼叫視圖決議器(ViewResolver)來決議HandlerAdapter傳遞的邏輯視圖名,

  10. 視圖決議器將決議的邏輯視圖名傳給DispatcherServlet,

  11. DispatcherServlet根據視圖決議器決議的視圖結果,呼叫具體的視圖,

  12. 最終視圖呈現給用戶,

3、第一個MVC程式

3.1、配置版

  1. 新建一個Moudle , springmvc-02-hello , 添加web的支持!

  2. 確定匯入了SpringMVC 的依賴!

  3. 配置web.xml , 注冊DispatcherServlet

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
            version="4.0">
    
       <!--1.注冊DispatcherServlet-->
       <servlet>
           <servlet-name>springmvc</servlet-name>
           <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
           <!--關聯一個springmvc的組態檔:【servlet-name】-servlet.xml-->
           <init-param>
               <param-name>contextConfigLocation</param-name>
               <param-value>classpath:springmvc-servlet.xml</param-value>
           </init-param>
           <!--啟動級別-1-->
           <load-on-startup>1</load-on-startup>
       </servlet>
    
       <!--/ 匹配所有的請求;(不包括.jsp)-->
       <!--/* 匹配所有的請求;(包括.jsp)-->
       <servlet-mapping>
           <servlet-name>springmvc</servlet-name>
           <url-pattern>/</url-pattern>
       </servlet-mapping>
    
    </web-app>
    
  4. 撰寫SpringMVC 的 組態檔!名稱:springmvc-servlet.xml : [servletname]-servlet.xml

    說明,這里的名稱要求是按照官方來的

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    </beans>
    
  5. 添加 處理映射器(可省略)

    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    
  6. 添加 處理器配接器(可省略)

    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
    
  7. 添加 視圖決議器

    <!--視圖決議器:DispatcherServlet給他的ModelAndView-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
       <!--前綴-->
       <property name="prefix" value="/WEB-INF/jsp/"/>
       <!--后綴-->
       <property name="suffix" value=".jsp"/>
    </bean>
    
  8. 撰寫我們要操作業務Controller ,要么實作Controller介面,要么增加注解;需要回傳一個ModelAndView,裝資料,封視圖;

    package nuc.ss.controller;
    
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.Controller;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    //注意:這里我們先匯入Controller介面
    public class HelloController implements Controller {
    
       public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
           //ModelAndView 模型和視圖
           ModelAndView mv = new ModelAndView();
    
           //封裝物件,放在ModelAndView中,Model
           mv.addObject("msg","HelloSpringMVC!");
           //封裝要跳轉的視圖,放在ModelAndView中
           mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp
           return mv;
      }
    }
    
  9. 將自己的類交給SpringIOC容器,注冊bean

    <!--Handler-->
    <bean id="/hello" class="nuc.ss.controller.HelloController"/>
    
  10. 寫要跳轉的jsp頁面,顯示ModelandView存放的資料,以及我們的正常頁面;

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
       <title>Kuangshen</title>
    </head>
    <body>
    ${msg}
    </body>
    </html>
    
  11. 配置Tomcat 啟動測驗!

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qy5e45Le-1613122851059)(SpringMVC課堂筆記.assets/1595124994780.png)]
在這里插入圖片描述

可能遇到的問題:訪問出現404,排查步驟:

  1. 查看控制臺輸出,看一下是不是缺少了什么jar包,
  2. 如果jar包存在,顯示無法輸出,就在IDEA的專案發布中,添加lib依賴!
  3. 重啟Tomcat 即可解決!

小結:我們來看個注解版實作,這才是SpringMVC的精髓,

3.2、注解版

  1. 新建一個Moudle,springmvc-03-hello-annotation ,添加web支持!

  2. 由于Maven可能存在資源過濾的問題,我們將配置完善

    <build>
       <resources>
           <resource>
               <directory>src/main/java</directory>
               <includes>
                   <include>**/*.properties</include>
                   <include>**/*.xml</include>
               </includes>
               <filtering>false</filtering>
           </resource>
           <resource>
               <directory>src/main/resources</directory>
               <includes>
                   <include>**/*.properties</include>
                   <include>**/*.xml</include>
               </includes>
               <filtering>false</filtering>
           </resource>
       </resources>
    </build>
    
  3. 在pom.xml檔案引入相關的依賴:主要有Spring框架核心庫、Spring MVC、servlet , JSTL等,我們在父依賴中已經引入了!

  4. 配置web.xml

    注意點:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
            version="4.0">
    
       <!--1.注冊servlet-->
       <servlet>
           <servlet-name>SpringMVC</servlet-name>
           <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
           <!--通過初始化引數指定SpringMVC組態檔的位置,進行關聯-->
           <init-param>
               <param-name>contextConfigLocation</param-name>
               <param-value>classpath:springmvc-servlet.xml</param-value>
           </init-param>
           <!-- 啟動順序,數字越小,啟動越早 -->
           <load-on-startup>1</load-on-startup>
       </servlet>
    
       <!--所有請求都會被springmvc攔截 -->
       <servlet-mapping>
           <servlet-name>SpringMVC</servlet-name>
           <url-pattern>/</url-pattern>
       </servlet-mapping>
    
    </web-app>
    
  5. / 和 /* 的區別:

    • < url-pattern > / </ url-pattern > 不會匹配到.jsp, 只針對我們撰寫的請求;即:.jsp 不會進入spring的 DispatcherServlet類 ,
    • < url-pattern > /* </ url-pattern > 會匹配 *.jsp,會出現回傳 jsp視圖 時再次進入spring的DispatcherServlet 類,導致找不到對應的controller所以報404錯,
  6. 添加Spring MVC組態檔

    在resource目錄下添加springmvc-servlet.xml組態檔,配置的形式與Spring容器配置基本類似,為了支持基于注解的IOC,設定了自動掃描包的功能,具體配置資訊如下:

    <?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">
    
       <!-- 自動掃描包,讓指定包下的注解生效,由IOC容器統一管理 -->
       <context:component-scan base-package="nuc.ss.controller"/>
       <!-- 讓Spring MVC不處理靜態資源 -->
       <mvc:default-servlet-handler />
       <!--
       支持mvc注解驅動
           在spring中一般采用@RequestMapping注解來完成映射關系
           要想使@RequestMapping注解生效
           必須向背景關系中注冊DefaultAnnotationHandlerMapping
           和一個AnnotationMethodHandlerAdapter實體
           這兩個實體分別在類級別和方法級別處理,
           而annotation-driven配置幫助我們自動完成上述兩個實體的注入,
        -->
       <mvc:annotation-driven />
    
       <!-- 視圖決議器 -->
       <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
             id="internalResourceViewResolver">
           <!-- 前綴 -->
           <property name="prefix" value="/WEB-INF/jsp/" />
           <!-- 后綴 -->
           <property name="suffix" value=".jsp" />
       </bean>
    
    </beans>
    

在視圖決議器中我們把所有的視圖都存放在/WEB-INF/目錄下,這樣可以保證視圖安全,因為這個目錄下的檔案,客戶端不能直接訪問,

  • 讓IOC的注解生效

  • 靜態資源過濾 :HTML . JS . CSS . 圖片 , 視頻 …

    • MVC的注解驅動
    • 配置視圖決議器
  1. 創建Controller

    撰寫一個Java控制類:nuc.ss.controller.HelloController , 注意編碼規范

    package nuc.ss.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    @RequestMapping("/HelloController")
    public class HelloController {
    
       //真實訪問地址 : 專案名/HelloController/hello
       @RequestMapping("/hello")
       public String sayHello(Model model){
           //向模型中添加屬性msg與值,可以在JSP頁面中取出并渲染
           model.addAttribute("msg","hello,SpringMVC");
           //web-inf/jsp/hello.jsp
           return "hello";
      }
    }
    
    • @Controller是為了讓Spring IOC容器初始化時自動掃描到;
    • @RequestMapping是為了映射請求路徑,這里因為類與方法上都有映射所以訪問時應該是/HelloController/hello;
    • 方法中宣告Model型別的引數是為了把Action中的資料帶到視圖中;
    • 方法回傳的結果是視圖的名稱hello,加上組態檔中的前后綴變成WEB-INF/jsp/hello.jsp
  2. 創建視圖層

    在WEB-INF/ jsp目錄中創建hello.jsp , 視圖可以直接取出并展示從Controller帶回的資訊;

    可以通過EL表示取出Model中存放的值,或者物件;

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
       <title>SpringMVC</title>
    </head>
    <body>
    ${msg}
    </body>
    </html>
    
  3. 配置Tomcat運行

    配置Tomcat , 開啟服務器 , 訪問 對應的請求路徑!

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-gbDzUuZt-1613122851060)(SpringMVC課堂筆記.assets/1594622304382.png)]
    在這里插入圖片描述

    OK,運行成功!

小結

實作步驟其實非常的簡單:

  1. 新建一個web專案
  2. 匯入相關jar包
  3. 撰寫web.xml , 注冊DispatcherServlet
  4. 撰寫springmvc組態檔
  5. 接下來就是去創建對應的控制類 , controller
  6. 最后完善前端視圖和controller之間的對應
  7. 測驗運行除錯.

使用springMVC必須配置的三大件

處理器映射器、處理器配接器、視圖決議器

通常,我們只需要手動配置視圖決議器,而處理器映射器處理器配接器只需要開啟注解驅動即可,而省去了大段的xml配置

4、RestFul和控制器

4.1、控制器Controller

  • 控制器復雜提供訪問應用程式的行為,通常通過介面定義或注解定義兩種方法實作,

  • 控制器負責決議用戶的請求并將其轉換為一個模型,

  • 在Spring MVC中一個控制器類可以包含多個方法

  • 在Spring MVC中,對于Controller的配置方式有很多種

4.2、實作Controller介面

Controller是一個介面,在org.springframework.web.servlet.mvc包下,介面中只有一個方法;

//實作該介面的類獲得控制器功能
public interface Controller {
   //處理請求且回傳一個模型與視圖物件
   ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}

測驗

  1. 新建一個Moudle,springmvc-04-controller!

    • mvc的組態檔只留下 視圖決議器!
  2. 撰寫一個Controller類,ControllerTest1

    //定義控制器
    //注意點:不要導錯包,實作Controller介面,重寫方法;
    public class ControllerTest1 implements Controller {
    
       public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
           //回傳一個模型視圖物件
           ModelAndView mv = new ModelAndView();
           mv.addObject("msg","Test1Controller");
           mv.setViewName("test");
           return mv;
      }
    }
    
  3. 撰寫完畢后,去Spring組態檔中注冊請求的bean;name對應請求路徑,class對應處理請求的類

    <bean name="/t1" class="nuc.ss.controller.ControllerTest1"/>
    
  4. 撰寫前端test.jsp,注意在WEB-INF/jsp目錄下撰寫,對應我們的視圖決議器

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
       <title>Kuangshen</title>
    </head>
    <body>
    ${msg}
    </body>
    </html>
    
  5. 配置Tomcat運行測驗,我這里沒有專案發布名配置的就是一個 / ,所以請求不用加專案名,OK!

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xn69Bm6v-1613122851061)(SpringMVC課堂筆記.assets/1595128496794.png)]
    在這里插入圖片描述

說明:

  • 實作介面Controller定義控制器是較老的辦法

  • 缺點是:一個控制器中只有一個方法,如果要多個方法則需要定義多個Controller;定義的方式比較麻煩;

使用注解@Controller

  • @Controller注解型別用于宣告Spring類的實體是一個控制器(在講IOC時還提到了另外3個注解);

  • Spring可以使用掃描機制來找到應用程式中所有基于注解的控制器類,為了保證Spring能找到你的控制器,需要在組態檔中宣告組件掃描,

    <!-- 自動掃描指定的包,下面所有注解類交給IOC容器管理 -->
    <context:component-scan base-package="nuc.ss.controller"/>
    
  • 增加一個ControllerTest2類,使用注解實作;

    //@Controller注解的類會自動添加到Spring背景關系中
    @Controller
    public class ControllerTest2{
    
       //映射訪問路徑
       @RequestMapping("/t2")
       public String index(Model model){
           //Spring MVC會自動實體化一個Model物件用于向視圖中傳值
           model.addAttribute("msg", "ControllerTest2");
           //回傳視圖位置
           return "test";
      }
    }
    
  • 運行tomcat測驗

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-E1opAo2b-1613122851062)(SpringMVC課堂筆記.assets/1595128649687.png)]

    在這里插入圖片描述

可以發現,我們的兩個請求都可以指向一個視圖(test),但是頁面結果的結果是不一樣的,從這里可以看出視圖是被復用的,而控制器與視圖之間是弱偶合關系,

注解方式是平時使用的最多的方式!

RequestMapping

@RequestMapping

  • @RequestMapping注解用于映射url到控制器類或一個特定的處理程式方法,可用于類或方法上,用于類上,表示類中的所有回應請求的方法都是以該地址作為父路徑,

  • 為了測驗結論更加準確,我們可以加上一個專案名測驗 myweb

  • 只注解在方法上面

    @Controller
    public class TestController {
       @RequestMapping("/h1")
       public String test(){
           return "test";
      }
    }
    

    訪問路徑:http://localhost:8080 / 專案名 / h1

  • 同時注解類與方法

    @Controller
    @RequestMapping("/admin")
    public class TestController {
       @RequestMapping("/h1")
       public String test(){
           return "test";
      }
    }
    

    訪問路徑:http://localhost:8080 / 專案名/ admin /h1 , 需要先指定類的路徑再指定方法的路徑;

RestFul 風格

概念

Restful就是一個資源定位及資源操作的風格,不是標準也不是協議,只是一種風格,基于這個風格設計的軟體可以更簡潔,更有層次,更易于實作快取等機制,

功能

資源:互聯網所有的事物都可以被抽象為資源

資源操作:使用POST、DELETE、PUT、GET,使用不同方法對資源進行操作,

分別對應 添加、 洗掉、修改、查詢,

傳統方式操作資源 :通過不同的引數來實作不同的效果!方法單一,post 和 get

? http://127.0.0.1/item/queryItem.action?id=1 查詢,GET

? http://127.0.0.1/item/saveItem.action 新增,POST

? http://127.0.0.1/item/updateItem.action 更新,POST

? http://127.0.0.1/item/deleteItem.action?id=1 洗掉,GET或POST

使用RESTful操作資源 :可以通過不同的請求方式來實作不同的效果!如下:請求地址一樣,但是功能可以不同!

? http://127.0.0.1/item/1 查詢,GET

? http://127.0.0.1/item 新增,POST

? http://127.0.0.1/item 更新,PUT

? http://127.0.0.1/item/1 洗掉,DELETE

學習測驗

  1. 在新建一個類 RestFulController

    @Controller
    public class RestFulController {}
    
  2. 在Spring MVC中可以使用 @PathVariable 注解,讓方法引數的值對應系結到一個URI模板變數上,

    @Controller
    public class RestFulController {
    
       //映射訪問路徑
       @RequestMapping("/add/{p1}/{p2}")
       public String index(@PathVariable int p1, @PathVariable int p2, Model model){
           
           int result = p1+p2;
           //Spring MVC會自動實體化一個Model物件用于向視圖中傳值
           model.addAttribute("msg", "結果:"+result);
           //回傳視圖位置
           return "test";
           
      }
       
    }
    
  3. 我們來測驗請求查看下

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-fqjEWtDc-1613122851063)(SpringMVC課堂筆記.assets/1595129216809.png)]
    在這里插入圖片描述

  4. 思考:使用路徑變數的好處?

    • 使路徑變得更加簡潔;

    • 獲得引數更加方便,框架會自動進行型別轉換,

    • 通過路徑變數的型別可以約束訪問引數,如果型別不一樣,則訪問不到對應的請求方法,如這里訪問是的路徑是/add/1/a,則路徑與方法不匹配,而不會是引數轉換失敗,

      [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-SHBV02h4-1613122851063)(SpringMVC課堂筆記.assets/1595129271494.png)]
      在這里插入圖片描述

  5. 我們來修改下對應的引數型別,再次測驗

    //映射訪問路徑
    @RequestMapping("/add/{p1}/{p2}")
    public String index(@PathVariable int p1, @PathVariable String p2, Model model){
    
       String result = p1+p2;
       //Spring MVC會自動實體化一個Model物件用于向視圖中傳值
       model.addAttribute("msg", "結果:"+result);
       //回傳視圖位置
       return "test";
    
    }
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3gVukMxl-1613122851063)(SpringMVC課堂筆記.assets/1595129577077.png)]
    在這里插入圖片描述

使用method屬性指定請求型別

用于約束請求的型別,可以收窄請求范圍,指定請求謂詞的型別如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等

我們來測驗一下:

  • 增加一個方法

    //映射訪問路徑,必須是POST請求
    @RequestMapping(value = "/hello",method = {RequestMethod.POST})
    public String index2(Model model){
       model.addAttribute("msg", "hello!");
       return "test";
    }
    
  • 我們使用瀏覽器地址欄進行訪問默認是Get請求,會報錯405:

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yu3bqIg5-1613122851064)(SpringMVC課堂筆記.assets/1595129829057.png)]
    在這里插入圖片描述

  • 如果將POST修改為GET則正常了;

    //映射訪問路徑,必須是Get請求
    @RequestMapping(value = "/hello",method = {RequestMethod.GET})
    public String index2(Model model){
       model.addAttribute("msg", "hello!");
       return "test";
    }
    

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tbzf4pRk-1613122851064)(SpringMVC課堂筆記.assets/1595129889298.png)]
    在這里插入圖片描述

小結:

Spring MVC 的 @RequestMapping 注解能夠處理 HTTP 請求的方法, 比如 GET, PUT, POST, DELETE 以及 PATCH,

所有的地址欄請求默認都會是 HTTP GET 型別的,

方法級別的注解變體有如下幾個:組合注解

@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping

@GetMapping 是一個組合注解,平時使用的會比較多!

它所扮演的是 @RequestMapping(method =RequestMethod.GET) 的一個快捷方式,

擴展:小黃鴨除錯法

場景一:我們都有過向別人(甚至可能向完全不會編程的人)提問及解釋編程問題的經歷,但是很多時候就在我們解釋的程序中自己卻想到了問題的解決方案,然后對方卻一臉茫然,

場景二:你的同行跑來問你一個問題,但是當他自己把問題說完,或說到一半的時候就想出答案走了,留下一臉茫然的你,

其實上面兩種場景現象就是所謂的小黃鴨除錯法(Rubber Duck Debuging),又稱橡皮鴨除錯法,它是我們軟體工程中最常使用除錯方法之一,

img

此概念據說來自《程式員修煉之道》書中的一個故事,傳說程式大師隨身攜帶一只小黃鴨,在除錯代碼的時候會在桌上放上這只小黃鴨,然后詳細地向鴨子解釋每行代碼,然后很快就將問題定位修復了,

5、結果跳轉方式

5.1、ModelAndView

設定ModelAndView物件 , 根據view的名稱 , 和視圖決議器跳到指定的頁面 .

頁面 : {視圖決議器前綴} + viewName +{視圖決議器后綴}

<!-- 視圖決議器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
     id="internalResourceViewResolver">
   <!-- 前綴 -->
   <property name="prefix" value="/WEB-INF/jsp/" />
   <!-- 后綴 -->
   <property name="suffix" value=".jsp" />
</bean>

對應的controller類

public class ControllerTest1 implements Controller {

   public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
       //回傳一個模型視圖物件
       ModelAndView mv = new ModelAndView();
       mv.addObject("msg","ControllerTest1");
       mv.setViewName("test");
       return mv;
  }
}

5.2、ServletAPI

ServletAPI

通過設定ServletAPI , 不需要視圖決議器 .

  1. 通過HttpServletResponse進行輸出

  2. 通過HttpServletResponse實作重定向

  3. 通過HttpServletResponse實作轉發

    @Controller
    public class ResultGo {
    
       @RequestMapping("/result/t1")
       public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
           rsp.getWriter().println("Hello,Spring BY servlet API");
      }
    
       @RequestMapping("/result/t2")
       public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
           rsp.sendRedirect("/index.jsp");
      }
    
       @RequestMapping("/result/t3")
       public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
           //轉發
           req.setAttribute("msg","/result/t3");
           req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);
      }
    
    }
    

5.3、SpringMVC

通過SpringMVC來實作轉發和重定向 - 無需視圖決議器;

測驗前,需要將視圖決議器注釋掉

  • 默認為forward轉發(也可以加上
  • redirect轉發需特別加
@Controller
public class ResultSpringMVC {
   @RequestMapping("/rsm/t1")
   public String test1(){
       //轉發
       return "/index.jsp";
  }

   @RequestMapping("/rsm/t2")
   public String test2(){
       //轉發二
       return "forward:/index.jsp";
  }

   @RequestMapping("/rsm/t3")
   public String test3(){
       //重定向
       return "redirect:/index.jsp";
  }
}

通過SpringMVC來實作轉發和重定向 - 有視圖決議器;

重定向 , 不需要視圖決議器 , 本質就是重新請求一個新地方嘛 , 所以注意路徑問題.

可以重定向到另外一個請求實作 .

  • 默認為forward轉發(不可以加上
  • redirect轉發需特別加
@Controller
public class ResultSpringMVC2 {
   @RequestMapping("/rsm2/t1")
   public String test1(){
       //轉發
       return "test";
  }

   @RequestMapping("/rsm2/t2")
   public String test2(){
       //重定向
       return "redirect:/index.jsp";
       //return "redirect:hello.do"; //hello.do為另一個請求/
  }

}

6、資料處理

6.1、處理提交資料

1、提交的域名稱和處理方法的引數名一致

提交資料 : http://localhost:8080/hello?name=kuangshen

處理方法 :

@RequestMapping("/hello")
public String hello(String name){
   System.out.println(name);
   return "hello";
}

后臺輸出 : kuangshen

2、提交的域名稱和處理方法的引數名不一致

提交資料 : http://localhost:8080/hello?username=kuangshen

處理方法 :

//@RequestParam("username") : username提交的域的名稱 .
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name){
   System.out.println(name);
   return "hello";
}

后臺輸出 : kuangshen

3、提交的是一個物件

要求提交的表單域和物件的屬性名一致 , 引數使用物件即可

  1. 物體類

    public class User {
       private int id;
       private String name;
       private int age;
       //構造
       //get/set
       //tostring()
    }
    
  2. 提交資料 : http://localhost:8080/mvc04/user?name=kuangshen&id=1&age=15

  3. 處理方法 :

    @RequestMapping("/user")
    public String user(User user){
       System.out.println(user);
       return "hello";
    }
    

后臺輸出 : User { id=1, name=‘kuangshen’, age=15 }

說明:如果使用物件的話,前端傳遞的引數名和物件名必須一致,否則就是null,

6.2、資料顯示到前端

第一種 : 通過ModelAndView

我們前面一直都是如此 . 就不過多解釋

public class ControllerTest1 implements Controller {

   public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
       //回傳一個模型視圖物件
       ModelAndView mv = new ModelAndView();
       mv.addObject("msg","ControllerTest1");
       mv.setViewName("test");
       return mv;
  }
}

第二種 : 通過ModelMap

ModelMap

@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap modelMap){
   //封裝要顯示到視圖中的資料
   //相當于req.setAttribute("name",name);
   modelMap.addAttribute("name",name);
   System.out.println(name);
   return "hello";
}

第三種 : 通過Model

Model

@RequestMapping("/ct2/hello")
public String hello(@RequestParam("username") String name, Model model){
   //封裝要顯示到視圖中的資料
   //相當于req.setAttribute("name",name);
   model.addAttribute("msg",name);
   System.out.println(name);
   return "test";
}

6.3、對比

就對于新手而言簡單來說使用區別就是:

Model 只有寥寥幾個方法只適合用于儲存資料,簡化了新手對于Model物件的操作和理解;
ModelMap 繼承了 LinkedMap ,除了實作了自身的一些方法,同樣的繼承 LinkedMap 的方法和特性;
ModelAndView 可以在儲存資料的同時,可以進行設定回傳的邏輯視圖,進行控制展示層的跳轉,

當然更多的以后開發考慮的更多的是性能和優化,就不能單單僅限于此的了解,

請使用80%的時間打好扎實的基礎,剩下18%的時間研究框架,2%的時間去學點英文,框架的官方檔案永遠是最好的教程,

7、亂碼問題

測驗步驟:

  1. 我們可以在首頁撰寫一個提交的表單

    <form action="/e/t" method="post">
     <input type="text" name="name">
     <input type="submit">
    </form>
    
  2. 后臺撰寫對應的處理類

    @Controller
    public class Encoding {
       @RequestMapping("/e/t")
       public String test(Model model,String name){
           model.addAttribute("msg",name); //獲取表單提交的值
           return "test"; //跳轉到test頁面顯示輸入的值
      }
    }
    
  3. 輸入中文測驗,發現亂碼

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-HxFI7CDF-1613122851066)(SpringMVC課堂筆記.assets/1595131750549.png)]
    在這里插入圖片描述

不得不說,亂碼問題是在我們開發中十分常見的問題,也是讓我們程式猿比較頭大的問題!

以前亂碼問題通過過濾器解決 , 而SpringMVC給我們提供了一個過濾器 , 可以在web.xml中配置 .

修改了xml檔案需要重啟服務器!

filter>
   <filter-name>encoding</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>encoding</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

注意:這里寫/*,寫/的話過濾不了jsp頁面,不能解決亂碼

但是我們發現 , 有些極端情況下.這個過濾器對get的支持不好 .

處理方法 :

  1. 修改tomcat組態檔 :設定編碼!

    <Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"
              connectionTimeout="20000"
              redirectPort="8443" />
    
  2. 自定義過濾器(萬能解決)

    package com.kuang.filter;
    
    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.Map;
    
    /**
    * 解決get和post請求 全部亂碼的過濾器
    */
    public class GenericEncodingFilter implements Filter {
    
       @Override
       public void destroy() {
      }
    
       @Override
       public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
           //處理response的字符編碼
           HttpServletResponse myResponse=(HttpServletResponse) response;
           myResponse.setContentType("text/html;charset=UTF-8");
    
           // 轉型為與協議相關物件
           HttpServletRequest httpServletRequest = (HttpServletRequest) request;
           // 對request包裝增強
           HttpServletRequest myrequest = new MyRequest(httpServletRequest);
           chain.doFilter(myrequest, response);
      }
    
       @Override
       public void init(FilterConfig filterConfig) throws ServletException {
      }
    
    }
    
    //自定義request物件,HttpServletRequest的包裝類
    class MyRequest extends HttpServletRequestWrapper {
    
       private HttpServletRequest request;
       //是否編碼的標記
       private boolean hasEncode;
       //定義一個可以傳入HttpServletRequest物件的建構式,以便對其進行裝飾
       public MyRequest(HttpServletRequest request) {
           super(request);// super必須寫
           this.request = request;
      }
    
       // 對需要增強方法 進行覆寫
       @Override
       public Map getParameterMap() {
           // 先獲得請求方式
           String method = request.getMethod();
           if (method.equalsIgnoreCase("post")) {
               // post請求
               try {
                   // 處理post亂碼
                   request.setCharacterEncoding("utf-8");
                   return request.getParameterMap();
              } catch (UnsupportedEncodingException e) {
                   e.printStackTrace();
              }
          } else if (method.equalsIgnoreCase("get")) {
               // get請求
               Map<String, String[]> parameterMap = request.getParameterMap();
               if (!hasEncode) { // 確保get手動編碼邏輯只運行一次
                   for (String parameterName : parameterMap.keySet()) {
                       String[] values = parameterMap.get(parameterName);
                       if (values != null) {
                           for (int i = 0; i < values.length; i++) {
                               try {
                                   // 處理get亂碼
                                   values[i] = new String(values[i]
                                          .getBytes("ISO-8859-1"), "utf-8");
                              } catch (UnsupportedEncodingException e) {
                                   e.printStackTrace();
                              }
                          }
                      }
                  }
                   hasEncode = true;
              }
               return parameterMap;
          }
           return super.getParameterMap();
      }
    
       //取一個值
       @Override
       public String getParameter(String name) {
           Map<String, String[]> parameterMap = getParameterMap();
           String[] values = parameterMap.get(name);
           if (values == null) {
               return null;
          }
           return values[0]; // 取回引數的第一個值
      }
    
       //取所有值
       @Override
       public String[] getParameterValues(String name) {
           Map<String, String[]> parameterMap = getParameterMap();
           String[] values = parameterMap.get(name);
           return values;
      }
    }
    

    一般情況下,SpringMVC默認的亂碼處理就已經能夠很好的解決了!

    然后在web.xml中配置這個過濾器即可!

    亂碼問題,需要平時多注意,在盡可能能設定編碼的地方,都設定為統一編碼 UTF-8!

8、Json互動處理

8.1、什么是JSON?

  • JSON(JavaScript Object Notation, JS 物件標記) 是一種輕量級的資料交換格式,目前使用特別廣泛,
  • 采用完全獨立于編程語言的文本格式來存盤和表示資料,
  • 簡潔和清晰的層次結構使得 JSON 成為理想的資料交換語言,
  • 易于人閱讀和撰寫,同時也易于機器決議和生成,并有效地提升網路傳輸效率,

在 JavaScript 語言中,一切都是物件,因此,任何JavaScript 支持的型別都可以通過 JSON 來表示,例如字串、數字、物件、陣列等,看看他的要求和語法格式:

  • 物件表示為鍵值對,資料由逗號分隔
  • 花括號保存物件
  • 方括號保存陣列

JSON 鍵值對是用來保存 JavaScript 物件的一種方式,和 JavaScript 物件的寫法也大同小異,鍵/值對組合中的鍵名寫在前面并用雙引號 “” 包裹,使用冒號 : 分隔,然后緊接著值:

{"name": "QinJiang"}
{"age": "3"}
{"sex": "男"}

很多人搞不清楚 JSON 和 JavaScript 物件的關系,甚至連誰是誰都不清楚,其實,可以這么理解:

JSON 是 JavaScript 物件的字串表示法,它使用文本表示一個 JS 物件的資訊,本質是一個字串,

var obj = {a: 'Hello', b: 'World'}; //這是一個物件,注意鍵名也是可以使用引號包裹的
var json = '{"a": "Hello", "b": "World"}'; //這是一個 JSON 字串,本質是一個字串

8.2、JSON 和 JavaScript 物件互轉

要實作從JSON字串轉換為JavaScript 物件,使用 JSON.parse() 方法:

var obj = JSON.parse('{"a": "Hello", "b": "World"}');
//結果是 {a: 'Hello', b: 'World'}

要實作從JavaScript 物件轉換為JSON字串,使用 JSON.stringify() 方法:

var json = JSON.stringify({a: 'Hello', b: 'World'});
//結果是 '{"a": "Hello", "b": "World"}'

代碼測驗

  1. 新建一個module ,springmvc-05-json , 添加web的支持

  2. 在web目錄下新建一個 json-1.html , 撰寫測驗內容

    <!DOCTYPE html>
    <html lang="en">
    <head>
       <meta charset="UTF-8">
       <title>JSON_秦疆</title>
    </head>
    <body>
    
    <script type="text/javascript">
       //撰寫一個js的物件
       var user = {
           name:"秦疆",
           age:3,
           sex:"男"
      };
       //將js物件轉換成json字串
       var str = JSON.stringify(user);
       console.log(str);
       
       //將json字串轉換為js物件
       var user2 = JSON.parse(str);
       console.log(user2.age,user2.name,user2.sex);
    
    </script>
    
    </body>
    </html>
    
  3. 在IDEA中使用瀏覽器打開,查看控制臺輸出!

8.3、Controller回傳JSON資料

  • Jackson應該是目前比較好的json決議工具了

  • 當然工具不止這一個,比如還有阿里巴巴的 fastjson 等等,

  • 我們這里使用Jackson,使用它需要匯入它的jar包;

    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
    <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-databind</artifactId>
       <version>2.9.8</version>
    </dependency>
    
  • 配置SpringMVC需要的配置

    • (web.xml)

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
              version="4.0">
      
         <!--1.注冊servlet-->
         <servlet>
             <servlet-name>SpringMVC</servlet-name>
             <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
             <!--通過初始化引數指定SpringMVC組態檔的位置,進行關聯-->
             <init-param>
                 <param-name>contextConfigLocation</param-name>
                 <param-value>classpath:springmvc-servlet.xml</param-value>
             </init-param>
             <!-- 啟動順序,數字越小,啟動越早 -->
             <load-on-startup>1</load-on-startup>
         </servlet>
      
         <!--所有請求都會被springmvc攔截 -->
         <servlet-mapping>
             <servlet-name>SpringMVC</servlet-name>
             <url-pattern>/</url-pattern>
         </servlet-mapping>
      
         <filter>
             <filter-name>encoding</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>encoding</filter-name>
             <url-pattern>/</url-pattern>
         </filter-mapping>
      
      </web-app>
      
    • springmvc-servlet.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:context="http://www.springframework.org/schema/context"
            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">
      
         <!-- 自動掃描指定的包,下面所有注解類交給IOC容器管理 -->
         <context:component-scan base-package="com.kuang.controller"/>
      
         <!-- 視圖決議器 -->
         <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
               id="internalResourceViewResolver">
             <!-- 前綴 -->
             <property name="prefix" value="/WEB-INF/jsp/" />
             <!-- 后綴 -->
             <property name="suffix" value=".jsp" />
         </bean>
      
      </beans>
      
    • 我們隨便撰寫一個User的物體類,然后我們去撰寫我們的測驗Controller;

      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      public class User {
          private int id;
          private String name;
        private int age;
      }
      
    • 這里我們需要兩個新東西,一個是@ResponseBody,一個是ObjectMapper物件,我們看下具體的用法

      撰寫一個Controller;

      @Controller
      public class UserController {
      @RequestMapping("/j1")
       @ResponseBody//他就不會走視圖決議器,會直接回傳一個 字串
       public String json1() throws JsonProcessingException {
           //jackson,ObjectMapper
           ObjectMapper mapper = new ObjectMapper();
      
           //創建一個物件
           User user = new User(1, "秦疆一號", 12);
           //System.out.println(user);
      
           String str = mapper.writeValueAsString(user);
           return str;
       }
      
    • 此時輸入中文會產生亂碼

      //produces:指定回應體回傳型別和編碼
      @RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")
      
    • 配置Tomcat , 啟動測驗一下!http://localhost:8080/json1

      [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-O7hQvSsC-1613122851066)(SpringMVC課堂筆記.assets/1595133634951.png)]
      在這里插入圖片描述

【注意:使用json記得處理亂碼問題】

8.4代碼優化

亂碼統一解決

上一種方法比較麻煩,如果專案中有許多請求則每一個都要添加,可以通過Spring配置統一指定,這樣就不用每次都去處理了!

我們可以在springmvc的組態檔上添加一段訊息StringHttpMessageConverter轉換配置!

<mvc:annotation-driven>
   <mvc:message-converters register-defaults="true">
       <bean class="org.springframework.http.converter.StringHttpMessageConverter">
           <constructor-arg value="UTF-8"/>
       </bean>
       <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
           <property name="objectMapper">
               <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                   <property name="failOnEmptyBeans" value="false"/>
               </bean>
           </property>
       </bean>
   </mvc:message-converters>
</mvc:annotation-driven>

回傳json字串統一解決

  • @ResponseBody解決(每個方法都得加,不建議使用)

    @Controller
    public class UserController {
       //produces:指定回應體回傳型別和編碼
       @RequestMapping(value = "/json1")
       @ResponseBody
       public String json1() throws JsonProcessingException {
           //創建一個jackson的物件映射器,用來決議資料
           ObjectMapper mapper = new ObjectMapper();
           //創建一個物件
           User user = new User(1, "秦疆一號", 12);
           //將我們的物件決議成為json格式
           String str = mapper.writeValueAsString(user);
           //由于@ResponseBody注解,這里會將str轉成json格式回傳;十分方便
           return str;
      }
    }
    
  • @RestController(直接加到類上即可)

@RestController
public class UserController {
   @RequestMapping(value = "/j1")
   public String json1() throws JsonProcessingException {
       //創建一個jackson的物件映射器,用來決議資料
       ObjectMapper mapper = new ObjectMapper();
       //創建一個物件
       User user = new User(1, "秦疆一號", 12);
       //將我們的物件決議成為json格式
       String str = mapper.writeValueAsString(user);
       return str;
  }

}

8.5、測驗集合輸出

增加一個新的方法

@RequestMapping("/j2")
public String json2() throws JsonProcessingException {

    //創建一個jackson的物件映射器,用來決議資料
    ObjectMapper mapper = new ObjectMapper();
    //創建一個物件
   	User user1 = new User(1, "秦疆1號", 12);
    User user2 = new User(2, "秦疆2號", 12);
    User user3 = new User(3, "秦疆3號", 12);
    User user4 = new User(4, "秦疆4號", 12);
    User user5 = new User(5, "秦疆5號", 12);
    List<User> list = new ArrayList<User>();
    list.add(user1);
    list.add(user2);
    list.add(user3);
    list.add(user4);
    list.add(user5);
    //將我們的物件決議成為json格式
    String str = mapper.writeValueAsString(list);
    return str;
}

運行結果 : 十分完美,沒有任何問題!

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-v14sPycX-1613122851066)(SpringMVC課堂筆記.assets/1595133587875.png)]
在這里插入圖片描述

8.6、輸出時間物件

  • 增加一個新的方法

    @RequestMapping("/j3")
    public String json3() throws JsonProcessingException {
    
       ObjectMapper mapper = new ObjectMapper();
    
       //創建時間一個物件,java.util.Date
       Date date = new Date();
       //將我們的物件決議成為json格式
       String str = mapper.writeValueAsString(date);
       return str;
    }
    
  • 運行結果 :

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-DvI4u73m-1613122851068)(SpringMVC課堂筆記.assets/1595134256420.png)]
    在這里插入圖片描述

  • 默認日期格式會變成一個數字,是1970年1月1日到當前日期的毫秒數!

  • Jackson 默認是會把時間轉成timestamps形式

解決方案:取消timestamps形式 , 自定義時間格式

@RequestMapping("/j3")
public String json4() throws JsonProcessingException {

   ObjectMapper mapper = new ObjectMapper();

   //不使用時間戳的方式
   mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
   //自定義日期格式物件
   SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   //指定日期格式
   mapper.setDateFormat(sdf);

   Date date = new Date();
   String str = mapper.writeValueAsString(date);

   return str;
}

運行結果 : 成功的輸出了時間!

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qkVbrdmu-1613122851068)(SpringMVC課堂筆記.assets/1595134398126.png)]
在這里插入圖片描述

抽取為工具類

如果要經常使用的話,這樣是比較麻煩的,我們可以將這些代碼封裝到一個工具類中;我們去撰寫下

public class JsonUtils {
    public static String getJson(Object object) {
        return getJson(object,"yyyy-MM-dd HH:mm:ss");
    }
    public static String getJson(Object object, String dateFormat) {
        ObjectMapper mapper = new ObjectMapper();

        //java自定義日期格式
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        //sdf.format(date)

        // 使用ObjectMapper 來格式化輸出
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
        mapper.setDateFormat(sdf);

        try {
            //ObjectMapper,時間決議后的默認格式為:TImestamp.時間戳
            return mapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

}

我們使用工具類,代碼就更加簡潔了!

@RequestMapping("/j3")
    public String json3(){

        Date date = new Date();

        return JsonUtils.getJson(date,"yyyy-MM-dd HH:mm:ss");
    }
}

大功告成!完美!

8.7、FastJson

  • fastjson.jar是阿里開發的一款專門用于Java開發的包,
  • 實作json物件與JavaBean物件的轉換,
  • 實作JavaBean物件與json字串的轉換,
  • 實作json物件與json字串的轉換,
  • 實作json的轉換方法很多,最后的實作結果都是一樣的,

fastjson 的 pom依賴!

<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>fastjson</artifactId>
   <version>1.2.60</version>
</dependency>

fastjson 三個主要的類:

  1. JSONObject 代表 json 物件
    • JSONObject實作了Map介面, 猜想 JSONObject底層操作是由Map實作的,
    • JSONObject對應json物件,通過各種形式的get()方法可以獲取json物件中的資料,也可利用諸如size(),isEmpty()等方法獲取"鍵:值"對的個數和判斷是否為空,其本質是通過實作Map介面并呼叫介面中的方法完成的,
  2. JSONArray 代表 json 物件陣列
    • 內部是有List介面中的方法來完成操作的,
  3. JSON代表 JSONObject和JSONArray的轉化
    • JSON類原始碼分析與使用
    • 仔細觀察這些方法,主要是實作json物件,json物件陣列,javabean物件,json字串之間的相互轉化,

代碼測驗,我們新建一個FastJsonDemo 類

@RequestMapping("/j4")
    //@ResponseBody//他就不會走視圖決議器,會直接回傳一個 字串
    public String json4(){

        User user1 = new User(1, "秦疆1號", 12);
        User user2 = new User(2, "秦疆2號", 12);
        User user3 = new User(3, "秦疆3號", 12);
        User user4 = new User(4, "秦疆4號", 12);
        User user5 = new User(5, "秦疆5號", 12);

        List<User> list = new ArrayList<User>();
        list.add(user1);
        list.add(user2);
        list.add(user3);
        list.add(user4);
        list.add(user5);

        System.out.println("*******Java物件 轉 JSON字串*******");
        String str1 = JSON.toJSONString(list);
        System.out.println("JSON.toJSONString(list)==>"+str1);
        String str2 = JSON.toJSONString(user1);
        System.out.println("JSON.toJSONString(user1)==>"+str2);

        System.out.println("\n****** JSON字串 轉 Java物件*******");
        User jp_user1=JSON.parseObject(str2,User.class);
        System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1);

        System.out.println("\n****** Java物件 轉 JSON物件 ******");
        JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
        System.out.println("(JSONObject) JSON.toJSON(user2)==>"+jsonObject1.getString("name"));

        System.out.println("\n****** JSON物件 轉 Java物件 ******");
        User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
        System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user);

        return JSON.toJSONString(list);
    }

這種工具類,我們只需要掌握使用就好了,在使用的時候在根據具體的業務去找對應的實作,和以前的commons-io那種工具包一樣,拿來用就好了!

9、Ajax研究

9.1、簡介

  • AJAX = Asynchronous JavaScript and XML(異步的 JavaScript 和 XML),

  • AJAX 是一種在無需重新加載整個網頁的情況下,能夠更新部分網頁的技術,

  • Ajax 不是一種新的編程語言,而是一種用于創建更好更快以及互動性更強的Web應用程式的技術,

  • 在 2005 年,Google 通過其 Google Suggest 使 AJAX 變得流行起來,Google Suggest能夠自動幫你完成搜索單詞,

  • Google Suggest 使用 AJAX 創造出動態性極強的 web 界面:當您在谷歌的搜索框輸入關鍵字時,JavaScript 會把這些字符發送到服務器,然后服務器會回傳一個搜索建議的串列,

  • 就和國內百度的搜索框一樣!

  • 傳統的網頁(即不用ajax技術的網頁),想要更新內容或者提交一個表單,都需要重新加載整個網頁,

  • 使用ajax技術的網頁,通過在后臺服務器進行少量的資料交換,就可以實作異步區域更新,

  • 使用Ajax,用戶可以創建接近本地桌面應用的直接、高可用、更豐富、更動態的Web用戶界面,

9.2、偽造Ajax

我們可以使用前端的一個標簽來偽造一個ajax的樣子,iframe標簽

  1. 新建一個module :sspringmvc-06-ajax , 匯入web支持!

  2. 撰寫一個 ajax-frame.html 使用 iframe 測驗,感受下效果

    <!DOCTYPE html>
    <html>
    <head lang="en">
       <meta charset="UTF-8">
       <title>kuangshen</title>
    </head>
    <body>
    
    <script type="text/javascript">
       window.onload = function(){
           var myDate = new Date();
           document.getElementById('currentTime').innerText = myDate.getTime();
      };
    
       function LoadPage(){
           var targetUrl =  document.getElementById('url').value;
           console.log(targetUrl);
           document.getElementById("iframePosition").src = targetUrl;
      }
    
    </script>
    
    <div>
       <p>請輸入要加載的地址:<span id="currentTime"></span></p>
       <p>
           <input id="url" type="text" value="https://www.baidu.com/"/>
           <input type="button" value="提交" onclick="LoadPage()">
       </p>
    </div>
    
    <div>
       <h3>加載頁面位置:</h3>
       <iframe id="iframePosition" style="width: 100%;height: 500px;"></iframe>
    </div>
    
    </body>
    </html>
    
  3. 使用IDEA開瀏覽器測驗一下!

利用AJAX可以做:

  • 注冊時,輸入用戶名自動檢測用戶是否已經存在,
  • 登陸時,提示用戶名密碼錯誤
  • 洗掉資料行時,將行ID發送到后臺,后臺在資料庫中洗掉,資料庫洗掉成功后,在頁面DOM中將資料行也洗掉,
  • …等等

9.3、jQuery.ajax

  • 純JS原生實作Ajax我們不去講解這里,直接使用jquery提供的,方便學習和使用,避免重復造輪子,有興趣的同學可以去了解下JS原生XMLHttpRequest !

  • Ajax的核心是XMLHttpRequest物件(XHR),XHR為向服務器發送請求和決議服務器回應提供了介面,能夠以異步方式從服務器獲取新資料,

  • jQuery 提供多個與 AJAX 有關的方法,

  • 通過 jQuery AJAX 方法,您能夠使用 HTTP Get 和 HTTP Post 從遠程服務器上請求文本、HTML、XML 或 JSON – 同時您能夠把這些外部資料直接載入網頁的被選元素中,

  • jQuery 不是生產者,而是大自然搬運工,

  • jQuery Ajax本質就是 XMLHttpRequest,對他進行了封裝,方便呼叫!

jQuery.ajax(...)
      部分引數:
            url:請求地址
            type:請求方式,GETPOST1.9.0之后用method)
        headers:請求頭
            data:要發送的資料
    contentType:即將發送資訊至服務器的內容編碼型別(默認: "application/x-www-form-urlencoded; charset=UTF-8")
          async:是否異步
        timeout:設定請求超時時間(毫秒)
      beforeSend:發送請求前執行的函式(全域)
        complete:完成之后執行的回呼函式(全域)
        success:成功之后執行的回呼函式(全域)
          error:失敗之后執行的回呼函式(全域)
        accepts:通過請求頭發送給服務器,告訴服務器當前客戶端可接受的資料型別
        dataType:將服務器端回傳的資料轉換成指定型別
          "xml": 將服務器端回傳的內容轉換成xml格式
          "text": 將服務器端回傳的內容轉換成普通文本格式
          "html": 將服務器端回傳的內容轉換成普通文本格式,在插入DOM中時,如果包含JavaScript標簽,則會嘗試去執行,
        "script": 嘗試將回傳值當作JavaScript去執行,然后再將服務器端回傳的內容轉換成普通文本格式
          "json": 將服務器端回傳的內容轉換成相應的JavaScript物件
        "jsonp": JSONP 格式使用 JSONP 形式呼叫函式時,如 "myurl?callback=?" jQuery 將自動替換 ? 為正確的函式名,以執行回呼函式

我們來個簡單的測驗,使用最原始的HttpServletResponse處理 , .最簡單 , 最通用

  1. 配置web.xml 和 springmvc的組態檔【記得靜態資源過濾和注解驅動配置上】

    <?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">
    
       <!-- 自動掃描指定的包,下面所有注解類交給IOC容器管理 -->
       <context:component-scan base-package="com.kuang.controller"/>
        <!--靜態資源過濾-->
       <mvc:default-servlet-handler />
        <!--注解驅動配-->
       <mvc:annotation-driven />
    
       <!-- 視圖決議器 -->
       <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
             id="internalResourceViewResolver">
           <!-- 前綴 -->
           <property name="prefix" value="/WEB-INF/jsp/" />
           <!-- 后綴 -->
           <property name="suffix" value=".jsp" />
       </bean>
    
    </beans>
    
  2. 撰寫一個AjaxController

    @Controller
    public class AjaxController {
    
       @RequestMapping("/a1")
       public void ajax1(String name , HttpServletResponse response) throws IOException {
           if ("admin".equals(name)){
               response.getWriter().print("true");
          }else{
               response.getWriter().print("false");
          }
      }
    
    }
    
  3. 匯入jquery , 可以使用在線的CDN , 也可以下載匯入

    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <script src="${pageContext.request.contextPath}/statics/js/jquery-3.1.1.min.js"></script>
    
  4. 撰寫index.jsp測驗

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
     <head>
       <title>$Title$</title>
      <%--<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>--%>
       <script src="${pageContext.request.contextPath}/statics/js/jquery-3.1.1.min.js"></script>
       <script>
           function a1(){
               $.post({
                   url:"${pageContext.request.contextPath}/a1",
                   data:{'name':$("#txtName").val()},
                   success:function (data,status) {
                       alert(data);
                       alert(status);
                  }
              });
          }
       </script>
     </head>
     <body>
    
    <%--onblur:失去焦點觸發事件--%>
    用戶名:<input type="text" id="txtName" οnblur="a1()"/>
    
     </body>
    </html>
    
  5. 啟動tomcat測驗!打開瀏覽器的控制臺,當我們滑鼠離開輸入框的時候,可以看到發出了一個ajax的請求!是后臺回傳給我們的結果!測驗成功!

9.4、Springmvc實作

  1. 物體類user(使用了lombok插件,可以自己寫實作類方法)

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
    
       private String name;
       private int age;
       private String sex;
    
    }
    
  2. 我們來獲取一個集合物件,展示到前端頁面

    @RequestMapping("/a2")
    public List<User> ajax2(){
       List<User> list = new ArrayList<User>();
       list.add(new User("秦疆1號",3,"男"));
       list.add(new User("秦疆2號",3,"男"));
       list.add(new User("秦疆3號",3,"男"));
       return list; //由于@RestController注解,將list轉成json格式回傳
    }
    
  3. 前端頁面

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
        <script src="${pageContext.request.contextPath}/static/js/jquery-3.4.1.js"></script>
        <script>
            $(function () {
                $("#btn").click(function () {
                    // console.log('點擊事件成功')
                    // $.post(url,param,[可以省略],success)
                    $.post("${pageContext.request.contextPath}/a2",function (data) {
                        console.log(data[0].name);
                        let html =  "";
                        for (let i = 0; i < data.length; i++) {
                            html += `<tr>
                                        <td>${"${data[i].name}"}</td>
                                        <td>${"${data[i].age}"}</td>
                                        <td>${"${data[i].sex}"}</td>
                                    </tr>`
                        }
                        $("#content").html(html)
                        console.log(html)
                    })
                })
            })
        </script>
    </head>
    <body>
    <input type="button" value="加載資料" id="btn">
    <table>
        <thead>
            <tr>
                <td>姓名</td>
                <td>年齡</td>
                <td>性別</td>
            </tr>
        </thead>
        <tbody id="content">
            <%--資料:后臺--%>
        </tbody>
    </table>
    </body>
    </html>
    

成功實作了資料回顯!可以體會一下Ajax的好處!

9.5、注冊提示效果

  1. 我們寫一個Controller

    @RequestMapping("/a3")
    public String ajax3(String name,String pwd){
       String msg = "";
       //模擬資料庫中存在資料
       if (name!=null){
           if ("admin".equals(name)){
               msg = "OK";
          }else {
               msg = "用戶名輸入錯誤";
          }
      }
       if (pwd!=null){
           if ("123456".equals(pwd)){
               msg = "OK";
          }else {
               msg = "密碼輸入有誤";
          }
      }
       return msg; //由于@RestController注解,將msg轉成json格式回傳
    }
    
  2. 前端頁面 login.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
       <title>ajax</title>
       <script src="${pageContext.request.contextPath}/statics/js/jquery-3.1.1.min.js"></script>
       <script>
    
           function a1(){
               $.post({
                   url:"${pageContext.request.contextPath}/a3",
                   data:{'name':$("#name").val()},
                   success:function (data) {
                       if (data.toString()=='OK'){
                           $("#userInfo").css("color","green");
                      }else {
                           $("#userInfo").css("color","red");
                      }
                       $("#userInfo").html(data);
                  }
              });
          }
           function a2(){
               $.post({
                   url:"${pageContext.request.contextPath}/a3",
                   data:{'pwd':$("#pwd").val()},
                   success:function (data) {
                       if (data.toString()=='OK'){
                           $("#pwdInfo").css("color","green");
                      }else {
                           $("#pwdInfo").css("color","red");
                      }
                       $("#pwdInfo").html(data);
                  }
              });
          }
    
       </script>
    </head>
    <body>
    <p>
      用戶名:<input type="text" id="name" οnblur="a1()"/>
       <span id="userInfo"></span>
    </p>
    <p>
      密碼:<input type="text" id="pwd" οnblur="a2()"/>
       <span id="pwdInfo"></span>
    </p>
    </body>
    </html>
    
  3. 記得處理json亂碼問題

    <!--JSON亂碼問題配置-->
        <mvc:annotation-driven>
            <mvc:message-converters register-defaults="true">
                <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                    <constructor-arg value="UTF-8"/>
                </bean>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                    <property name="objectMapper">
                        <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                            <property name="failOnEmptyBeans" value="false"/>
                        </bean>
                    </property>
                </bean>
            </mvc:message-converters>
        </mvc:annotation-driven>
    
    
  4. 測驗一下效果,動態請求回應,區域重繪,就是如此!

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-y0pMKeXD-1613122851068)(SpringMVC課堂筆記.assets/1595137816208.png)]
    在這里插入圖片描述

9.6、獲取baidu介面Demo

  1. JSONP.html

    <!DOCTYPE HTML>
    <html>
    <head>
       <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
       <title>JSONP百度搜索</title>
       <style>
           #q{
               width: 500px;
               height: 30px;
               border:1px solid #ddd;
               line-height: 30px;
               display: block;
               margin: 0 auto;
               padding: 0 10px;
               font-size: 14px;
          }
           #ul{
               width: 520px;
               list-style: none;
               margin: 0 auto;
               padding: 0;
               border:1px solid #ddd;
               margin-top: -1px;
               display: none;
          }
           #ul li{
               line-height: 30px;
               padding: 0 10px;
          }
           #ul li:hover{
               background-color: #f60;
               color: #fff;
          }
       </style>
       <script>
    
           // 2.步驟二
           // 定義demo函式 (分析介面、資料)
           function demo(data){
               var Ul = document.getElementById('ul');
               var html = '';
               // 如果搜索資料存在 把內容添加進去
               if (data.s.length) {
                   // 隱藏掉的ul顯示出來
                   Ul.style.display = 'block';
                   // 搜索到的資料回圈追加到li里
                   for(var i = 0;i<data.s.length;i++){
                       html += '<li>'+data.s[i]+'</li>';
                  }
                   // 回圈的li寫入ul
                   Ul.innerHTML = html;
              }
          }
    
           // 1.步驟一
           window.onload = function(){
               // 獲取輸入框和ul
               var Q = document.getElementById('q');
               var Ul = document.getElementById('ul');
    
               // 事件滑鼠抬起時候
               Q.onkeyup = function(){
                   // 如果輸入框不等于空
                   if (this.value != '') {
                       // ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆JSONPz重點☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
                       // 創建標簽
                       var script = document.createElement('script');
                       //給定要跨域的地址 賦值給src
                       //這里是要請求的跨域的地址 我寫的是百度搜索的跨域地址
                       script.src = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+this.value+'&cb=demo';
                       // 將組合好的帶src的script標簽追加到body里
                       document.body.appendChild(script);
                  }
              }
          }
       </script>
    </head>
    
    <body>
    <input type="text" id="q" />
    <ul id="ul">
    
    </ul>
    </body>
    </html>
    
  2. 測驗

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MrxGsetk-1613122851070)(SpringMVC課堂筆記.assets/1595138107341.png)]
    在這里插入圖片描述

10、攔截器

10.1、概述

  • SpringMVC的處理器攔截器類似于Servlet開發中的過濾器Filter,用于對處理器進行預處理和后處理,
  • 開發者可以自己定義一些攔截器來實作特定的功能,

**過濾器與攔截器的區別:**攔截器是AOP思想的具體應用,

過濾器

  • servlet規范中的一部分,任何javaweb工程都可以使用
  • 在url-pattern中配置了/*之后,可以對所有要訪問的資源進行攔截

攔截器

  • 攔截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
  • 攔截器只會攔截訪問的控制器方法, 如果訪問的是jsp/html/css/image/js是不會進行攔截的

10.2、自定義攔截器

  1. 新建一個Moudule , springmvc-Interceptor , 添加web支持

  2. 配置web.xml 和 springmvc-servlet.xml 檔案

  3. 撰寫一個攔截器(必須實作 HandlerInterceptor 介面

    package nuc.ss.config;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class MyInterceptor implements HandlerInterceptor {
        //return true; 執行下一個攔截器,放行
        //return false; 不執行下一個攔截器,攔截
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("===========處理前===========");
            return true;
        }
        //日志
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("===========處理后===========");
    
        }
        //日志
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("===========清理===========");
    
        }
    }
    
    
  4. 在springmvc的組態檔中配置攔截器

    <!--攔截器配置-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--包括這個請求下面的所有請求-->
            <mvc:mapping path="/**"/>
            <bean class="nuc.ss.config.MyInterceptor"/>
        </mvc:interceptor>
    
    </mvc:interceptors>
    
  5. 撰寫一個Controller,接收請求

    package nuc.ss.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class TestController {
        @GetMapping("/t1")
        public String test() {
            System.out.println("TestController.test");
            return "ok";
        }
    }
    
  6. 啟動tomcat 測驗一下!(http://localhost:8888/t1)

10.3、驗證用戶是否登錄 (認證用戶)

實作思路

  1. 有一個登陸頁面,需要寫一個controller訪問頁面,

  2. 登陸頁面有一提交表單的動作,需要在controller中處理,判斷用戶名密碼是否正確,如果正確,向session中寫入用戶資訊,回傳登陸成功,

  3. 攔截用戶請求,判斷用戶是否登陸,如果用戶已經登陸,放行, 如果用戶未登陸,跳轉到登陸頁面

測驗:

  1. 撰寫一個登陸頁面 login.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>登錄</title>
    </head>
    <body>
    <%--在web-inf下面的所有頁面或者資源,只能通過controller或者Servlet進行訪問--%>
    <h1>登錄頁面</h1>
    
    <form action="${pageContext.request.contextPath}/user/login" method="post">
        用戶名:<input type="text" name="username">
        密碼:<input type="text" name="password">
        <input type="submit" value="提交">
    </form>
    </body>
    </html>
    
    
  2. 撰寫一個Controller處理請求

    @Controller
    @RequestMapping("/user")
    public class LoginController {
        @RequestMapping("/main")
        public String main() {
            return "main";
        }
    
        @RequestMapping("/goLogin")
        public String login() {
            return "login";
        }
        @RequestMapping("/login")
        public String login(HttpSession session, String username, String password, Model model) {
    
            //把用戶的資訊存在session中
            session.setAttribute("userLoginInfo",username);
            model.addAttribute("password",password);
            model.addAttribute("username",username);
            return "main";
        }
    
        @RequestMapping("/goOut")
        public String goOut(HttpSession sessionl) {
            sessionl.removeAttribute("userLoginInfo");
            return "login";
        }
    }
    
    
  3. 撰寫一個登陸成功的頁面 main.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>首頁</title>
    </head>
    <body>
    <h1>首頁</h1>
    <span>${password}</span>
    <span>${username}</span>
    
    <p>
        <a href="${pageContext.request.contextPath}/user/goOut">注銷</a>
    </p>
    
    </body>
    </html>
    
    
  4. 在 index 頁面上測驗跳轉!啟動Tomcat 測驗,未登錄也可以進入主頁!

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
      <title>index</title>
    </head>
    <body>
    <h1><a href="${pageContext.request.contextPath}/user/goLogin">登錄頁面</a></h1>
    <h1><a href="${pageContext.request.contextPath}/user/main">首頁</a></h1>
    
    </body>
    </html>
    
  5. 撰寫用戶登錄攔截器

    package nuc.ss.config;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    public class LoginInterceptor implements HandlerInterceptor {
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            HttpSession session = request.getSession();
            //放行:判斷什么情況下登錄
    
            //登錄頁面也會放行
            if (request.getRequestURI().contains("goLogin")) {
                return true;
            }
            if (request.getRequestURI().contains("login")) {
                return true;
            }
            if (session.getAttribute("userLoginInfo") != null) {
                return true;
            }
            //判斷什么情況下沒有登錄
            request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
            return false;
        }
    }
    
    
  6. 在Springmvc的組態檔中注冊攔截器

    <!--關于攔截器的配置-->
    <mvc:interceptors>
       <mvc:interceptor>
           <mvc:mapping path="/**"/>
           <bean id="loginInterceptor" class="com.kuang.interceptor.LoginInterceptor"/>
       </mvc:interceptor>
    </mvc:interceptors>
    
  7. 再次重啟Tomcat測驗!

OK,測驗登錄攔截功能無誤.

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-sEIVidON-1613122851070)(SpringMVC課堂筆記.assets/1595139309383.png)]
在這里插入圖片描述

11、檔案上傳和下載

11.1、準備作業

  • 檔案上傳是專案開發中最常見的功能之一 ,springMVC 可以很好的支持檔案上傳,
  • SpringMVC背景關系中默認沒有裝配MultipartResolver,因此默認情況下其不能處理檔案上傳作業,如果想使用Spring的檔案上傳功能,則需要在背景關系中配置MultipartResolver,
  • 前端表單要求:為了能上傳檔案,必須將表單的method設定為POST,并將enctype設定為multipart/form-data,只有在這樣的情況下,瀏覽器才會把用戶選擇的檔案以二進制資料發送給服務器;

對表單中的 enctype 屬性做個詳細的說明:

  • application/x-www=form-urlencoded:默認方式,只處理表單域中的 value 屬性值,采用這種編碼方式的表單會將表單域中的值處理成 URL 編碼方式,
  • multipart/form-data:這種編碼方式會以二進制流的方式來處理表單資料,這種編碼方式會把檔案域指定檔案的內容也封裝到請求引數中,不會對字符編碼,
  • text/plain:除了把空格轉換為 “+” 號外,其他字符都不做編碼處理,這種方式適用直接通過表單發送郵件,
<form action="" enctype="multipart/form-data" method="post">
   <input type="file" name="file"/>
   <input type="submit">
</form>

一旦設定了enctype為multipart/form-data,瀏覽器即會采用二進制流的方式來處理表單資料,而對于檔案上傳的處理則涉及在服務器端決議原始的HTTP回應,在2003年,Apache Software Foundation發布了開源的Commons FileUpload組件,其很快成為Servlet/JSP程式員上傳檔案的最佳選擇,

  • Servlet3.0規范已經提供方法來處理檔案上傳,但這種上傳需要在Servlet中完成,
  • 而Spring MVC則提供了更簡單的封裝,
  • Spring MVC為檔案上傳提供了直接的支持,這種支持是用即插即用的MultipartResolver實作的,
  • Spring MVC使用Apache Commons FileUpload技術實作了一個MultipartResolver實作類:
  • CommonsMultipartResolver,因此,SpringMVC的檔案上傳還需要依賴Apache Commons FileUpload的組件,

11.2、檔案上傳

  1. 匯入檔案上傳的jar包,commons-fileupload , Maven會自動幫我們匯入他的依賴包 commons-io包;

    <!--檔案上傳-->
    <dependency>
       <groupId>commons-fileupload</groupId>
       <artifactId>commons-fileupload</artifactId>
       <version>1.3.3</version>
    </dependency>
    <!--servlet-api匯入高版本的-->
    <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>javax.servlet-api</artifactId>
       <version>4.0.1</version>
    </dependency>
    
  2. 配置bean:multipartResolver

    注意!!!這個bena的id必須為:multipartResolver , 否則上傳檔案會報400的錯誤!在這里栽過坑,教訓!

    <!--檔案上傳配置-->
    <bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
       <!-- 請求的編碼格式,必須和jSP的pageEncoding屬性一致,以便正確讀取表單的內容,默認為ISO-8859-1 -->
       <property name="defaultEncoding" value="utf-8"/>
       <!-- 上傳檔案大小上限,單位為位元組(10485760=10M) -->
       <property name="maxUploadSize" value="10485760"/>
       <property name="maxInMemorySize" value="40960"/>
    </bean>
    

    CommonsMultipartFile 的 常用方法:

    • String getOriginalFilename():獲取上傳檔案的原名
    • InputStream getInputStream():獲取檔案流
    • void transferTo(File dest):將上傳檔案保存到一個目錄檔案中

    我們去實際測驗一下

  3. 撰寫前端頁面

    <form action="/upload" enctype="multipart/form-data" method="post">
     <input type="file" name="file"/>
     <input type="submit" value="upload">
    </form>
    
  4. Controller

    package nuc.ss.controller;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.multipart.commons.CommonsMultipartFile;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.*;
    import java.net.URLEncoder;
    
    @RestController
    public class FileController {
    
        //@RequestParam("file") 將name=file控制元件得到的檔案封裝成CommonsMultipartFile 物件
        //批量上傳CommonsMultipartFile則為陣列即可
        @RequestMapping("/upload")
        public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
    
            //獲取檔案名 : file.getOriginalFilename();
            String uploadFileName = file.getOriginalFilename();
    
            //如果檔案名為空,直接回到首頁!
            if ("".equals(uploadFileName)){
                return "redirect:/index.jsp";
            }
            System.out.println("上傳檔案名 : "+uploadFileName);
    
            //上傳路徑保存設定
            String path = request.getServletContext().getRealPath("/upload");
            //如果路徑不存在,創建一個
            File realPath = new File(path);
            if (!realPath.exists()){
                realPath.mkdir();
            }
            System.out.println("上傳檔案保存地址:"+realPath);
    
            InputStream is = file.getInputStream(); //檔案輸入流
            OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //檔案輸出流
    
            //讀取寫出
            int len=0;
            byte[] buffer = new byte[1024];
            while ((len=is.read(buffer))!=-1){
                os.write(buffer,0,len);
                os.flush();
            }
            os.close();
            is.close();
            return "redirect:/index.jsp";
        }
    
        /*
         * 采用file.Transto 來保存上傳的檔案
         */
        @RequestMapping("/upload2")
        public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
    
            //上傳路徑保存設定
            String path = request.getServletContext().getRealPath("/upload");
            File realPath = new File(path);
            if (!realPath.exists()){
                realPath.mkdir();
            }
            //上傳檔案地址
            System.out.println("上傳檔案保存地址:"+realPath);
    
            //通過CommonsMultipartFile的方法直接寫檔案(注意這個時候)
            file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
    
            return "redirect:/index.jsp";
        }
    
        @RequestMapping(value="/download")
        public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
            //要下載的圖片地址
            String  path = request.getServletContext().getRealPath("/upload");
            String  fileName = "bg1.jpg";
    
            //1、設定response 回應頭
            response.reset(); //設定頁面不快取,清空buffer
            response.setCharacterEncoding("UTF-8"); //字符編碼
            response.setContentType("multipart/form-data"); //二進制傳輸資料
            //設定回應頭
            response.setHeader("Content-Disposition",
                    "attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));
    
            File file = new File(path,fileName);
            //2、 讀取檔案--輸入流
            InputStream input=new FileInputStream(file);
            //3、 寫出檔案--輸出流
            OutputStream out = response.getOutputStream();
    
            byte[] buff =new byte[1024];
            int index=0;
            //4、執行 寫出操作
            while((index= input.read(buff))!= -1){
                out.write(buff, 0, index);
                out.flush();
            }
            out.close();
            input.close();
            return null;
        }
    }
    
    
  5. 測驗上傳檔案,OK!

采用file.Transto 來保存上傳的檔案

  1. 撰寫Controller

    /*
    * 采用file.Transto 來保存上傳的檔案
    */
    @RequestMapping("/upload2")
    public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
    
       //上傳路徑保存設定
       String path = request.getServletContext().getRealPath("/upload");
       File realPath = new File(path);
       if (!realPath.exists()){
           realPath.mkdir();
      }
       //上傳檔案地址
       System.out.println("上傳檔案保存地址:"+realPath);
    
       //通過CommonsMultipartFile的方法直接寫檔案(注意這個時候)
       file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
    
       return "redirect:/index.jsp";
    }
    
  2. 前端表單提交地址修改

  3. 訪問提交測驗,OK!

11.3、檔案下載

檔案下載步驟:

  1. 設定 response 回應頭

  2. 讀取檔案 – InputStream

  3. 寫出檔案 – OutputStream

  4. 執行操作

  5. 關閉流 (先開后關)

代碼實作:

@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
   //要下載的圖片地址
   String  path = request.getServletContext().getRealPath("/upload");
   String  fileName = "基礎語法.jpg";

   //1、設定response 回應頭
   response.reset(); //設定頁面不快取,清空buffer
   response.setCharacterEncoding("UTF-8"); //字符編碼
   response.setContentType("multipart/form-data"); //二進制傳輸資料
   //設定回應頭
   response.setHeader("Content-Disposition",
           "attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));

   File file = new File(path,fileName);
   //2、 讀取檔案--輸入流
   InputStream input=new FileInputStream(file);
   //3、 寫出檔案--輸出流
   OutputStream out = response.getOutputStream();

   byte[] buff =new byte[1024];
   int index=0;
   //4、執行 寫出操作
   while((index= input.read(buff))!= -1){
       out.write(buff, 0, index);
       out.flush();
  }
   out.close();
   input.close();
   return null;
}

前端

<a href="/download">點擊下載</a>

測驗,檔案下載OK

ring fileName = “bg1.jpg”;

       //1、設定response 回應頭
       response.reset(); //設定頁面不快取,清空buffer
       response.setCharacterEncoding("UTF-8"); //字符編碼
       response.setContentType("multipart/form-data"); //二進制傳輸資料
       //設定回應頭
       response.setHeader("Content-Disposition",
               "attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));

       File file = new File(path,fileName);
       //2、 讀取檔案--輸入流
       InputStream input=new FileInputStream(file);
       //3、 寫出檔案--輸出流
       OutputStream out = response.getOutputStream();

       byte[] buff =new byte[1024];
       int index=0;
       //4、執行 寫出操作
       while((index= input.read(buff))!= -1){
           out.write(buff, 0, index);
           out.flush();
       }
       out.close();
       input.close();
       return null;
   }

}


5. 測驗上傳檔案,OK!

**采用file.Transto 來保存上傳的檔案**

1. 撰寫Controller

```java
/*
* 采用file.Transto 來保存上傳的檔案
*/
@RequestMapping("/upload2")
public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {

   //上傳路徑保存設定
   String path = request.getServletContext().getRealPath("/upload");
   File realPath = new File(path);
   if (!realPath.exists()){
       realPath.mkdir();
  }
   //上傳檔案地址
   System.out.println("上傳檔案保存地址:"+realPath);

   //通過CommonsMultipartFile的方法直接寫檔案(注意這個時候)
   file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));

   return "redirect:/index.jsp";
}
  1. 前端表單提交地址修改

  2. 訪問提交測驗,OK!

11.3、檔案下載

檔案下載步驟:

  1. 設定 response 回應頭

  2. 讀取檔案 – InputStream

  3. 寫出檔案 – OutputStream

  4. 執行操作

  5. 關閉流 (先開后關)

代碼實作:

@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
   //要下載的圖片地址
   String  path = request.getServletContext().getRealPath("/upload");
   String  fileName = "基礎語法.jpg";

   //1、設定response 回應頭
   response.reset(); //設定頁面不快取,清空buffer
   response.setCharacterEncoding("UTF-8"); //字符編碼
   response.setContentType("multipart/form-data"); //二進制傳輸資料
   //設定回應頭
   response.setHeader("Content-Disposition",
           "attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));

   File file = new File(path,fileName);
   //2、 讀取檔案--輸入流
   InputStream input=new FileInputStream(file);
   //3、 寫出檔案--輸出流
   OutputStream out = response.getOutputStream();

   byte[] buff =new byte[1024];
   int index=0;
   //4、執行 寫出操作
   while((index= input.read(buff))!= -1){
       out.write(buff, 0, index);
       out.flush();
  }
   out.close();
   input.close();
   return null;
}

前端

<a href="/download">點擊下載</a>

測驗,檔案下載OK

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/259211.html

標籤:其他

上一篇:JAVA的三大框架之Spring復習,理解Spring原理,Spring實踐案例

下一篇:HTTP

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more