天天看點

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

《SpringMVC架構介紹》(建議收藏)

❤️希望博友給個三連+關注!!!

SSM: mybatis + Spring + SpringMVC MVC三層架構

SpringMVC + Vue + SpringBoot + SpringCloud + Linux

SSM = JavaWeb做項目;

Spring: IOC和APO

SpringMVC: SpringMVC的執行流程!

SpringMVC : SSM架構整合!

Spring

MVC:模型(dao, service) 視圖 (jsp)控制器 (Servlet)

dao

service

servlet :轉發,重定向

jsp/html

前端資料傳輸實體類

實體類:使用者名,密碼,生日,愛好,… 20個

前端:使用者名密碼

pojo: User

vo: UserVo

dto:

JSP:本質就是一個Servlet

假設:你的項目的架構,是設計好的,還是演進的? 演講

  • Alibaba PHP
  • 随着使用者大, Java
  • 王堅去 IOE MySQL
  • MySQL : MySQL–> AliSQL. AliRedis
  • All in one -->微服務

MVC :

MWM: M V VM ViewModel :雙向綁定

1、什麼是MVC

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

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

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

**Controller(控制器):**接收使用者請求,委托給模型進行處理(狀态改變),處理完畢後把傳回的模型資料傳回給視圖,由視圖負責展示。 也就是說控制器做了個排程員的工作。

最典型的MVC就是JSP + servlet + javabean的模式。

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

1.1、Model1時代

  • 在web早期的開發中,通常采用的都是Model1。
  • Model1中,主要分為兩層,視圖層和模型層。
❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

Model1優點:架構簡單,比較适合小型項目開發;

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

1.2、Model2時代

Model2把一個項目分成三部分,包括視圖、控制、模型。

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

使用者發請求

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

職責分析:

Controller:控制器

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

Model:模型

  1. 業務邏輯
  2. 儲存資料的狀态

View:視圖

  1. 顯示頁面

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

