SpringMVC學習筆記

SpringMVC學習筆記

Spring MVC框架入門教程

ssm: MyBatis + Spring + SpringMVCjavascript

1. 回顧MVC

1.1 什麼是 MVC

  • MVC 是模型(Model)、視圖(View)、控制器(Controller)的簡寫,是一種軟件設計規範。
  • 是將業務邏輯、數據、顯示分離的方法來組織代碼。
  • MVC 主要做用是下降了視圖與業務邏輯間的雙向耦合。
  • MVC 不是一種設計模式,MVC 是一種架構模式,固然不一樣的 MVC 存在差別。

Model(模型):數據類型,提供要展現的數據,所以包含數據和行爲,能夠認爲是領域模型或 JavaBean 組件(包含數據和行爲)。不過如今通常都分離開來: Value Object(數據 Dao)和服務層(行爲 Service)。也就是模型提供了模型數據查詢和模型數據的狀態更新等功能,包括數據和業務。css

View(視圖):負責進行模型的展現,通常就是咱們見到的用戶界面,客戶想看到的東西。html

Controller(控制器):接收用戶請求,委託給模型進行處理(狀態改變)。處理完畢後把返回的模型數據返回給視圖,由視圖負責展現。也就是說控制器作了個調度員的工做。前端

最典型的MVC 就是 JSP + Servlet + JavaBean 的模式vue

image-20200512101727380

1.2 Model1時代

  • 在web早期的開發中,一般採用的是 Model1。java

  • Model1中,主要分爲兩層,視圖層和模型層mysql

image-20200512105946239

Model1 的優勢:架構簡單,比較適合小型項目的開發。react

Model1 的缺點:JSP 職責不單一,職責太重,不便於維護。jquery

1.3 Model2時代

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

image-20200512111319240

職責分析:

Controller:控制器

  1. 獲取表單數據

  2. 調用業務邏輯

  3. 轉向指定的頁面

Model:模型

  1. 業務邏輯
  2. 保存數據的狀態

View:視圖

  1. 顯示頁面

Model1 和 Model2 的對比:

Model2 這樣不只提升了代碼的複用率與項目的拓展性,並且大大下降了項目的維護成本。

Model1模式的實現比較簡單,適用於快速開發小規模項目,Model1 中的 JSP 頁面身兼 View 和 Controller 兩種角色,將控制邏輯和表現邏輯混雜在一塊兒,從而致使代碼的重用性很是低,增長了應用的拓展性和維護的難度。Model2 消除了 Model1 的缺點。

1.4 回顧Servlet

  1. 新建一個 Maven 工程看成父工程,並在 pom.xml 中導入須要的依賴

    <dependencies>
            <!-- junit:測試 -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
            <!-- SpringMvc -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.3.RELEASE</version>
            </dependency>
            <!-- 開啓Servlet支持 -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>2.5</version>
            </dependency>
            <!-- 開啓jsp支持 -->
            <dependency>
                <groupId>javax.servlet.jsp</groupId>
                <artifactId>jsp-api</artifactId>
                <version>2.2</version>
            </dependency>
            <!-- jackson -->
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.10.2</version>
            </dependency>
            <!-- lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.10</version>
            </dependency>
        </dependencies>
  2. 創建一個 Module:SpringMVC-01-Servlet ,添加 Web app的支持

  3. 編寫一個Servlet類:HelloServlet

    public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 獲取前端參數
            String method = req.getParameter("method");
            if ("add".equals(method)){
                req.getSession().setAttribute("msg","執行了add方法");
            }
            if ("delete".equals(method)){
                req.getSession().setAttribute("msg","執行了delete方法");
            }
            // 調用業務層
            // 視圖轉發或重定向
            req.getRequestDispatcher("WEB-INF/jsp/test.jsp").forward(req,resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
  4. 在 web.xml 中配置 servlet

    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
  5. 配置 Tomcat 服務器,並將工程項目打包發佈

  6. 直接用 url 請求 Servlet

    http://localhost:8888/hello?method=add
    http://localhost:8888/hello?method=delete

MVC 框架要作哪些事情

  1. 將 url 映射到 java 類 或 java 方法
  2. 封裝用戶提交的數據
  3. 處理請求,調用相關的業務處理,封裝響應數據
  4. 將響應的數據進行渲染 jsp/html 等表示層數據

說明:

常見的服務端 MVC 框架: Struts、Spring MVC、ASP.NET MVC、Zend Frameword、JSF;

常見前端 MVC 框架:vue、angularjs、react、backbone;

由 MVC 演化出了另一些模式入:MVP、MVVM 等等

2. 什麼是Spring MVC

2.1 概述

Spring MVC 是 Spring Framework 的一部分,是基於 Java 實現 MVC 的輕量級 Web 框架。

官方文檔地址:https://docs.spring.io/spring/docs/5.3.0-SNAPSHOT/spring-framework-reference/web.html#spring-web

咱們爲何要學習 Spring MVC呢?

Spring MVC 的特色:

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

正是由於 SpringMVC 好,簡單,邊界,易學,天生和 Spring 無縫集成(使用 SpringIoC 和 Aop),使用約定優於配置,可以進行簡單的 junit 測試,支持 Restful 風格,異常處理,本地化,國際化,數據驗證,類型轉換,攔截器等等,因此咱們要學習。

最重要的一點仍是用的人多,使用的公司多。

2.2 中心控制器

Spring 的 web 框架圍繞 DispatcherServlet【調度Servlet】設計

DispatcherServlet 的做用是將請求分發到不一樣的處理器。從 Spring 2.5 開始,使用 Java 5 或者以上版本的用戶能夠採用基於註解形式進行開發,十分簡潔,用戶能夠採用基於註解的 controller 聲明方式。

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

image-20200512133503366

(圖片引自博客 https://blog.csdn.net/licwzy/article/details/81875635)

SpringMVC 的原理以下圖所示:

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

image-20200512143002247

2.3 SpringMVC 原理

image-20200512143317781

(圖引自狂神說公衆號)

圖爲 SpringMVC 的一個較完整的流程圖,實線表示 SpringMVC框架提供的技術,不須要開發者實現,虛線表示須要開發者實現。

須要分析執行流程

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

    咱們假設請求的url爲:http://localhost:8080/SpringMVC/hello

    如上url拆分紅三部分:

    http://localhost:8080:服務器域名

    SpringMVC: 部署在服務器上的 web 站點

    hello: 表示控制器

    經過分析,如上url表示爲:請求位於http://localhost:8080 上的 SpringMVC 站點的 hello 控制器

  2. HandlerMapping 爲處理器映射。DispatcherServlet 調用HandelerMapping,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. 視圖解析器將解析的邏輯視圖結果,調用具體的視圖。

  12. 最總視圖呈現給用戶。

3. 第一個SpringMVC項目

3.1 配置版

  1. 新建一個Moudle:SpringMVC-02-HelloMVC,添加 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">
        
        <!-- 註冊DispatcherServlet -->
        <servlet>
            <servlet-name>SpringMVC</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- 關聯一個SpringMVC配置文件:【servlet-name】 springmvc-servlet.xml -->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:config/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. 編寫咱們要操做的業務 Controller,要麼實現 Controller 接口,要麼增長註解;須要返回一個 ModelAndView ,裝數據,封視圖

    public class HelloController implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
            // 建立 ModelAndView 對象
            ModelAndView mv = new ModelAndView();
            // 封裝對象,放在 ModelAndView 中,Model
            mv.addObject("msg","HelloSpringMVC!");
            // 封裝要跳轉的視圖,放在 ModelAndView 中,至關於 /WEB-INF/jsp/hello.jsp
             mv.setViewName("hello");
            return mv;
        }
    }
  5. 編寫 SpringMVC 配置文件:springmvc-servlet.xml

    • 添加處理器映射器
    • 添加處理器適配器
    • 添加視圖解析器
    • 將本身的類交給 SpringIoC 容器,註冊 Bean
    <?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
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- 處理映射器 -->
        <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
        <!-- 處理器適配器 -->
        <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
    
        <!--視圖解析器: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>
    
       <!-- 跳轉的視圖 -->
        <bean id="/hello" class="controller.HelloController"/>
    
    </beans>
  6. 建立須要跳轉的 jsp 頁面,並顯示 ModelAndView 中存放的數據

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    ${msg}
    </body>
    </html>
  7. 配置 Tomcat 並啓動測試

    在 url 地址欄中輸入 http://localhost:8080/hello

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

  1. 查看控制檯輸出,看一下是否是缺乏了什麼 jar 包。
  2. 若是 jar 包存在,顯示沒法輸出,就在 IDEA 的項目發佈中,添加 lib文件夾,並添加對應的依賴
  3. 重啓 Tomcat便可解決

image-20200512163312333

上面配置版的 SpringMVC項目,能更好地理解 SpringMVC 的原理。可是,在咱們實際開發中並不會這麼寫。而是使用註解進行開發!