1.3、回顧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 com.kk.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.擷取前端參數
        String method = req.getParameter("method");
        if (method.equals("add")){
            req.getSession().setAttribute("msg","執行了add方法");
        }
        if (method.equals("delete")){
            req.getSession().setAttribute("msg","執行了delete方法");
        }

        //2.調用業務層

        //3.視圖轉發或者重定向
        req.getRequestDispatcher("/WEB-INF/jsp/text.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>hello</servlet-name>
        <servlet-class>com.kk.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

<!--    <session-config>-->
<!--        <session-timeout>15</session-timeout>-->
<!--    </session-config>-->

<!--    <welcome-file-list>-->
<!--        <welcome-file>index.jsp</welcome-file>-->
<!--    </welcome-file-list>-->


</web-app>      
  1. 配置Tomcat,并啟動測試
  • localhost:8080/user?method=add
  • localhost:8080/user?method=delete

8.通路結果

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

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

概述

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

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風格 .異常處理 , 本地化 , 國際化 , 資料驗證 , 類型轉換 , 攔截器 等等…是以我們要學習 .

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

中心控制器

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

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

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

圖來源:狂神說,如有侵權,請聯系删除!

SpringMVC的原理如下圖所示:

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

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

圖來源:狂神說,如有侵權,請聯系删除!

SpringMVC執行原理

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

圖來源:狂神說,如有侵權,請聯系删除!

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

簡要分析執行流程

  1. DispatcherServlet表示前置控制器,是整個SpringMVC的控制中心。使用者送出請求,DispatcherServlet接收請求并攔截請求。
  • 我們假設請求的url為 :​​http://localhost​​:8080/SpringMVC/hello
  • 如上url拆分成三部分:
  • ​​http://localhost​​:8080伺服器域名
  • SpringMVC部署在伺服器上的web站點
  • hello表示控制器
  • 通過分析,如上url表示為:請求位于伺服器localhost:8080上的SpringMVC站點的hello控制器。
  1. HandlerMapping為處理器映射。DispatcherServlet調用HandlerMapping,HandlerMapping根據請求url查找Handler。
  2. HandlerExecution表示具體的Handler,其主要作用是根據url查找控制器,如上url被查找控制器為:hello。
  3. HandlerExecution将解析後的資訊傳遞給DispatcherServlet,如解析控制器映射等。
  4. HandlerAdapter表示處理器擴充卡,其按照特定的規則去執行Handler。
  5. Handler讓具體的Controller執行。
  6. Controller将具體的執行資訊傳回給HandlerAdapter,如ModelAndView。
  7. HandlerAdapter将視圖邏輯名或模型傳遞給DispatcherServlet。
  8. DispatcherServlet調用視圖解析器(ViewResolver)來解析HandlerAdapter傳遞的邏輯視圖名。
  9. 視圖解析器将解析的邏輯視圖名傳給DispatcherServlet。
  10. DispatcherServlet根據視圖解析器解析的視圖結果,調用具體的視圖。
  11. 最終視圖呈現給使用者。

3、HelloSpringMVC(配置版)

3.1、建立一個Moudle , 添加web的支援!

3.2、确定導入了SpringMVC 的依賴!

3.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">

    <!--    配置DispatchServlet:這個是MVC的核心;也叫請求分發器,或前端控制器-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <!--       DispatchServlet要綁定SpringMVC的配置檔案-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-serlvet.xml</param-value>
        </init-param>

<!--        啟動級别-->
        <load-on-startup>1</load-on-startup>
    </servlet>

<!--
    在SpringMVC中  /   /*
    /  :隻比對所有的請求,不會去比對jsp頁面
    /*  :比對所有的請求,包括jsp頁面
-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>      

3.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>      

3.5、添加 處理映射器

3.6、添加 處理器擴充卡

3.7、添加 視圖解析器

如下:

<?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">

<!--    處理器映射器-->
<!--   從這開始執行,BeanNameUrlHandlerMapping:bean找到/hello..找到對應的類-->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--    處理器擴充卡-->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

<!--    視圖解析器;模闆引擎Thymeleaf  Fremarker-->
    <!--視圖解析器:DispatcherServlet給他的ModelAndView-->
<!--    傳回的 ModelAndView交給視圖解析器去做-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--        字首-->
        <property name="prefix"  value="/WEB-INF/jsp/"/>
<!--        字尾-->
        <property name="suffix" value=".jsp"/>
    </bean>

<!--    BeanNameUrlHandlerMapping:bean-->
    <bean id="/hello" class="com.kk.controller.HelloController"></bean>
</beans>      

3.8、編寫我們要操作業務Controller ,要麼實作Controller接口,要麼增加注解;需要傳回一個ModelAndView,裝資料,封視圖;

package com.kk.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;
    }
}      

3.9、将自己的類交給SpringIOC容器(寫到springmvc-servlet.xml),注冊bean

<!--Handler-->
<bean id="/hello" class="com.kuang.controller.HelloController"/>      

3.10、寫要跳轉的jsp頁面,顯示ModelandView存放的資料,以及我們的正常頁面;

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
${msg}
</body>
</html>      

3.1.1、配置Tomcat 啟動測試!

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

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

  1. 檢視控制台輸出,看一下是不是缺少了什麼jar包。
  2. 如果jar包存在,顯示無法輸出,就在IDEA的項目釋出中,添加lib依賴!(與classes同級目錄)
❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️
**小結**:看這個估計大部分同學都能了解其中的原理了,但是我們實際開發才不會這麼寫,不然就瘋了,還學這個玩意幹嘛!我們來看個注解版實作,這才是SpringMVC的精髓,到底有多麼簡單,看這個圖就知道了。      
❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

圖來源:狂神說,如有侵權,請聯系删除!

4、使用注解開發SpringMVC(注解版)

4.1、第一步:建立一個Moudle , 添加web支援!建立包結構 com.kk.controller

4.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>      

4.3、第三步:在pom.xml檔案引入相關的依賴:

主要有Spring架構核心庫、Spring MVC、servlet , JSTL等。我們在父依賴中已經引入了!

4.4、第四步:配置web.xml

注意點:

  • 注意web.xml版本問題,要最新版!
  • 注冊DispatcherServlet
  • 關聯SpringMVC的配置檔案
  • 啟動級别為1
  • 映射路徑為 / 【不要用/*,會404】

4.5、第五步:添加Spring MVC配置檔案

  • 讓IOC的注解生效
  • 靜态資源過濾 :HTML . JS . CSS . 圖檔 , 視訊 …
  • 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="com.kk.controller"/>
    <!-- 讓Spring MVC不處理靜态資源 過濾掉一些靜态資源,如.css  .js  .html .mp3-->
    <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/目錄下,這樣可以保證視圖安全,因為這個目錄下的檔案,用戶端不能直接通路。

4.6、第六步:建立Controller

編寫一個Java控制類: com.kuang.controller.HelloController , 注意編碼規範

package com.kk.controller;


import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller

public class HelloController {


    @RequestMapping("/hello")
    public String hello(Model model){
        //封裝資料
        model.addAttribute("msg","Hello SpringMVCAnnotation");
        return "hello"; //這個會被視圖解析器處理;
    }

}      
  • @Controller是為了讓Spring IOC容器初始化時自動掃描到;
  • @RequestMapping是為了映射請求路徑,這裡因為類與方法上都有映射是以通路時應該是/HelloController/hello;
  • 方法中聲明Model類型的參數是為了把Action中的資料帶到視圖中;
  • 方法傳回的結果是視圖的名稱hello,加上配置檔案中的前字尾變成WEB-INF/jsp/hello.jsp。

4.7、第七步:建立視圖層

在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>      

4.8、第八步:配置Tomcat運作

配置Tomcat , 開啟伺服器 , 通路 對應的請求路徑!

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

運作成功!

小結

實作步驟非常的簡單:

  1. 建立一個web項目
  2. 導入相關jar包
  3. 編寫web.xml , 注冊DispatcherServlet
  4. 編寫springmvc配置檔案
  5. 接下來就是去建立對應的控制類 , controller
  6. 最後完善前端視圖和controller之間的對應
  7. 測試運作調試.

使用springMVC必須配置的三大件:

處理器映射器、處理器擴充卡、視圖解析器

通常,我們隻需要手動配置視圖解析器,而處理器映射器和處理器擴充卡隻需要開啟注解驅動即可,而省去了大段的xml配置

5、Controller 及 RestFul風格

控制器Controller

  • 控制器複雜提供通路應用程式的行為,通常通過接口定義或注解定義兩種方法實作。
  • 控制器負責解析使用者的請求并将其轉換為一個模型。
  • 在Spring MVC中一個控制器類可以包含多個方法
  • 在Spring MVC中,對于Controller的配置方式有很多種

    我們來看看有哪些方式可以實作:

實作Controller接口

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

測試

  1. 建立一個Moudle,springmvc-04-controller 。 将剛才的03 拷貝一份, 我們進行操作!
  • 删掉HelloController
  • mvc的配置檔案隻留下 視圖解析器!
  1. 編寫一個Controller類,ControllerTest1
package com.kk.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 ControllerTest01 implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg","ControllerTest01!");  //添加資料

        mv.setViewName("test");  //設定跳轉視圖  跳轉到哪 由這個控制  如 跳轉到test(.jps頁面)

        return mv;
    }
}      

編寫完畢後,去Spring配置檔案中注冊請求的bean;name對應請求路徑,class對應處理請求的類

<bean name="/test" class="com.kk.controller.ControllerTest01"/>      

編寫前端test.jsp,注意在WEB-INF/jsp目錄下編寫,對應我們的視圖解析器

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
${msg}
</body>
</html>      

配置Tomcat運作測試,我這裡沒有項目釋出名配置的就是一個 / ,是以請求不用加項目名;

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

說明:

  • 實作接口Controller定義控制器是較老的辦法
  • 缺點是:一個控制器中隻有一個方法,如果要多個方法則需要定義多個Controller;定義的方式比較麻煩;

使用注解@Controller

  • @Controller注解類型用于聲明Spring類的執行個體是一個控制器(在講IOC時還提到了另外3個注解);
  • Spring可以使用掃描機制來找到應用程式中所有基于注解的控制器類,為了保證Spring能找到你的控制器,需要在配置檔案中聲明元件掃描。
<context:component-scan base-package="com.kk.controller"/>      

增加一個ControllerTest2類,使用注解實作;

package com.kk.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller  //代表這個類會被Spring接管,被這個注解的類,中的所有方法,
// 如果傳回值是String 并且有具體頁面可以跳轉,那麼就會被視圖解析器解析;
public class ControllerTest02{
    @RequestMapping("/test2")
    public String test1(Model model){
        model.addAttribute("msg","ControllerTest02!");


        return "test";
    }

}      

運作tomcat測試

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

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

RequestMapping

@RequestMapping

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

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("c3")
public class ControllerTest03 {
    @RequestMapping("t1")
    public String test1(Model model){
        model.addAttribute("msg","ControllerTest03");
        return "test";
    }
}      

通路路徑:​​http://localhost​​:8080 /c3/t1 , 需要先指定類的路徑再指定方法的路徑;

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

6、RestFul 風格(簡潔,高效,安全)

概念

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

功能

  • 資源:網際網路所有的事物都可以被抽象為資源
  • 資源操作:使用POST、DELETE、PUT、GET,使用不同方法對資源進行操作。
  • 分别對應 添加、 删除、修改、查詢。

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

測試1:

1.在建立一個類 RestFulController

package com.kk.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class RestFulController {

    //原來的方式 http://localhost:8080/add?a=1&b=10

    @RequestMapping("/add")
    public String test1(int a, int b, Model model){
        int res=a+b;
        model.addAttribute("msg","結果為:"+res);

        return "test";
    }
}      
❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

測試2:

2.在Spring MVC中可以使用 @PathVariable 注解,讓方法參數的值對應綁定到一個URI模闆變量上。

package com.kk.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class RestFulController {


    // RestFul http://localhost:8080/add/a/b

    @RequestMapping("/add/{a}/{b}")
    public String test1(@PathVariable int a,@PathVariable int b, Model model){
        int res=a+b;
        model.addAttribute("msg","結果為:"+res);

        return "test";
    }
}      
❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

思考:使用路徑變量的好處?

  • 使路徑變得更加簡潔;
  • 獲得參數更加友善,架構會自動進行類型轉換。
  • 通過路徑變量的類型可以限制通路參數,如果類型不一樣,則通路不到對應的請求方法,如這裡通路是的路徑是/commit/1/a,則路徑與方法不比對,而不會是參數轉換失敗。
❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

圖來源:狂神說,如有侵權,請聯系删除!

我們來修改下對應的參數類型,再次測試

@Controller
public class RestFulController {

    @PostMapping("/add/{a}/{b}")
    public String test1(@PathVariable int a,@PathVariable String b, Model model){
//        int res=a+b;
          String res=a+b;
        model.addAttribute("msg","結果1為:"+res);

        return "test";
    }

}      
❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

圖來源:狂神說,如有侵權,請聯系删除!

使用method屬性指定請求類型

用于限制請求的類型,可以收窄請求範圍。指定請求謂詞的類型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等

我們來測試一下:

  • 增加一個方法
//映射通路路徑,必須是POST請求
@RequestMapping(value = "/hello",method = {RequestMethod.POST})
public String test(Model model){
    model.addAttribute("msg", "hello!");
    return "test";
}      

我們使用浏覽器位址欄進行通路預設是Get請求,會報錯405:

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

圖來源:狂神說,如有侵權,請聯系删除!

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

//映射通路路徑,必須是Get請求
@RequestMapping(value = "/hello",method = {RequestMethod.GET})
public String test(Model model){
    model.addAttribute("msg", "hello!");
    return "test";
}      
❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

圖來源:狂神說,如有侵權,請聯系删除!

小結:

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

所有的位址欄請求預設都會是 HTTP GET 類型的

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

@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping      

@GetMapping 是一個組合注解

@Controller
public class RestFulController {


    //映射通路路徑
    @GetMapping("/commit/{a}/{b}")
    public String test2(@PathVariable int a,@PathVariable String b, Model model){

        String res=a+b;
        model.addAttribute("msg","結果2為:"+res);

        return "test";
    }
}      

7、SpringMVC:結果跳轉三種方式(轉發、重定向)

7.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 ControllerTest01 implements Controller {

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

7.2、ServletAPI

通過設定ServletAPI , 不需要視圖解析器 .

  1. 通過HttpServletResponse進行輸出
  2. 通過HttpServletResponse實作重定向
  3. 通過HttpServletResponse實作轉發
@Controller
public class ResultGo {

    @RequestMapping("/m1/t1")
    public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
        rsp.getWriter().println("Hello,Spring BY servlet API");
    }

    @RequestMapping("/m2/t2")
    public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
        rsp.sendRedirect("/index.jsp");
    }

    @RequestMapping("/m3/t3")
    public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
        //轉發
        req.setAttribute("msg","/m3/t3");
        req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);
    }

}      

7.3、SpringMVC

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

測試前,需要将視圖解析器注釋掉

package com.kk.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@Controller
public class ModelTest01 {


//    @RequestMapping("/m1/t1")
//    public String test(HttpServletRequest request, HttpServletResponse response){
//        HttpSession session = request.getSession();
//        System.out.println(session.getId());
//
//        return "/test.jsp";
//    }


//        @RequestMapping("/m1/t1")
//    public String test(Model model){
//            model.addAttribute("msg","ModelTest01");
//            //轉發
//            return "forward:/WEB-INF/jsp/test.jsp";
//   }

    //http://localhost:8080/index.jsp?msg=ModelTest01
    @RequestMapping("/m1/t1")
    public String test2(Model model){
        model.addAttribute("msg","ModelTest01");
        //重定向
        return "redirect:/index.jsp";
    }
}      

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

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

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

@Controller
public class ResultSpringMVC2 {
    @RequestMapping("/m1/t1")
    public String test1(){
        //轉發
        return "test";
    }

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

}      

8、資料處理(接收請求參數及資料回顯)

8.1、處理送出資料

1、送出的域名稱和處理方法的參數名一緻

送出資料 : ​​http://localhost​​:8080/user/t1?name=dada

@Controller
@RequestMapping("/user")
public class UserController {
    @GetMapping("/t1")
    public String test(tring name, Model model){
        //1.接收前端參數
        System.out.println("接收到前端的參數為為:"+name);
        //2.将傳回的結果傳遞給前端   Model
        model.addAttribute("msg",name);
        //3.視圖傳遞
        return "test";
    }

}      

背景輸出 : dada

2、送出的域名稱和處理方法的參數名不一緻

送出資料 : ​​http://localhost​​:8080/user/t1?username=dada

處理方法 :

@Controller
@RequestMapping("/user")
public class UserController {
    @GetMapping("/t1")
    public String test(@RequestParam("username") String name, Model model){
        //1.接收前端參數
        System.out.println("接收到前端的參數為為:"+name);
        //2.将傳回的結果傳遞給前端   Model
        model.addAttribute("msg",name);
        //3.視圖傳遞
        return "test";
    }

}      

背景輸出 :

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

要求送出的表單域和對象的屬性名一緻 , 參數使用對象即可

1.實體類

package com.kk.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
    private int id;
    private String name;
    private int age;
}      

處理方法 :

package com.kk.controller;

import com.kk.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/user")
public class UserController {

    //前端接收的是一個對象 id name age
    /*
    1.接收前端使用者傳遞的參數,判斷參數的名字,假設名字直接在方法上,可以直接使用
    2.假設傳遞的是一個對象User 比對User對象中的字段名,如果名字一直則ok  否則比對不到
     */
    @GetMapping("/t2")
    public String test2(User user){
        System.out.println(user);
        return "test";
    }


}      

送出資料:http://localhost:8080/user/t2?id=1&name=王&age=17

背景輸出:User{id=1, name=‘王’, age=17}

8.2、資料顯示到前端

第一種 : 通過ModelAndView

public class ControllerTest01 implements Controller {

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

第二種 : 通過ModelMap

ModelMap

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

第三種 : 通過Model

Model

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

8.3、對比

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

Model 隻有寥寥幾個方法隻适合用于儲存資料,簡化了新手對于Model對象的操作和了解;

ModelMap 繼承了 LinkedMap ,除了實作了自身的一些方法,同樣的繼承 LinkedMap 的方法和特性;

ModelAndView 可以在儲存資料的同時,可以進行設定傳回的邏輯視圖,進行控制展示層的跳轉。      

9、資料處理(亂碼問題)

測試步驟:

1.我們可以在首頁編寫一個送出的表單

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/e/t1" method="post">
    <input type="text" name="name">
    <input type="submit">
</form>

</body>
</html>      

2.背景編寫對應的處理類

@Controller
public class EncodingController {

  
    @RequestMapping("/e/t1")
    public String test1(String name, Model model){
        System.out.println(name);
        model.addAttribute("msg",name);//使用視圖解析器,将資料傳遞到return test(即test.jsp頁面)
        return "test";
    }
}      

3.輸入中文測試,發現亂碼

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

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

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

修改了xml檔案需要重新開機伺服器!

<!--2.配置SpringMVC的亂碼過濾-->
<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>      

有些極端情況下.這個過濾器對get的支援不好 .

處理方法 :

1.修改tomcat配置檔案 : 設定編碼!

<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />      

2.自定義過濾器

package com.kk.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;

public class GenericEncodingFilter implements Filter {