3.2 註解版

  1. 新建一個Moudle:SpringMVC-03-Hello-Annotation,添加 web 支持

  2. 導入依賴,並解決 Maven 資源過濾問題

    <!-- 解決 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. 建立 SpringMVC 配置文件

    在 resource 目錄下建立個 config 文件夾,並添加springmvc-servlet.xml 配置文件,配置的形式與 Spring 容器配置基本相似,爲了支持基於註解的 IoC,配置了自動掃描包的功能,

    配置步驟:

    • 讓 IoC 的註解生效
    • 靜態資源過濾: HTML、JS、CSS、圖片、視頻 等
    • MVC 的註解驅動
    • 配置視圖解析器

    具體配置信息以下:

    <?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.xp.controller"/>
        <!-- 讓 SpringMVC 處理靜態資源 -->
        <mvc:default-servlet-handler/>
        <!--
        支持mvc註解驅動
        在 Spring 中通常採用 @RequestMapping 註解來完成映射關係
        要想使 @RequestMapping 註解生效
        必須向上下文中註冊 DefaultAnnotationHandlerMapping 和一個 AnnotationMethodHandlerAdapter實例
        這兩個實例分別在類級別和方法級別處理
        而 annotation-driver 配置幫助咱們自動完成上述兩個實例的注入
        -->
        <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. 配置 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">
    
        <!-- 註冊 DispatcherServlet註解 -->
        <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:config/springmvc-servlet.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>
        
    </web-app>

    / 和 / 的區別:*

    < url-pattern > / </ url-pattern > 不會匹配到.jsp,只針對咱們編寫的請求;即.jsp不會進入 Spring 的 DispatcherServlet 類。

    < url-pattern > /* </ url-pattern > 會匹配*.jsp,會出現返回 JSP 視圖時再次進入 Spring 的 DispatcherServlet 類,致使找不到對應的 controller 因此報404錯。

    • 注意 web.xml 版本問題,要最新版
    • 註冊 DispatcherServlet
    • 關聯 SpringMVC 的配置文件
    • 啓動級別爲1
    • 映射路徑爲 / 【不要用/*,會404】
  5. 建立視圖層 hello.jsp

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

    編寫一個 Java 控制類:HelloController

    @Controller
    @RequestMapping("hello")
    public class HelloController {
        // 真實的訪問地址:項目名/hello/h1
        @RequestMapping("h1")
        public String hello(Model model){
            // 向模型中添加屬性msg與值,能夠在JSP頁面中取出並渲染
            model.addAttribute("msg","HelloSpringMVCAnnotation!");
            // WEB-INF/jsp/hello.jsp
            return "hello";
        }
    }
    • @Controller 是爲了讓 Spring IoC容器初始化時自動掃描到並做爲 Spring 中的一個組件

    • @RequestMapping 時爲了映射請求路徑,這裏時由於類與方法上都有映射,因此訪問的是項目名/hello/h1

    • 方法中聲明 Model 類型的參數是爲了把 Action 中的數據帶到視圖中

    • 方法返回的結果是視圖的名稱 hello,加上配置文件中的先後綴變成 WEB-INF/jsp/hello.jsp

  7. 啓動 Tomcat 測試

小結

實現步驟其實很是簡單:

  1. 新建一個 web 項目
  2. 導入相關 jar 包
  3. 編寫 web.xml,註冊 DispatcherServlet
  4. 編寫 SpringMVC 配置文件
  5. 建立對應的控制類 controller
  6. 最後完善前端視圖和 controller 之間的對應
  7. 測試運行調試

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

處理器映射器、處理器適配器、視圖解析器

一般,咱們只須要手動配置視圖解析器,而處理器映射器處理器適配器只須要開啓註解驅動便可,這樣省去了大段的 xml 配置

4. RESTful 和 Controller

4.1 控制器 Controlle

控制器 Controller

  • 控制器負責提供訪問應用程序的行爲,一般經過接口定義或者註解定義兩種實現方式。
  • 控制器負責解析用戶的請求並將其轉黃爲一個模型。
  • 在 SpringMVC 中一個控制器類能夠包含多個方法。
  • 在 SpringMVC 中,對於 Controller 的配置方式又不少種

Controller 有兩種實現方式

  • 實現 Controller 接口
  • 使用註解

兩種方式的對比:

  • 實現接口 Controller 定義控制器是較老的方法
  • 實現接口的缺點是:一個控制器中只有一個方法,若是要多個方法則須要定義多個 Controller;定義的方式比較麻煩
  • 使用註解可以減小配置,更簡單

將類看成組件交由 Spring 託管的註解

@Component	// 普通類註解
@Controller	// controller層註解
@Repository	// dao層註解
@Service	// service層註解

4.2 @RequestMapping

  • @RequestMapping 註解用於映射 url 到控制器類或一個特定的處理程序方法。可用於類或方法上。用於類上,表示類中的全部響應請求的方法都是以該地址做爲父路徑。
@Controller
@RequestMapping("hello")
public class HelloController {

    @RequestMapping("h1")
    public String hello(Model model){
        model.addAttribute("msg","HelloSpringMVCAnnotation!");
        return "hello";
    }

}

上面代碼hello方法的路徑是 項目名/hello/h1

4.3 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

在原來的配置基礎上,增長一個 Controller 類

使用 @PathVariable 註解,讓方法參數的值對應綁定到一個 URI 模板變量上

@Controller
public class HelloController {

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

瀏覽器 url 訪問及結果

image-20200513110631700

全部地址欄請求默認都是 HTTP GET 類型的。

方法級別的註釋變體有以下幾個

@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping

5. 數據處理及跳轉

5.1 結果跳轉方式

ModelAndView

設置 ModelAndView 對象,根據 view 的名稱,和視圖解析器跳到指定的頁面。

頁面:{視圖解析器前綴} + viewName +{視圖解析器後綴}

<!-- 視圖解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!-- 前綴 -->
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <!-- 後綴 -->
    <property name="suffix" value=".jsp"/>
</bean>

對應的 Controller 爲:

public class HelloController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        // 建立 ModelAndView 對象
        ModelAndView mv = new ModelAndView();
        // 封裝對象,放在 ModelAndView 中,Model
        mv.addObject("msg","HelloSpringMVC!");
        // 封裝要跳轉的視圖,放在 ModelAndView 中,至關於 /WEB-INF/jsp/hello.jsp
         mv.setViewName("hello");
        return mv;
    }
}

5.2 ServletAPI

經過設置 ServletAPI,不須要視圖解析器

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

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

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

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

}

5.3 經過 SpringMVC 來實現轉發和重定向

5.3.1 無需視圖解析器

測試前,須要將視圖解析器註釋掉

默認地址是轉發地址,加了前綴 foward:/ 也是轉發,加了 redirect:/ 前綴表明則是重定向。

@Controller
public class TestController {
    @RequestMapping("test1")
    public String test1(Model model){
        model.addAttribute("msg","test1");
        // 轉發
       return "/WEB-INF/jsp/test.jsp";
    }
    @RequestMapping("test2")
    public String test2(Model model){
        model.addAttribute("msg","test2");
        // 轉發
        return "forward:/WEB-INF/jsp/test.jsp";
    }
    @RequestMapping("test3")
    public String test3(){
        // 重定向
        return "redirect:/index.jsp";
    }
}

重定向時須要注意一個點。重定向是客戶端的,轉發是服務端內部的。重定向是讓客戶端去訪問重定向的地址。客戶端是無權訪問 WEB-INF 目錄下資源。

若須要重定向到 WEB-INF 下,能夠先定向到一個地址,而後由服務器內部去跳轉

@RequestMapping("test3")
public String test3(){
    // 重定向到轉發的url
    return "redirect:/toWebInf";
}

@RequestMapping("toWebInf")
public String toWebInf(){
    // 經過轉發,能夠訪問WEB-INF目錄下的資源
    return "/WEB-INF/jsp/test.jsp";
}

5.3.2 有視圖解析器:

@Controller
@RequestMapping("/t2")
public class TestController2 {

    @RequestMapping("/test1")
    public String test1(Model model){
        model.addAttribute("msg","test1");
        // 轉發
        return "test";
    }

    @RequestMapping("/test2")
    public String test2(Model model){
        model.addAttribute("msg","test2");
        // 轉發,使用 forward 必須使用全限定名
        return "forward:/WEB-INF/jsp/test.jsp";
    }

    @RequestMapping("/test3")
    public String test3(){
        // 重定向
        return "redirect:/t2/toWebInf";
    }

    @RequestMapping("/toWebInf")
    public String toWebInf(){
        // 經過轉發訪問 WEB-INF 目錄下的資源
        return "test";
    }

}

使用 forward:/ 進行轉發和使用 redirect:/ 重定向 時,後面必須是全限定名

5.4 數據顯示到前端

第一種:經過ModelAndView

和一開始的講原理時的代碼同樣

public class ControllerTest1 implements Controller {

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

第二種:經過ModelMap

ModelMap

@Controller
@RequestMapping("user")
public class UserController {
    // 經過 http://localhost:8080/user/test1?name=xp 傳遞給後端
    @RequestMapping("test1")
    public String test1(String name, ModelMap model){
        // 接收前端對象
        System.out.println("name->"+name);
        // 返回數據給前端
        model.addAttribute("msg",name);
        // 跳轉視圖
        return "test";
    }
}

第三種:經過Model

Model

@Controller
@RequestMapping("user")
public class UserController {
    // 經過 http://localhost:8080/user/test2?name=xp 傳遞給後端
    @RequestMapping("test2")
    public String test1(String name, Model model){
        // 接收前端對象
        System.out.println("name->"+name);
        // 返回數據給前端
        model.addAttribute("msg",name);
        // 跳轉視圖
        return "test";
    }
}

對比

就對於新手而言,簡單來講使用區別就是:

  • Model 只有寥寥幾個方法,只適用於存儲數據,簡化了新手對於 Model 對象的操做和理解
  • ModelMap 繼承了 LinkedMap ,除了實現了自身的一些方法,一樣的繼承 LinkedMap 的方法和特性
  • ModelAndView 能夠在儲存數據的同時,能夠進行設置返回的邏輯視圖,進行控制展現層的跳轉

固然,之後開發考慮的更多的是性能和優化,就不能單單僅限於此的瞭解

5.5 中文亂碼問題

測試環境

  1. 建立一個 encoding.jsp,用來提交表單

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>解決亂碼問題</title>
    </head>
    <body>
        <form action="${pageContext.request.contextPath}/encoding/test1" method="post">
            <input type="text" name="name"/>
            <input type="submit" value="提交"/>
        </form>
    </body>
    </html>
  2. 編寫控制器 EncodingController 來接收前端提交的表單

    @Controller
    @RequestMapping("encoding")
    public class EncodingController {
        @PostMapping("test1")
        public String test1(String name, Model model){
            // 查看獲取的前端提交的表單數據是否爲亂碼,方便定位問題
            System.out.println("name->"+name);
            // 獲取前端提交的表單數據
            model.addAttribute("msg",name);
            return "test";
        }
    }
  3. 提交表單,查看控制檯和瀏覽器頁面輸出

    image-20200513151536556

image-20200513151605405

​ 能夠看出,在前端頁面提交表單到後臺接收前端表單數據的過程當中,亂碼就已經產生了!

解決辦法

在 web.xml 中配置 SpringMVC 自帶的編碼過濾器,並重啓 Tomcat 服務器

<!-- 編碼過濾器:解決中文亂碼問題 -->
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

可是咱們發現,有些極端狀況下,這個過濾器對 GET 的支持很差

處理方法:

  1. 修改 Tomcat 配置文件,設置編碼

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

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

6. JSON

引入 Jackson 依賴

<!-- jackson -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.10.2</version>
</dependency>

6.1 什麼是JSON?

什麼是JSON?

  • JSON(JavaScript Object Notation),翻譯過來就是 JS 對象標記。是一種輕量級的數據交換格式,目前使用特別普遍。
  • 採用徹底獨立於編程語言的文本格式來存儲和表示數據。
  • 簡潔和清晰的層次結構使得 JSON 成爲理想的數據交換語言。
  • 易於人閱讀和編寫,同時也易於機器解析和生成,並有效地提高網絡傳輸效率。

在 JavaScript 語言中,一切都是對象。所以,任何 JavaScript 支持的類型均可以經過 JSON 來表示,例如字符串、數字、對象、數組等。

6.2 JSON的格式

JSON 的格式:

  • 對象表示爲鍵值對,數據由逗號分隔。
  • 花括號保存對象。
  • 方括號保存數組。

JSON 鍵值對 是用來保存 JavaScript 對象的一種方式,和 JavaScript 對象的寫法也大同小異,鍵值對組合中的鍵名卸載前面,並用雙引號 "" 包裹,使用冒號 : 分隔,而後緊接着值:

{"name": "zhangsan"}
{"age": "18"}
{"sex": "男"}

不少人搞不清楚 JSON 和 JavaScript 對象的關係,甚至誰是誰都不清楚。其實,能夠這麼理解:

JSON 是 JavaScript 對象的字符串表示法,它使用文本表示一個 JS 對象的信息,本質是一個字符串。

var obj = {name:"zhangsan",age:18,sex:"男"};
var json = ‘{"name","zhangsan","age":18,"sex":"男"}’;

6.3 JSON 和 JavaScript 對象互轉

要實現從 JSON 字符串轉換爲 JavaScript 對象,使用 JSON.parse() 方法:

var obj = JSON.parse(‘{"name","zhangsan","age":18,"sex":"男"}’);

要實現從 JavaScript 對象轉換爲 JSON 字符串,使用 JSON.stringify() 方法:

var json = JSON.stringify({name:"zhangsan",age:18,sex:"男"});

測試環境搭建

  1. 新建一個 module: SpringMVC-05-JSON,並添加web支持

  2. 在 web 目錄下新建一個 json1.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:18,
           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中使用瀏覽器打開,查看控制檯輸出

    image-20200513205935055

6.4 Controller返回JSON數據

Jackson: 目前比較好的 JSON 解析工具

固然工具不止這一種,好比還有阿里的 fastjson ,谷歌的 gson 等等

咱們這裏使用 Jackson,具體操做以下:

  1. 導入 Jackson 的依賴

    <!-- jackson -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.10.2</version>
    </dependency>
  2. 配置 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">
    
        <!-- 註冊DispatcherServlet -->
        <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:config/springmvc-servlet.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>
            <init-param>
                <param-name>forceEncoding</param-name>
                <param-value>true</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>encoding</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    </web-app>
  3. 建立 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">
    
        <!-- 開啓註解支持 -->
        <context:component-scan base-package="com.xp.controller"/>
        <!-- 靜態資源過濾 -->
        <mvc:default-servlet-handler/>
        <!-- 開啓mvc註解驅動支持 -->
        <mvc:annotation-driven/>
    
        <!-- 視圖解析器 -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <!-- 前綴 -->
            <property name="prefix" value="/WEB-INF/jsp"/>
            <!-- 後最 -->
            <property name="suffix" value=".jsp"/>
        </bean>
    
    </beans>
  4. 編寫實體類 User

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class User {
        public String name;
        public String age;
        public String sex;
    }
  5. 編寫控制器 JsonController

    @Controller
    public class JsonController {
        @RequestMapping(path = "/json1", produces = "application/json;charset=utf-8")
        @ResponseBody // 添加ResponseBody註釋,它就不會走視圖解析器,會直接返回一個字符串
        public String json1() throws JsonProcessingException {
            ObjectMapper objectMapper = new ObjectMapper();
            User user = new User("zhangsan", "18", "男");
            return objectMapper.writeValueAsString(user);
        }
    }

    @ResponseBody :該註解能夠添加在方法或類上,添加該註解後,該類或該方法就不會走視圖解析器,會直接返回一個字符串。

    在先後端分離開發中,通常都使用 @ResponseBody 註解,十分方便。

    若是在 @RequestMapping 註解中不配置 produces 屬性的話,就會產生中文亂碼。

    image-20200513211558172

    固然,還有一種解決亂碼一勞永逸的方法

    在 springmvc-servlet.xml 配置文件中增長以下配置

    <!-- 開啓mvc註解驅動支持 -->
    <mvc:annotation-driven>
        <!-- 解決jackson亂碼問題 -->
        <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>

使用這種方法解決亂碼問題後,就不須要在 @RequestMapping 註解中配置 produces 屬性

輸出集合

@RequestMapping("/json3")
public String json3() throws JsonProcessingException {
    ObjectMapper objectMapper = new ObjectMapper();
    User user1 = new User("張三1", "18", "男");
    User user2 = new User("張三2", "18", "男");
    User user3 = new User("張三3", "18", "男");
    User user4 = new User("張三4", "18", "男");
    List<User> users = new ArrayList<>();
    users.add(user1);
    users.add(user2);
    users.add(user3);
    users.add(user4);
    String str = objectMapper.writeValueAsString(users);
    return str;
}

輸出時間對象

@RequestMapping("/json4")
public String json4() throws JsonProcessingException {
    ObjectMapper objectMapper = new ObjectMapper();
    Date date = new Date();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String format = sdf.format(date);
    return objectMapper.writeValueAsString(format);
}

6.5 fastjson

fastjson.jar 是阿里開發的一款專門用於 Java 開發的包。能夠方便的實現 json 對象與 JavaBean 對象的轉換,實現 JavaBean 對象與 json 字符串的轉換,實現 json 對象與 json 字符串的轉換。

導入 fastjson 依賴

<dependencies>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.68</version>
    </dependency>
</dependencies>

fastjson 三個主要的類:

JSONObject 表明 json 對象

  • JSONObject 實現了 Map 接口
  • JSONObject 對應 json 對象,經過各類形式的 get() 方法能夠獲取 json 對象中的數據,也能夠利用諸如 size(),isEmpty() 等方法獲取鍵值對的個數和判斷是否未空。其本質是經過實現 Map 接口並調用接口中的方法完成的。

JSONArray 表明 json 對象數組

  • 內部是有 List 接口中的方法來完成操做

JSON 表明 JSONObject 和 JSONArray 的轉化

  • JSON 類源碼分析與使用
  • 仔細觀察這些方法,主要是實現 json 對象,json 對象數組,javabean 對象,json 字符串之間的相互轉化

代碼測試

public class FastJsonDemo {
   public static void main(String[] args) {
       //建立一個對象
       User user1 = new User("張三1號", 3, "男");
       User user2 = new User("張三2號", 3, "男");
       User user3 = new User("張三3號", 3, "男");
       User user4 = new User("張三4號", 3, "男");
       List<User> list = new ArrayList<User>();
       list.add(user1);
       list.add(user2);
       list.add(user3);
       list.add(user4);

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

7. AJAX

7.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 用戶界面。

使用AJAX能夠作:

  • 註冊時,輸入用戶名自動檢測用戶是否已經存在。
  • 登錄時,提示用戶名密碼錯誤
  • 刪除數據行時,將行ID發送到後臺,後臺在數據庫中刪除,數據庫刪除成功後,在頁面 DOM 中將數據行也刪除
  • 等等。。

7.2 iframe標籤

iframe,能夠算是僞造的 AJAX,也能夠實現頁面局部刷新。雖然,iframe 標籤的使用比 AJAX 要簡單得多,但其安全性以及用戶體驗性並不如人意。

下面,咱們來使用 iframe 標籤實現頁面的局部刷新

  1. 建立一個新的工程項目:SpringMVC-06-AJAX,添加 web 框架

  2. 在 index.jsp 中編寫 iframe 標籤

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
      <head>
        <title>iframeTest</title>
        <script>
          // iframe 加載url
          function loadUrl(url) {
            var iframe = document.getElementById("iframe");
            iframe.src = url;
          }
        </script>
      </head>
      <body>
      <%-- 點擊按鈕後,iframe 加載頁面 --%>
      <div>
        <button id="iframeBtn" onclick="loadUrl('iframe.jsp')">點我加載 iframe.jsp</button>
      </div>
      <iframe src="" id="iframe"></iframe>
      </body>
    </html>
  3. 在 web 目錄下建立 iframe.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <h1>這是 iframe.jsp</h1>
    </body>
    </html>
  4. 測試是否頁面局部加載成功

    image-20200515220355919

    若是咱們讓 loadUrl() 的參數是百度網址時,也能夠跳轉到百度的頁面

    <div>
      <button id="iframeBtn" onclick="loadUrl('http://www.baidu.com')">點我加載 iframe.jsp</button>
    </div>

    而且咱們按 f12 打開開發者工具的時候,會發現頁面中,只有 iframe 內部的 #document 在改變,而整個頁面並無刷新。因此 iframe 標籤是實現頁面局部刷新的,能夠當作是一個僞 AJAX

    image-20200515221029851

7.2 原生AJAX

XMLHttpRequest 是 AJAX 的基礎。

全部現代瀏覽器均支持 XMLHttpRequest 對象(IE5 和 IE6 使用 ActiveXObject)

XMLHttpRequest 用於在後臺與服務器交換數據。這意味着能夠不從新加載整個網頁的狀況下,對網頁的某部分進行更新

7.3 jQuery AJAX

jQuery AJAX 簡介

  • jQuery 是一個優秀的js框架,對 js 原生的 Ajax 進行了封裝。
  • 在封裝後的 AJAX 的操做更加簡潔,功能更增強大
  • 使用 jQuery AJAX ,避免重複造輪子

Ajax 的核心是 XMLHttpRequest 對象(XHR),XHR 爲向服務器發送請求和解析服務器響應提供了接口,可以以異步方式從服務器獲取新數據。

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

經過 jQuery AJAX 方法,咱們可以使用 HTTP GET 和 HTTP POST 從遠程服務器上請求文本、HTML、XML 或 JSON。同時咱們可以把這些外部數據直接載入網頁的被選元素中。

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 將自動替換 ? 爲正確的函數名,以執行回調函數

SpringMVC使用AJAX

  1. 配置 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">
    
        <!-- 掃描包,開啓註解支持 -->
        <context:component-scan base-package="com.xp.controller"/>
        <!-- 靜態資源過濾 -->
        <mvc:default-servlet-handler/>
        <!-- 開啓註解驅動支持 -->
        <mvc:annotation-driven/>
    
        <!-- 視圖解析器 -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <!-- 前綴 -->
            <property name="prefix" value="/WEB=INF/html/"/>
            <!-- 後綴 -->
            <property name="suffix" value=".html"/>
        </bean>
    
    </beans>
  2. 配置 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">
    
        <!-- 註冊 DispatcherServlet -->
        <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:springmvc-servlet.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>encodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>utf-8</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>encodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
    </web-app>
  3. 編寫控制器 AJAXController,假設數據庫中帳號和密碼分別是 admin 和 12345

    package com.xp.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @Controller
    public class AJAXController {
    	// produces 解決亂碼問題
        @RequestMapping(path = "/ajax/userName" ,produces="text/html;charset=UTF-8;")
        @ResponseBody
        public String ajaxUserName(String userName){
            return ("admin".equals(userName))?"正確":"錯誤";
        }
    
        @RequestMapping(path = "/ajax/password" ,produces="text/html;charset=UTF-8;")
        @ResponseBody
        public String ajaxPassword(String password){
            return ("12345".equals(password))?"正確":"錯誤";
        }
    
    }
  4. 編寫前端頁面和 AJAX 請求

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>AJAX</title>
        <!-- 引入 jQuery -->
        <script src="../js/jquery-3.4.1.min.js"></script>
        <script type="text/javascript">
            function userNameBlur() {
                $.post({
                    url: "/ajax/userName",
                    data: "userName="+$("#userName").val(),
                    dataType: "text",
                    success: function (data) {
                        var userNameAjax = $("#userNameAjax");
                        if ("正確" === data){
                            userNameAjax.css("color","green");
                        }else {
                            userNameAjax.css("color","red");
                        }
                        userNameAjax.html(data);
                    }
                })
            }
            function passwordBlur() {
                $.post({
                    url: "/ajax/password",
                    data: "password="+$("#password").val(),
                    dataType: "text",
                    success: function (data) {
                        var passwordAjax = $("#passwordAjax");
                        if ("正確" === data){
                            passwordAjax.css("color","green");
                        }else {
                            passwordAjax.css("color","red");
                        }
                        passwordAjax.html(data);
                    }
                });
            }
        </script>
    </head>
    <body>
    <div id="test">
        <label>用戶名:<input type="text" id="userName" onblur="userNameBlur()"/></label>
        <span id="userNameAjax"></span>
    </div>
    <div>
        <label>密碼:<input type="text" id="password" onblur="passwordBlur()"/></label>
        <span id="passwordAjax"></span>
    </div>
    </body>
    </html>
  5. 啓動 Tomcat 服務器,測試

    測試時,能夠發現,當咱們鼠標點擊輸入框後再點擊其它地方失去焦點時,右邊的span標籤內的內容會發生變化。這樣,咱們就學會了 SpringMVC 中使用 AJAX。

8. Thymeleaf模板引擎

8.1 簡介

Thymeleaf 是一款用於渲染 XML/XHTML/HTML5 內容的模板引擎,相似 JSP, Velocity, FreeMaker 等。它能夠輕易與 Spring MVC 等 Web 框架進行集成做爲 Web 應用的模板引擎。是 SpringBoot 官方使用的模板引擎。

官網:https://www.thymeleaf.org/

8.2 特色

  • 動靜結合:Thymeleaf 在有網絡和無網絡的環境下皆可運行。
  • 開箱即用:它提供標準和 Spring 標準兩種方言,能夠直接套用模板實現 JSTL、OGNL 表達式效果。
  • 多方言支持:Thymeleaf 提供 Spring 標準方言和一個與 SpringMVC 完美集成的可選模板,能夠快速地實現表單綁定、屬性編輯器、國際化等功能。
  • 與 SpringBoot 完美整合,SpringBoot 提供了 Thymeleaf 的默認配置,而且爲 Thymeleaf 設置了視圖解析器,能夠像之前操做 jsp 同樣來操做 Thymeleaf。代碼幾乎沒有任何區別,就是在模板語法上有區別。

8.3 簡單使用

  1. 新建一個module:Springmvc-07-Thymeleaf,添加 web 支持

  2. 配置 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">
    
        <!-- 註冊 DispatcherServlet -->
        <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:config/springmvc-servlet.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>
  3. 導入 Themeleaf 依賴

    <dependencies>
        <!-- Thymeleaf 支持Spring方言 -->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>
        <!-- Thymeleaf -->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.11.RELEASE</version>
        </dependency>
    </dependencies>
  4. 配置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">
    
        <context:component-scan base-package="com.xp.controller"/>
        <mvc:default-servlet-handler/>
        <mvc:annotation-driven/>
    
        <!-- 模板解析器 -->
        <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver" id="templateResolver">
            <property name="prefix" value="/WEB-INF/html"/>
            <property name="suffix" value=".html"/>
            <property name="templateMode" value="HTML"/>
            <property name="characterEncoding" value="utf-8"/>
            <property name="cacheable" value="false"/>
        </bean>
    
        <!-- 模板引擎 -->
        <bean class="org.thymeleaf.spring5.SpringTemplateEngine" id="templateEngine">
            <property name="templateResolver" ref="templateResolver"/>
            <property name="enableSpringELCompiler" value="true"/>
        </bean>
    
        <!-- 視圖解析器 -->
        <bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
            <property name="templateEngine" ref="templateEngine"/>
            <property name="characterEncoding" value="utf-8"/>
        </bean>
    
    </beans>
  5. 編寫控制器

    @Controller
    public class ThymeleafController {
    
        @RequestMapping("/thymeleaf")
        public String thymeleaf(Model model){
            model.addAttribute("thymeleaf","Hello,Thymeleaf!");
            return "thymeleaf";
        }
    
    }
  6. 編寫視圖層

    注:要使用 Thymeleaf 模板引擎的頁面,必需要在 html 標籤上加上 xmlns:th="http://www.thymeleaf.org"

    index.xml

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Thymeleaf</title>
    </head>
    <body>
        <h1><a href="/thymeleaf">Hello,Thymeleaf!</a></h1>
    </body>
    </html>

    thymeleaf.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <!--/*@thymesVar id="thymeleaf" type="java.lang.String"*/-->
        <div th:text="${thymeleaf}"></div>
    </body>
    </html>
  7. 測試