    public void destroy() {
    }


    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("===========================");
        //處理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);
    }


    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;
    }

}      

3.在web中注冊:

<filter>
    <filter-name>encoding</filter-name>
    <filter-class>com.kk.filter.GenericEncodingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>      

這個也是我在網上找的一些大神寫的,一般情況下,SpringMVC預設的亂碼處理就已經能夠很好的解決了!

平常使用SringMVC過濾器即可,在web中注冊!

<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>      

10、JSON講解

9.1、什麼是JSON?

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

在 JavaScript 語言中,一切都是對象。是以,任何JavaScript 支援的類型都可以通過 JSON 來表示,例如字元串、數字、對象、數組等。看看他的要求和文法格式:

  • 對象表示為鍵值對,資料由逗号分隔
  • 花括号儲存對象
  • 方括号儲存數組

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

{"name": "kk"}
{"age": "17"}
{"sex": "男"}      

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

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

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>Title</title>
  <script type="text/javascript">//編寫與一個JavaScript對象
    var user={
      name:"小白",
      age:17,
      sex:"男"
    };
    //将js對象轉換為json對象
    var json=JSON.stringify(user);
    console.log(json);
    console.log("========================");
   //将json對象轉換為JavaScript對象
    var obj=JSON.parse(json);
    console.log(obj);</script>
</head>
<body>

</body>
</html>      

3.在IDEA中使用浏覽器打開,檢視控制台輸出!

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

9.2、Controller傳回JSON資料

1.jackson

  • 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.10.0</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;

public class User {
    private String name;
    private int age;
    private String sex;

    public User() {
    }

    public User(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}      
  • 這裡我們需要兩個新東西,一個是@ResponseBody,一個是ObjectMapper對象,我們看下具體的用法

Controller

package com.kk.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kk.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {
    @RequestMapping("/j1")
    @ResponseBody  //隻要增加了ResponseBody  它就不會走試圖解析器,會直接傳回一個字元串
    public String Json1() throws JsonProcessingException {

        //jackson  ObjectMapper
        ObjectMapper mapper=new ObjectMapper();

        //建立一個對象
        User user = new User("1号",17,"男");

        //将user轉換為Json
        String str = mapper.writeValueAsString(user);


        return  str;
    }
}      
  • 配置Tomcat , 啟動測試一下!
  • ❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️
  • 發現出現了亂碼問題,我們需要設定一下他的編碼格式為utf-8,以及它傳回的類型;
  • 通過@RequestMaping的produces屬性來實作,修改下代碼
//produces:指定響應體傳回類型和編碼
@RequestMapping(value = "/j1",produces = "application/json;charset=utf-8")      
  • 再次測試,​​http://localhost​​:8080/j1 , 亂碼問題OK!
❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

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

代碼優化

亂碼統一解決

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

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

<!--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>      

傳回json字元串統一解決

在類上直接使用 @RestController ,這樣子,裡面所有的方法都隻會傳回 json 字元串了,不用再每一個都添加@ResponseBody !我們在前後端分離開發中,一般都使用 @RestController ,十分便捷!

//@Controller  會調用視圖解析器
@RestController //會傳回字元串
public class UserController {
//    @RequestMapping(value = "/j1",produces = "application/json;charset=utf-8")
    @RequestMapping(value = "/j1")
//    @ResponseBody  //隻要增加了ResponseBody  它就不會走試圖解析器,會直接傳回一個字元串
    //使用了RestController就不用ResponseBody了
    public String Json1() throws JsonProcessingException {

        //jackson  ObjectMapper
        ObjectMapper mapper=new ObjectMapper();
        //建立一個對象
        User user = new User("1号",17,"男");
        //将user轉換為Json
        String str = mapper.writeValueAsString(user);
        return  str;
    }

}      

啟動tomcat測試,結果都正常輸出!

測試集合輸出

增加一個新的方法

//@Controller  會調用視圖解析器
@RestController //會傳回字元串
public class UserController {
//    @RequestMapping(value = "/j1",produces = "application/json;charset=utf-8")
    @RequestMapping(value = "/j1")
//    @ResponseBody  //隻要增加了ResponseBody  它就不會走試圖解析器,會直接傳回一個字元串
    //使用了RestController就不用ResponseBody了
    public String Json1() throws JsonProcessingException {

        //jackson  ObjectMapper
        ObjectMapper mapper=new ObjectMapper();
        //建立一個對象
        User user = new User("1号",17,"男");
        //将user轉換為Json
        String str = mapper.writeValueAsString(user);
        return  str;
    }