咱們能夠發現 SpringMVC 整合 Thymeleaf 模板引擎,只是導入依賴後,在 springmvc-servlet.xml 配置文件中加入了模板解析器、模板引擎和視圖解析器三個 bean,並不須要修改 web.xml 中的配置。咱們就能夠在 html 中像 jsp 同樣使用 el 表達式了。下面,咱們來看下經常使用的 Thymeleaf 語法以及標籤。

8.4 經常使用語法

Thymeleaf 的主要做用是把 model 中的數據渲染到html 中,所以其語法主要是如何解析 model 中的數據。從如下方面來學習:

  • 變量、方法、條件判斷、循環、運算【邏輯運算、布爾運算、比較運算、條件運算】
  • 其它
  1. Thymeleaf 經過 ${...} 來獲取 model 中的變量,語法和 el 表達式差很少,但它是 ognl 表達式

    <!--/*@thymesVar id="thymeleaf" type="java.lang.String"*/-->
    <div th:text="${thymeleaf}"></div>
  2. Themeleaf 經過 th:object 自定義變量,能夠經過 *{...} 取出對應的屬性

    <!--/*@thymesVar id="user" type="com.xp.entity.User"*/-->
    <div th:object="${user}">
        <h2 th:text="*{name}"></h2>
        <h2 th:text="*{age}"></h2>
        <!--/*@thymesVar id="friend" type="com.xp.entity.Friend"*/-->
        <h2 th:text="*{friend.name}"></h2>
    </div>
  3. ognl 表達式自己就支持方法調用,但須要注意的是必須使用註釋指明該變量是哪一個類的

    <!--/*@thymesVar id="user" type="com.xp.entity.User"*/-->
    <!--/*@thymesVar id="name" type="java.lang.String"*/-->
    <!--/*@thymesVar id="age" type="java.lang.Integer"*/-->
    <div th:object="${user}">
        <h2 th:text="*{name.hashCode()}"></h2>
        <h2 th:text="*{age.hashCode()}"></h2>
        <!--/*@thymesVar id="friend" type="com.xp.entity.Friend"*/-->
        <h2 th:text="*{friend.name.hashCode()}"></h2>
    </div>

    Thymeleaf 中提供了一些內置對象,而且這些對象中提供了一些方法,方便咱們調用、獲取這些對象,須要使用 #對象名 來調用

    • 一些環境相關的對象

      對象 做用
      #ctx 獲取 Thymeleaf 本身的 Context 對象
      #request 若是是 web 程序,能夠獲取 HttpServletRequest 對象
      #respone 若是是 web 程序,能夠獲取 HttpServletResponse 對象
      #session 若是是 web 程序,能夠獲取 HttpSession 對象
      #servletContext 若是是web 程序,能夠獲取 HttpServletContext 對象
    • Thymeleaf 提供的全局對象

      對象 做用
      #datas 處理 java.util.date 的工具對象
      #calendars 處理 java.util.calendar 的工具對象
      #numbers 用來對數字格式的方法
      #strings 用來處理字符串的方法
      #bools 用來判斷布爾值的方法
      #arrays 用來護理數組的方法
      #lists 用來處理 List 集合的方法
      #sets 用來處理 Set 集合的方法
      #maps 用來處理 Map 集合的方法

      例如:

      <div th:text="${#dates.format(data,'yyyy-MM-dd HH:mm:ss')}"></div>
      <div th:Object="${#session.getAttribute('user')}">
          <h1 th:text="*{name}"></h1>
          <h1 th:text="*{age}"></h1>
          <h1 th:text="*{friend.name}"></h1>
      </div>
  4. 字面值

    • 字符串字面值:使用一對 '' (單引號)引用的內容就是字符串的字面值了

      <div th:text="'字符串字面值'"></div>
    • 數字字面值:不須要任何特殊語法,寫的是是什麼就是什麼,能夠進行算術運算

      <div th:text="2020"></div>
      <div th:text="2018+2"></div>
    • 布爾字面值:只有 true 或 false

      <div th:if="true">布爾值:true</div>
  5. 字符串拼接

    • 咱們常用得普通字符串拼接方法

      <div th:text="'歡迎 '+${user.name}+‘ !’"></div>
    • Thymeleaf 使用一對 | 拼接

      <div th:text="|歡迎 +${user.name} !|"></div>
  6. 運算

    • 算術運算

      支持的運算符: + - * / %

      <div th:text="${user.age}%2"></div>
    • 比較運算運算

      支持的比較運算: >,<,>=,<=,可是 >,< 不能直接使用,由於 html 會解析爲標籤,要使用別名

      注意 == 和 != 不只能夠比較數值,相似於 equals 的功能

      可使用的別名:gt(>), lt(<), ge(>=) , le(<=), not(!), eq(==), neq/ne(!=)

    • 條件運算

      • 三元運算

        <div th:text="${user.isAdmin}?'管理員':'普通會員'"></div>
      • 默認值

        有的時候,咱們取一個值可能爲空,這個時候須要作非空判斷,可使用表達式 ?: 默認值簡寫

        <span th:text="${user.name} ?: '二狗'"></span>
  7. Thymeleaf 經過 th:each 實現循環

    <div th:each="list:${lists}">
        <h1 th:text="${list}"></h1>
    </div>

    遍歷的結合能夠是如下類型

    • Iterable,實現了Iterable接口的類
    • Enumeration,枚舉
    • Interator,迭代器
    • Map,遍歷獲得的是Map.Entry
    • Array,數組及其它一切符合數組結果的對象
  8. Thymeleaf 使用 th:if 或者 if:unless 來進行邏輯判斷

    <div th:if="${user.age} >= 18">
        <h1>成年人</h1>
    </div>

    若是表達式的值爲 true,則標籤會渲染到頁面,不然不進行渲染。

    如下狀況會被認爲 true

    • 表達式值爲 true
    • 表達式值爲非0數值
    • 表達式值爲非0字符
    • 表達式值爲字符串,但不是「false」、「no」,「off」
    • 表達式不是布爾、字符串、數字、字符中的任何一種

    其它狀況包括 null 都被認定爲 false

  9. Thymeleaf 使用 th:switchth:case 來進行分支控制

    <div th:switch="${user.role}">
      <p th:case="'admin'">用戶是管理員</p>
      <p th:case="'manager'">用戶是經理</p>
      <p th:case="*">用戶是別的玩意</p>
    </div>

    須要注意的是,一旦有一個 th:case 成立,其它的則再也不判斷。與 java 中的 switch 是同樣的

    另外 th:case="*" 表示默認,放在最後

  10. Thymeleaf 使用 th:inline="javascript" 來聲明該 script 標籤的腳本是須要特殊處理的 js 腳本

    <script th:inline="javascript">
        var user = /*[[${user}]]*/ {};
        var age = /*[[${user.age}]]*/ 20;
        console.log(user);
        console.log(age)
    </script>
    var user = /*[[Thymeleaf表達式]]*/

    由於 Thymeleaf 被註釋起來,所以即使是靜態環境下,js 代碼也不會報錯,而是採用表達式後面跟着的默認值。且 User 對象會直接處理爲 json 格式