    @RequestMapping(value = "/j2")
    public String Json2() throws JsonProcessingException {
        ObjectMapper mapper=new ObjectMapper();
        //使用集合
        List<User> userList=new ArrayList<User>();
        User user1 = new User("1号",17,"男");
        User user2 = new User("1号",17,"男");
        User user3 = new User("1号",17,"男");
        User user4 = new User("1号",17,"男");
        User user5 = new User("1号",17,"男");
        User user6 = new User("1号",17,"男");
        User user7 = new User("1号",17,"男");
        userList.add(user1);
        userList.add(user2);
        userList.add(user3);
        userList.add(user4);
        userList.add(user5);
        userList.add(user6);
        userList.add(user7);
        String str = mapper.writeValueAsString(userList);
        return  str;
    }

}      

啟動tomcat測試,結果都正常輸出!

輸出時間對象

增加一個新的方法

@RequestMapping("/json3")

public String json3() throws JsonProcessingException {

@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;
    }
}      

運作結果 :

  • 預設日期格式會變成一個數字,是1970年1月1日到目前日期的毫秒數!
  • Jackson 預設是會把時間轉成timestamps形式

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

//@Controller  會調用視圖解析器
@RestController //會傳回字元串
public class UserController {

    @RequestMapping(value = "/j3")
    public String Json3() throws JsonProcessingException {
        ObjectMapper mapper=new ObjectMapper();

        //使用ObjectMapper 來格式化輸出
        //不使用時間戳的方法
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);

        Date date = new Date();
        //ObjectMapper  時間解析後的預設格式為 時間戳 Timestamp

        //自定義日期格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = sdf.format(date);
        String str = mapper.writeValueAsString(format);
        return  str;
    }
}      

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

也可以這樣!

方式一:

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

        ObjectMapper mapper = new ObjectMapper();
        Date date = new Date();
        //自定義日期的格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // objectMapper,時間解析後的預設格式為: Timestamp, 時間裁
        return mapper.writeValueAsString(sdf.format(date));

    }      

方式二:

//@Controller  會調用視圖解析器
@RestController //會傳回字元串
public class UserController {


    @RequestMapping(value = "/j3")
    public String Json3() throws JsonProcessingException {
        ObjectMapper mapper=new ObjectMapper();

        //使用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();
        //ObjectMapper  時間解析後的預設格式為 時間戳 Timestamp
        return  mapper.writeValueAsString(date);
    }
}      

抽取為工具類

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

package com.kk.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.text.SimpleDateFormat;

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();
        //不使用時間戳的方法
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);

        //自定義日期格式
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        mapper.setDateFormat(sdf);

        try {
            return mapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

}      

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

@RequestMapping(value = "/j4")
    public String Json4() throws JsonProcessingException {
        Date date=new Date();
//        return JsonUtils.getJson(date,"yyyy-MM-dd HH:mm:ss");
        return  JsonUtils.getJson(date);
    }      

2.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 三個主要的類:

  • 【JSONObject 代表 json 對象 】
  • JSONObject實作了Map接口, 猜想 JSONObject底層操作是由Map實作的。
  • JSONObject對應json對象,通過各種形式的get()方法可以擷取json對象中的資料,也可利用諸如size(),isEmpty()等方法擷取"鍵:值"對的個數和判斷是否為空。其本質是通過實作Map接口并調用接口中的方法完成的。
  • 【JSONArray 代表 json 對象數組】
  • 内部是有List接口中的方法來完成操作的。
  • 【JSON 代表 JSONObject和JSONArray的轉化】
  • JSON類源碼分析與使用
  • 仔細觀察這些方法,主要是實作json對象,json對象數組,javabean對象,json字元串之間的互相轉化。

代碼測試,我們建立一個測試 類

//@Controller  會調用視圖解析器
@RestController //會傳回字元串
public class UserController {

    @RequestMapping(value = "/j5")
    public String Json5() throws JsonProcessingException {
        ObjectMapper mapper=new ObjectMapper();
        //使用集合
        List<User> userList=new ArrayList<User>();
        User user1 = new User("1号",17,"男");
        User user2 = new User("1号",17,"男");
        User user3 = new User("1号",17,"男");
        User user4 = new User("1号",17,"男");
        User user5 = new User("1号",17,"男");
        User user6 = new User("1号",17,"男");
        User user7 = new User("1号",17,"男");
        userList.add(user1);
        userList.add(user2);
        userList.add(user3);
        userList.add(user4);
        userList.add(user5);
        userList.add(user6);
        userList.add(user7);

        String s = JSON.toJSONString(userList);
        return s;

    }

}      

測試:

​​http://localhost​​:8080/j5

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

11、Ajax研究

  • 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使用者界面。

僞造Ajax

我們可以使用前端的一個标簽來僞造一個ajax的樣子。iframe标簽

1、建立一個module :sspringmvc-06-ajax , 導入web支援!

2、編寫一個 ajax-frame.html 使用 iframe 測試,感受下效果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>iframe測試體驗頁面無重新整理</title>
  <script>function go(){
      var url=document.getElementById("url").value;
      document.getElementById("iframe1").src=url;
    }</script>
</head>
<body>
<div>
  <p>請輸入位址:</p>
  <p>
    <input type="text" id="url" value="https://blog.csdn.net/weixin_50569789?spm=1000.2115.3001.5343">
    <input type="button" value="送出" onclick="go()">
  </p>
</div>
<div>
  <iframe id="iframe1"style="width: 100%;height: 500px;"></iframe>
</div>
</body>
</html>      

3、使用IDEA開浏覽器測試一下!

利用AJAX可以做:

  • 注冊時,輸入使用者名自動檢測使用者是否已經存在。
  • 登陸時,提示使用者名密碼錯誤
  • 删除資料行時,将行ID發送到背景,背景在資料庫中删除,資料庫删除成功後,在頁面DOM中将資料行也删除。

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:請求方式,GET、POST(1.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 将自動替換 ? 為正确的函數名,以執行回調函數      

簡單案例:(前後端互動)

1、配置web.xml 和 application的配置檔案,複制上面案例的即可 【記得靜态資源過濾和注解驅動配置上】

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">

    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:application.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <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>      

application

<?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
    https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.kk.controller"/>
    <mvc:annotation-driven/>

<!--    靜态資源過濾-->
    <mvc:default-servlet-handler/>
    <mvc:annotation-driven/>


    <!-- 3.配置jsp 顯示ViewResolver視圖解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>      

2、編寫一個AjaxController

package com.kk.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@RestController
public class AjaxController {
    @RequestMapping("/t1")
    public String test(){
        return "hello";
    }

    @RequestMapping("a1") //發起一個請求
    public void a1(String name, HttpServletResponse response) throws IOException {
        System.out.println("a1:param=>"+name);
        if ("kk".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="${pageContext.request.contextPath}/static/js/jquery-3.6.0.js"></script>

    <script>function a() {
        $.post({
          url:"${pageContext.request.contextPath}/a1",
          data:{"name":$("#username").val()}, //取到輸入框的值
          success:function (data,status) {
            console.log("data="+data);
            console.log("status="+status);
          },error:function () {

          }

        })
      }</script>
  </head>
  <body>

<%--  失去焦點的時候,發起一個請求(攜帶資訊)到背景--%>
  使用者名:<input type="text" id="username" onblur="a()">


  </body>
</html>      

5、啟動tomcat測試!打開浏覽器的控制台,當我們滑鼠離開輸入框的時候,可以看到發出了一個ajax的請求!是背景傳回給我們的結果!測試成功!

Springmvc實作

實體類User

package com.kk.pojo;


public class User {

    private String name;
    private int age;
    private String sex;

    public User() {
    }

    public User(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}      

我們來擷取一個集合對象,展示到前端頁面

@RequestMapping("a2")
public List<User> a2(){
    List<User> userList = new ArrayList<User>();
    //添加資料
    userList.add(new User("Java",1,"男"));
    userList.add(new User("Linus",1,"男"));
    userList.add(new User("Mysql",1,"男"));
    return userList;
}      

前端頁面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/static/js/jquery-3.6.0.js"></script>
    <script>
        $(function () {
            $("#btn").click(function(){
                $.post({
                    url:"${pageContext.request.contextPath}/a2",
                    success:function (data) {
                        console.log(data)
                        var 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);
                    }
                })

            })
        })




    </script>



</head>
<body>
<input type="button" value="加載資料" id="btn">
<table>
    <tr>
        <td>姓名</td>
        <td>年齡</td>
        <td>性别</td>
    </tr>
    <tbody id="content">
<%--    資料: 從背景擷取--%>
    </tbody>
</table>
</body>
</html>      

成功實作了資料回顯!

Ajax驗證使用者名案例

AjaxController

@RequestMapping("/a3")
public String a3(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;
}      

需要在application配置json亂碼問題

<?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
    https://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!--自動掃描指定的包 下面所有注解類交給IOC容器管理-->
    <context:component-scan base-package="com.kk.controller"/>
    <mvc:annotation-driven/>

    <!--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>


<!--    靜态資源過濾-->
    <mvc:default-servlet-handler/>



    <!-- 3.配置jsp 顯示ViewResolver視圖解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>      

login.jsp頁面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/static/js/jquery-3.6.0.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); //将資料回報到前端頁面去
                // console.log(data.toString()); //轉換為字元串
            }
            })
        }

        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); //将資料回報到前端頁面去
                    // console.log(data.toString()); //轉換為字元串
                }
            })

        }
    </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>      