9. 攔截器

9.1概述

SpringMVC 的處理器攔截器相似於 Servlet 開發中的過濾器 Filter,用於對處理器進行預處理和後處理。開發者能夠本身定義一些攔截器來實現待定的功能。

過濾器與攔截器的區別:攔截器時 AOP 思想的具體應用。

過濾器

  • Servlet 規範中的一部分,任何 JavaWeb 工程均可以使用
  • 再 url-pattern 中配置了 /* 以後,能夠對全部要訪問的資源進行攔截

攔截器

  • 攔截器是 SpringMVC 框架本身的,只有使用了 SpringMVC 框架的工程才能使用
  • 攔截器只會攔截訪問的控制器方法,若是訪問得事 jsp/html/css/image/js 是不會進行攔截的

9.2 自定義攔截器

那如何實現攔截器呢?

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

  1. 新建一個 Moudule:Spring-08-Interceptor ,添加 web 支持

  2. 配置 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">
    
        <context:component-scan base-package="com.xp.controller"/>
        <mvc:default-servlet-handler/>
        <mvc:annotation-driven/>
    
        <!-- 攔截器 -->
        <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <bean class="com.xp.config.MyInterceptor"/>
            </mvc:interceptor>
        </mvc:interceptors>
        
        <!-- 模板解析器 -->
        <bean id="templateResolver" class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
            <property name="prefix" value="/WEB-INF/html/"/>
            <property name="suffix" value=".html"/>
            <property name="cacheable" value="false"/>
            <property name="characterEncoding" value="utf-8"/>
            <property name="templateMode" value="HTML"/>
        </bean>
    
        <!-- 模板引擎 -->
        <bean class="org.thymeleaf.spring5.SpringTemplateEngine" id="templateEngine">
            <property name="templateResolver" ref="templateResolver"/>
            <property name="enableSpringELCompiler" value="true"/>
        </bean>
    
        <!-- 視圖解析器 -->
        <bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
            <property name="templateEngine" ref="templateEngine"/>
            <property name="characterEncoding" value="utf-8"/>
        </bean>
    
    </beans>
  3. 配置 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">
    
        <!-- 註冊DispatcherServlet -->
        <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:config/springmvc-servlet.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>
  4. 編寫實體類 User

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private String account;
        private String password;
    }
  5. 建立控制器 InterceptorController

    @Controller
    @RequestMapping("/user")
    public class InperceptorController {
    
        @RequestMapping("/toMain")
        public String toMain(){
            return "main";
        }
    
        @RequestMapping("/toLogin")
        public String toLogin(){
            return "login";
        }
    
        @RequestMapping("/login")
        public String login(User user, HttpSession session){
            // 模擬從數據庫中查詢數據後判斷帳號密碼是否正確,正確則設置session,不然返回登陸頁面
            if ("admin".equals(user.getAccount()) && "12345".equals(user.getPassword())){
                session.setAttribute("user",user);
                return "main";
            }else {
                return toLogin();
            }
        }
    
        @RequestMapping("/logout")
        public String logout(HttpSession session){
            session.removeAttribute("user");
            return toLogin();
        }
    
    }
  6. 編寫視圖層

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h2><a href="/user/toMain">首頁</a></h2>
    <h2><a href="/user/toLogin">登陸</a></h2>
    </body>
    </html>

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登陸</title>
    </head>
    <body>
    <form action="/user/login">
        <label>用戶名:<input type="text" name="account"/></label>
        <label>密碼:<input type="text" name="password"/></label>
        <input type="submit" value="登陸"/>
    </form>
    </body>
    </html>

    main.html

    <!DOCTYPE html>
    <html lang="en"  xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>首頁</h1>
    <!-- 有session則顯示該div -->
    <div th:object="${#session.getAttribute('user')}"  th:if="Object">
        <span th:text="*{account}"></span>
        <a href="/user/logout">退出</a>
    </div>
    </body>
    </html>
  7. 建立攔截器 MyInterceptor ,實現 HandlerInterceptor 接口,並重寫 preHandle() 方法

    public class MyInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            String url = request.getRequestURI();
            System.out.println(url);
            // 導航頁放行
            if ("/".equals(url)){
                return true;
            }
            // 導航頁放行
            if (url.contains("index")){
                return true;
            }
            // 登陸請求放行
            if (url.contains("login")){
                return true;
            }
            // 跳轉登陸頁面請求放行
            if (url.contains("toLogin")){
                return true;
            }
            // 登陸後有session的放行
            if (request.getSession().getAttribute("user") != null){
                return true;
            }
            // 攔截後跳轉到登陸頁面
            response.sendRedirect("/user/toLogin");
            // 攔截
            return false;
        }
    }
  8. 啓動 Tomcat 測試

    測試沒登陸前能不能進入首頁、測試登陸後從導航頁是否能進入首頁、測試登陸後退出後可否再進入首頁。

    測試成功則表明攔截器配置成功

10.文件的上傳下載

10.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 的組件。

10.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
    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";
      }
    }
  5. 測試上傳文件,OK!

採用file.Transto 來保存上傳的文件

  1. 編寫Controller

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

10.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";

   //一、設置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);
   //二、 讀取文件--輸入流
   InputStream input=new FileInputStream(file);
   //三、 寫出文件--輸出流
   OutputStream out = response.getOutputStream();

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

前端

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

測試,文件下載OK

11. SSM框架整合

環境配置

  1. 建立數據庫並建立對應的表,並插入數據

    # 建立數據庫 ssmproject
    CREATE DATABASE IF NOT EXISTS ssmproject;
    
    # 建立表
    DROP TABLE IF EXISTS book;
    CREATE TABLE IF NOT EXISTS book(
    	book_id INT(10) PRIMARY KEY	auto_increment COMMENT '書id',
    	book_name VARCHAR(100) NOT NULL COMMENT '書名',
    	book_counts INT(11) NOT NULL COMMENT '數量',
    	detail VARCHAR(200) COMMENT '描述'
    );
    
    # 插入數據
    INSERT INTO book (book_name,book_counts,detail) 
    VALUES
    ('Java',1,'從入門到放棄'),
    ('MySQL',10,'從刪庫到排路'),
    ('Linux',5,'從入門到進牢');
  2. 在 pom.xml 中導入依賴並配置靜態資源過濾

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.xp</groupId>
        <artifactId>SSMProject</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <!-- 依賴 -->
        <dependencies>
            <!-- junit 測試 -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
            <!-- SpringMVC -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.3.RELEASE</version>
            </dependency>
            <!-- 織入包 -->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.5</version>
            </dependency>
            <!-- servlet支持 -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>2.5</version>
            </dependency>
            <!-- jackson 解析json -->
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>2.10.2</version>
            </dependency>
            <!-- spring-jdbc JDBC驅動支持 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.2.3.RELEASE</version>
            </dependency>
            <!-- mysql驅動 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.46</version>
            </dependency>
            <!-- mybatis -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.2</version>
            </dependency>
            <!-- c3p0 數據庫鏈接池 -->
            <dependency>
                <groupId>com.mchange</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.5.5</version>
            </dependency>
            <!-- mybatis-Spring -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>2.0.3</version>
            </dependency>
            <!-- lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.10</version>
            </dependency>
            <!-- thymeleaf -->
            <dependency>
                <groupId>org.thymeleaf</groupId>
                <artifactId>thymeleaf</artifactId>
                <version>LATEST</version>
            </dependency>
            <!-- Spring 整合 thymeleaf -->
            <dependency>
                <groupId>org.thymeleaf</groupId>
                <artifactId>thymeleaf-spring5</artifactId>
                <version>LATEST</version>
            </dependency>
            <!-- log4j 日誌 -->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>2.12.1</version>
            </dependency>
        </dependencies>
    
        <!-- 靜態資源過濾問題 -->
        <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>
    
    </project>
  3. 添加 web 支持,並把包目錄結構先創建起來

    image-20200514173241419

  4. 編寫實體類 Book

    /**
     * 書 實體類
     * @author xp
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Book {
        /**
         * 書id
         */
        private Integer bookId;
        /**
         * 書名
         */
        private String bookName;
        /**
         * 書數量
         */
        private Integer bookCounts;
        /**
         * 描述
         */
        private String detail;
    }
  5. 編寫 mapper 接口

    /**
     * BookMapper
     *
     * @author xp
     */
    public interface BookMapper {
        /**
         * 增長一本書
         *
         * @param book 待增長的書籍信息
         * @return 影響行數
         */
        int addBook(Book book);
    
        /**
         * 根據id刪除一本數
         *
         * @param id 被刪除的書的id
         * @return 影響行數
         */
        int deleteBookById(@Param("bookId") int id);
    
        /**
         * 修改一本數
         *
         * @param book 修改後的書籍信息
         * @return 影響行數
         */
        int updateBook(Book book);
    
        /**
         * 根據id查詢書
         *
         * @param id 書的id
         * @return 查詢後的結果
         */
        Book queryBookById(@Param("bookId") int id);
    
        /**
         * 查詢全部書
         *
         * @return 存儲書籍信息的集合
         */
        List<Book> queryAllBook();
        
        /**
         * 根據書籍名字查詢書籍
         *
         * @param name 書籍名字
         * @return 存儲書籍信息的集合
         */
        List<Book> queryBookByName(@Param("bookName") String name);
    }
  6. 編寫 Service 接口和其實現類

    Service 接口

    /**
     * 書本業務層
     *
     * @author xp
     */
    public interface BookService {
        /**
         * 增長一本書
         *
         * @param book 待增長的書籍信息
         * @return 影響行數
         */
        int addBook(Book book);
    
        /**
         * 根據id刪除一本數
         *
         * @param id 被刪除的書的id
         * @return 影響行數
         */
        int deleteBookById(int id);
    
        /**
         * 修改一本數
         *
         * @param book 修改後的書籍信息
         * @return 影響行數
         */
        int updateBook(Book book);
    
        /**
         * 根據id查詢書
         *
         * @param id 書的id
         * @return 查詢後的結果
         */
        Book queryBookById(int id);
    
        /**
         * 查詢全部書
         *
         * @return 存儲書籍信息的集合
         */
        List<Book> queryAllBook();
        
        /**
         * 根據書籍名字查詢書籍
         *
         * @param name 書籍名字
         * @return 存儲書籍信息的集合
         */
        List<Book> queryBookByName(String name);
    }

    Service 實現類

    /**
     * Service 實現類
     * @author xp
     */
    public class BookServiceImpl implements BookService {
    
        private BookMapper bookMapper;
    
        public void setBookMapper(BookMapper bookMapper) {
            this.bookMapper = bookMapper;
        }
    
        @Override
        public int addBook(Book book) {
            return bookMapper.addBook(book);
        }
    
        @Override
        public int deleteBookById(int id) {
            return bookMapper.deleteBookById(id);
        }
    
        @Override
        public int updateBook(Book book) {
            return bookMapper.updateBook(book);
        }
    
        @Override
        public Book queryBookById(int id) {
            return bookMapper.queryBookById(id);
        }
    
        @Override
        public List<Book> queryAllBook() {
            return bookMapper.queryAllBook();
        }
        
        @Override
        public List<Book> queryBookByName(String name) {
            return bookMapper.queryBookByName(name);
        }
    }
  7. 建立數據庫文件 db.properties

    jdbc.drive=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/ssmproject?useTimezone=true&serverTimezone=GMT%2b8&useUnicode=true&characterEncoding=UTF-8&useSSL=false
    jdbc.username=root
    jdbc.password=root
  8. 編寫 MyBatis 核心配置文件 mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <settings>
            <!-- 開啓駝峯映射 -->
            <setting name="mapUnderscoreToCamelCase" value="true"/>
            <!-- 開啓log4j日誌 -->
            <setting name="logImpl" value="LOG4J"/>
        </settings>
        <!-- 別名 -->
        <typeAliases>
            <package name="com.xp"/>
        </typeAliases>
        <!-- 註冊 mapper -->
        <mappers>
            <mapper resource="mapper/bookMapper.xml"/>
        </mappers>
    </configuration>
  9. 配置 log4j.properties

    #將等級爲DEBUG的日誌信息輸出到console和file這兩個目的地,console和file的定義在下面的代碼
    log4j.rootLogger=DEBUG,console,file
    
    #控制檯輸出的相關設置
    log4j.appender.console = org.apache.log4j.ConsoleAppender
    log4j.appender.console.Target = System.out
    log4j.appender.console.Threshold=DEBUG
    log4j.appender.console.layout = org.apache.log4j.PatternLayout
    log4j.appender.console.layout.ConversionPattern=【%c】-%m%n
    
    #文件輸出的相關設置
    log4j.appender.file = org.apache.log4j.RollingFileAppender
    log4j.appender.file.File=./log/xp.log
    log4j.appender.file.MaxFileSize=10mb
    log4j.appender.file.Threshold=DEBUG
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=【%p】【%d{yy-MM-dd}】【%c】%m%n
    
    #日誌輸出級別
    log4j.logger.org.mybatis=DEBUG
    log4j.logger.java.sql=DEBUG
    log4j.logger.java.sql.Statement=DEBUG
    log4j.logger.java.sql.ResultSet=DEBUG
    log4j.logger.java.sql.PreparedStatement=DEBUG
  10. 建立 spring-dao.xml,配置dao層,並交由 Spring 託管

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 關聯數據庫文件 -->
    <context:property-placeholder location="classpath:properties/db.properties"/>
    <!-- 鏈接池
        dbcp:半自動化操做,不能自動鏈接
        c3p0:自動化操做(自動化地加載配置文件,而且能夠自動設置到對象中)
        druid、hikari
     -->
    <bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
        <property name="driverClass" value="${jdbc.drive}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- SqlSessionFactory -->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactory">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:config/mybatis-config.xml"/>
    </bean>


    <!-- 配置dao接口掃描包,動態實現了Dao接口能夠注入Spring容器中 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 要掃描的包 -->
        <property name="basePackage" value="com.xp.mapper"/>
        <!-- 注入SqlSessionFactory -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