動态請求響應,局部重新整理,就是如此!

❤️六萬字《SpringMVC架構介紹—從入門到進階》(建議收藏)❤️

案例擷取baidu接口

<!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>      

攔截器

概述

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

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

過濾器

  • servlet規範中的一部分,任何java web工程都可以使用
  • 在url-pattern中配置了/*之後,可以對所有要通路的資源進行攔截

攔截器

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

自定義攔截器

那如何實作攔截器呢?

想要自定義攔截器,必須實作 HandlerInterceptor 接口。

1、建立一個Moudule , springmvc-07-Interceptor , 添加web支援

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

3、編寫一個攔截器

package com.kk.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  不執行下一個攔截器
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("======================處理前========================");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("======================處理後========================");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("=====================清理=========================");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}
//這裡寫完之後 需要到application.xml中配置      

4、在springmvc(或者application.xml)的配置檔案中配置攔截器

<!--    攔截器配置-->
    <mvc:interceptors>
        <mvc:interceptor>
<!--            包括這個請求下面的所有請求  /admin/ada/daad-->
            <mvc:mapping path="/**"/>
            <bean class="com.kk.config.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>      

5、編寫一個Controller,接收請求

//測試攔截器的控制器
@Controller
public class InterceptorController {

   @RequestMapping("/interceptor")
   @ResponseBody
   public String testFunction() {
       System.out.println("控制器中的方法執行了");
       return "hello";
  }
}      

6、前端 index.jsp

<a href="${pageContext.request.contextPath}/interceptor">攔截器測試</a>      

7、啟動tomcat 測試一下!

使用攔截器驗證使用者是否登入 (認證使用者)

實作思路

1、有一個登陸頁面,需要寫一個controller通路頁面。

2、登陸頁面有一送出表單的動作。需要在controller中處理。判斷使用者名密碼是否正确。如果正确,向session中寫入使用者資訊。傳回登陸成功。

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

測試:

1、編寫一個登陸頁面 在web的web-inf目錄下建立jsp檔案夾,然後建立login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>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="password" name="password"/>
        <input type="submit" value="登陸">
    </form>
</body>
</html>      

2、編寫一個Controller處理請求

package com.kk.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;

@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){
        System.out.println("login=>"+username);
        //把使用者的資訊存在session中
        session.setAttribute("userLoginInfo",username);
        model.addAttribute("username",username);
        return "main";  //點選送出登陸之後 跳轉到首頁
    }

    @RequestMapping("/goOut")
    public String goOut(HttpSession session){
        session.removeAttribute("userLoginInfo");
        return "main";  //點選登出之後 跳轉到首頁
    }
}      

3、編寫一個登入成功後跳轉到首頁面 在web的web-inf目錄下建立jsp檔案夾下建立main.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>首頁</h1>
<%--    使用model将資料顯示給前端--%>
<span>${username}</span>
<p>
    <a href="${pageContext.request.contextPath}/user/goOut">登出</a>
</p>


</body>
</html>      

5、編寫使用者登入攔截器

package com.kk.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 {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();

        // 放行的判斷:判斷什麼情況下登陸了

        //在登陸頁面 也放行
        if (request.getRequestURI().contains("Login")){
            return true;
        }
        //說明我在送出登陸
        if (request.getRequestURI().contains("login")){
            return true;
        }

        //第一次登陸 也是沒有session的
        if (session.getAttribute("userLoginInfo")!=null){
            return true;
        }


        //判斷什麼情況下沒有登陸
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);//重定向
        return false;
    }
}      

6、在Springmvc(application.xml)的配置檔案中注冊攔截器

<!--    運用了橫切aop思想-->
    <!--    攔截器配置-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--            包括這個請求下面的所有請求  /admin/ada/daad-->
            <mvc:mapping path="/user/**"/>
            <bean class="com.kk.config.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>      

7、再次重新開機Tomcat測試!

OK,測試登入攔截功能無誤.

檔案上傳和下載下傳

準備工作

檔案上傳是項目開發中最常見的功能之一 ,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的元件。

檔案上傳

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

<dependencies><!--檔案上傳 使用最高版本-->
        <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</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的錯誤!在這裡栽過坑,教訓!】

CommonsMultipartFile 的 常用方法:

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

測試

3.編寫前端頁面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
    <input type="file" name="file"/>
    <input type="submit">
  </form>
  </body>
</html>      

4、Controller

方式一:

package com.kk.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 java.io.*;


@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 來儲存上傳的檔案

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!

檔案下載下傳

檔案下載下傳步驟:

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 = "img.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="${pageContext.request.contextPath}/static/img.png">點選下載下傳</a>      

測試,檔案下載下傳OK

完結!!!

) 将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 來儲存上傳的檔案**

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";
}      

2、前端表單送出位址修改

3、通路送出測試,OK!

檔案下載下傳

檔案下載下傳步驟:

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 = "img.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="${pageContext.request.contextPath}/static/img.png">點選下載下傳</a>