</beans>
  1. 在 mapper 包下建立 bookMapper.xml,編寫映射器映射的sql語句

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.xp.mapper.BookMapper">
        <insert id="addBook" parameterType="book">
            insert into book (book_name, book_counts, detail)
            values (#{bookName},#{bookCounts},#{detail});
        </insert>
        <delete id="deleteBookById" parameterType="_int">
            delete from book where book_id = #{bookId};
        </delete>
        <update id="updateBook" parameterType="book">
            update book
            set book_name = #{bookName},book_counts=#{bookCounts},detail=#{detail}
            where book_id=#{bookId};
        </update>
        <select id="queryBookById" parameterType="_int">
            select * from book where book_id = #{bookId};
        </select>
        <select id="queryAllBook">
            select * from book;
        </select>
        <select id="queryBookByName" parameterType="String" resultType="book">
            select * from book where book_name = #{bookName};
        </select>
    </mapper>
  2. 編寫 spring-service.xml,將 Service 層注入到 Spring 容器中,並配置相對應的事務

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
        <!-- 掃描service包下的類 -->
        <context:component-scan base-package="com.xp.service"/>
    
        <!-- 將咱們全部的業務類,注入到Spring,能夠經過配置或註解實現,這裏使用配置實現 -->
        <bean id="bookService" class="com.xp.service.impl.BookServiceImpl">
            <property name="bookMapper" ref="bookMapper"/>
        </bean>
    
        <!-- 配置聲明式事務 -->
        <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
            <!-- 注入數據源 -->
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <!-- AOP 事務支持 -->
    
    </beans>
  3. 建立 springmvc-servlet.xml ,將 Controller 層注入到 Spring 中

    <?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">
    
        <!-- 掃描controller下的包 -->
        <context:component-scan base-package="com.xp.controller"/>
        <!-- 靜態資源處理 -->
        <mvc:default-servlet-handler/>
        <!-- 註解驅動支持 -->
        <mvc:annotation-driven>
            <!-- 解決Jackson亂碼問題 -->
            <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>
    
        <!-- 模板解析器 -->
        <bean id="templateResolver" class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
            <property name="prefix" value="/WEB-INF/html/" />
            <property name="suffix" value=".html" />
            <property name="templateMode" value="HTML5" />
            <property name="cacheable" value="false" />
            <property name="characterEncoding" value="UTF-8"/>
        </bean>
    
        <!-- 模板引擎 -->
        <bean class="org.thymeleaf.spring5.SpringTemplateEngine" id="templateEngine">
            <property name="templateResolver" ref="templateResolver"/>
            <property name="enableSpringELCompiler" value="true"/>
        </bean>
    
        <!-- 視圖解析器 -->
        <bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
            <property name="characterEncoding" value="utf-8"/>
            <property name="templateEngine" ref="templateEngine"/>
        </bean>
    
    </beans>
  4. 建立 applicationContext.xml ,使用 import 標籤將剛剛配置的文件導入到這個主配置中

    <?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">
    
        <!-- 整合配置文件 -->
        <import resource="springmvc-servlet.xml"/>
        <import resource="spring-dao.xml"/>
        <import resource="spring-service.xml"/>
    
    </beans>
  5. 配置 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">
    
        <!-- 配置 DispatcherServlet -->
        <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:config/applicationContext.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>
  6. 編寫控制器 BookController

    @Controller
    public class BookController {
    
        private static final String TO_ALL_BOOK = "/toAllBook";
        // Controller 層調用 Service 層
        @Autowired
        private BookService bookService;
    
        public void setBookService(BookService bookService) {
            this.bookService = bookService;
        }
    
        @RequestMapping(TO_ALL_BOOK)
        public String toAllBook() {
            return "allBook";
        }
        
        @RequestMapping("/allBook")
        @ResponseBody
        public String allBook() throws JsonProcessingException {
            List<Book> books = bookService.queryAllBook();
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.writeValueAsString(books);
        }
    
    }
  7. 編寫主頁 index.html

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <title>$Title$</title>
        <style>
          a{
            text-decoration: none;
            color: black;
            font-size: 38px;
          }
          h3{
            width: 300px;
            height: 80px;
            margin: 200px auto;
            text-align: center;
            line-height: 80px;
            background-color: #7afdf1;
            border-radius: 5px;
          }
        </style>
      </head>
      <body>
      <h3><a href="${pageContext.request.contextPath}/book/toAllBook">進入書籍頁面</a></h3>
      </body>
    </html>

到這裏,咱們的三層架構就已經搭建完成了。

啓動Tomcat,簡單測試一下配置是否有誤。

配置無誤後,就開始編寫前端頁面和控制器。

  • allBook.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>書籍展現</title>
    
        <script src="../../static/js/jquery-3.4.1.min.js"></script>
        <script src="../../static/js/bootstrap.min.js"></script>
        <link type="text/css" rel="stylesheet" href="../../static/css/bootstrap.min.css"/>
        <script type="text/javascript">
            // init 初始化頁面,加載後端的數據
            $.get({
                url: "/book/allBook",
                dataType: "json",
                success: function (data) {
                    booksJsonToString(data);
                }
            });
        </script>
    </head>
    <body>
    
    <div class="container">
    
        <!-- 標題 -->
        <div class="row clearfix">
            <div class="col-md-12 column">
                <div class="page-header">
                    <h1>
                        <small>書籍展現</small>
                    </h1>
                </div>
            </div>
        </div>
    
        <div class="row clearfix">
            <!-- 增長按鈕 -->
            <div class="col-md-4 column">
                <button class="btn btn-primary" onclick="clickToHref('/book/toAddBook')">增長</button>
                <!-- 顯示全部書籍按鈕 -->
                <button class="btn btn-primary" onclick="clickToHref('/book/toAllBook')">顯示全部書籍</button>
            </div>
            <!-- 搜索框 -->
            <div class="col-md-8 column" >
                <form class="form-inline" id="searchBookForm" style="float: right">
                    <span id="searchError" style="color:red"></span>&nbsp;&nbsp;
                    <input type="text" class="form-control" name="name" placeholder="請輸入查詢的書籍名稱"/>&nbsp;
                    <input id="searchBtn" class="btn btn-secondary" type="button" value="搜索" onclick="searchBtnClick()"/>
                </form>
            </div>
        </div>
    
        <!-- 表格 -->
        <div class="row clearfix">
            <div class="col-md-12 column">
                <table class="table table-hover table-striped table-responsive-sm">
                    <thead>
                    <tr>
                        <td>書籍編號</td>
                        <td>書籍名稱</td>
                        <td>書籍數量</td>
                        <td>書籍描述</td>
                        <td>操做</td>
                    </tr>
                    </thead>
                    <tbody id="tbody">
    
                    </tbody>
                </table>
            </div>
        </div>
    
    </div>
    
    <script>
        // 點擊後跳轉連接
        function clickToHref(href) {
            window.location.href=href;
        }
        function deleteClick(id) {
            var msg = "確認刪除嗎?";
            if (confirm(msg) === true){
                clickToHref('/book/deleteBook?id='+id)
            } else {
                return false;
            }
        }
        // 更新按鈕點擊跳轉
        function updateClick(href,id) {
            clickToHref(href+"?id="+id);
        }
        // 搜索按鈕點擊跳轉
        function searchBtnClick() {
            $.get({
                url: "/book/searchBook",
                data: $("#searchBookForm").serialize(),
                dataType: "json",
                success: function (data) {
                    var json = JSON.stringify(data);
                    var searchError = $("#searchError");
                    searchError.empty();
                    // 判斷數據是否爲空
                    if (json==="[]"){
                        searchError.html("搜索不到該書籍");
                        refreshTBody("");
                    }else {
                        booksJsonToString(data);
                    }
                }
            })
        }
    </script>
    <script>
        // 將book集合的json格式轉換成字符串
        function booksJsonToString(data) {
            var html = '';
            for (var i=0;i<data.length;i++){
                html += bookJsonToString(data[i]);
            }
            refreshTBody(html);
        }
        // 將book的json格式轉換成字符串
        function bookJsonToString(book) {
            var bookId = book.bookId;
            var html = "";
            html += "<tr><td>" + bookId + "</td><td>" + book.bookName + "</td><td>" + book.bookCounts + "</td><td>"
                + book.detail + "</td><td><button class='btn btn-sm btn-info' onclick=" + "updateClick('/book/toUpdateBook',"
                + bookId + ")" + " >修改</button>" + "&nbsp;<button class='btn btn-danger btn-sm' onclick=deleteClick(" + bookId + ")"
                + " >刪除</button></td></tr>";
            return html;
        }
        // 刷新表格中的內容
        function refreshTBody(html) {
            var tbody = $("#tbody");
            tbody.empty();
            tbody.html(html);
        }
    </script>
    </body>
    </html>
  • addBook.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>增長書籍</title>
    
        <script src="../../static/js/jquery-3.4.1.min.js"></script>
        <script src="../../static/js/bootstrap.min.js"></script>
        <link type="text/css" rel="stylesheet" href="../../static/css/bootstrap.min.css"/>
    </head>
    <body>
    <div class="container">
    
        <!-- 標題 -->
        <div class="row clearfix">
            <div class="col-md-12 column">
                <h1>
                    <small>增長書籍</small>
                </h1>
            </div>
        </div>
    
        <!-- 增長書籍的表單 -->
        <div class="row clearfix">
            <div class="col-md-8 column">
                <form action="/book/addBook">
                    <div class="form-row">
                        <label>書籍名稱<input type="text" name="bookName" class="form-control input-group mb-3" required/></label>
                .    </div>
                    <div class="form-row">
                        <label>書籍數量<input type="text" name="bookCounts" class="form-control input-group mb-3" required/>
                        </label>
                    </div>
                    <div class="form-row">
                        <label>書籍描述<input type="text" name="detail" class="form-control input-group mb-3" required/></label>
                    </div>
                    <div class="form-row">
                        <input type="submit" class="btn btn-primary form-control" onclick="return addClick()" value="添加" style="width: 200px"/>
                    </div>
                </form>
            </div>
        </div>
    
    </div>
    
    <script>
        // 防止誤點操做
        function addClick(){
            var msg = "確認增長?";
            return confirm(msg);
        }
    </script>
    
    </body>
    </html>
  • update.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>修改書籍</title>
    
        <script src="../../static/js/jquery-3.4.1.min.js"></script>
        <script src="../../static/js/bootstrap.min.js"></script>
        <link type="text/css" rel="stylesheet" href="../../static/css/bootstrap.min.css"/>
    </head>
    <body>
    <div class="container">
    
        <!-- 標題 -->
        <div class="row clearfix">
            <div class="col-md-12 column">
                <h1>
                    <small>修改書籍</small>
                </h1>
            </div>
        </div>
    
        <!--/*@thymesVar id="book" type="com.xp.entity.Book"*/-->
        <!-- 更新的表單 -->
        <div class="row clearfix">
            <div class="col-md-6">
                <form action="/book/updateBook">
                    <input type="hidden" name="bookId" th:value="${book.bookId}">
                    <div class="form-row input-group mb-3">
                        <label>書籍名稱<input type="text" name="bookName" class="form-control" th:value="${book.bookName} "/></label>
                    </div>
                    <div class="form-row input-group mb-3">
                        <label>書籍數量<input type="text" name="bookCounts" class="form-control" th:value="${book.bookCounts}"/></label>
                    </div>
                    <div class="form-row input-group mb-3">
                        <label>書籍描述<input type="text" name="detail" class="form-control"  th:value="${book.detail}"/></label>
                    </div>
                    <div class="form-row">
                        <input type="submit" class="btn btn-primary form-control" onclick="return updateClick()" value="修改" style="width: 200px"/>
                    </div>
                </form>
            </div>
        </div>
    
    </div>
    
    <script>
        // 防止誤點
        function updateClick(){
            var msg = "確認修改?";
            return confirm(msg) === true;
        }
    </script>
    
    </body>
    </html>
  • BookController

    package com.xp.controller;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.xp.entity.Book;
    import com.xp.service.BookService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.util.List;
    
    @Controller
    @RequestMapping("/book")
    @SuppressWarnings("all")
    public class BookController {
    
        private static final String TO_ALL_BOOK = "/toAllBook";
        // Controller 層調用 Service 層
        @Autowired
        private BookService bookService;
    
        public void setBookService(BookService bookService) {
            this.bookService = bookService;
        }
    
        @RequestMapping(TO_ALL_BOOK)
        public String toAllBook() {
            return "allBook";
        }
    
        @RequestMapping("/allBook")
        @ResponseBody
        public String allBook() throws JsonProcessingException {
            List<Book> books = bookService.queryAllBook();
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.writeValueAsString(books);
        }
    
        @RequestMapping("/toAddBook")
        public String toAddBook() {
            return "addBook";
        }
    
        @RequestMapping("/addBook")
        public String addBook(Book book) {
            return "redirect:/book" + TO_ALL_BOOK;
        }
    
        @RequestMapping("/deleteBook")
        public String deleteBook(int id) {
            bookService.deleteBookById(id);
            return "redirect:/book" + TO_ALL_BOOK;
        }
    
        @RequestMapping("/updateBook")
        public String updateBook(Book book) {
            bookService.updateBook(book);
            return "redirect:/book" + TO_ALL_BOOK;
        }
    
        @RequestMapping("/toUpdateBook")
        public String toUpdateBook(int id, Model model) {
            Book book = bookService.queryBookById(id);
            model.addAttribute("book", book);
            return "updateBook";
        }
    
        @RequestMapping("/searchBook")
        @ResponseBody
        public String searchBook(String name) throws JsonProcessingException {
            List<Book> book = bookService.queryBookByName(name);
            return new ObjectMapper().writeValueAsString(book);
        }
    
    
    }

到這裏,咱們的 SSM 框架纔算徹底整合。在之後再次寫 SSM 項目時,能夠將這個做爲模板來進行編寫。

相關文章
相關標籤/搜索