<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      SpringMVC 教程

      SpringMVC

      本項目參考 【狂神說Java】SpringMVC 最新教程 IDEA 版通俗易懂
      Github 地址:https://github.com/Lockegogo/Java-Study

      回顧 MVC

      什么是 MVC

      MVC 是:

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

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

      View:負責模型的展示,一般就是我們見到的用戶頁面,客戶想看到的東西

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

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

      img

      回顧 Servlet

      1. 新建一個 Maven 工程當做父工程! pom 依賴!
      <dependencies>
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.12</version>
          </dependency>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-webmvc</artifactId>
              <version>5.1.9.RELEASE</version>
          </dependency>
          <dependency>
              <groupId>javax.servlet</groupId>
              <artifactId>servlet-api</artifactId>
              <version>2.5</version>
          </dependency>
          <dependency>
              <groupId>javax.servlet.jsp</groupId>
              <artifactId>jsp-api</artifactId>
              <version>2.2</version>
          </dependency>
          <dependency>
              <groupId>javax.servlet</groupId>
              <artifactId>jstl</artifactId>
              <version>1.2</version>
          </dependency>
      </dependencies>
      
      1. 建立一個 Moudle:springmvc-01-servlet , 添加 Web app 的支持,導入 servlet 和 jsp 的 jar 依賴
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>servlet-api</artifactId>
          <version>2.5</version>
      </dependency>
      <dependency>
          <groupId>javax.servlet.jsp</groupId>
          <artifactId>jsp-api</artifactId>
          <version>2.2</version>
      </dependency>
      
      1. 編寫一個 servlet 類,用來處理用戶的請求
      // 實現 Servlet 接口
      public class HelloServlet extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              // 1. 獲取前端參數
              String method = req.getParameter("method");
              if (method.equals("add")){
                  req.getSession().setAttribute("msg","執行了add方法");
              }
              if (method.equals("delete")){
                  req.getSession().setAttribute("msg","執行了delete方法");
              }
              // 2. 調用業務層
              // 3. 視圖轉發或者重定向
              req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,resp);
          }
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doGet(req,resp);
          }
      }
      
      1. 編寫 test.jsp,在 WEB-INF 目錄下新建一個 jsp 的文件夾,新建 test.jsp
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
          <head>
              <title>My Java</title>
          </head>
          <body>
      
              ${msg}
      
          </body>
      </html>
      
      1. web.xml 中注冊 Servlet
      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
               version="4.0">
          <servlet>
              <servlet-name>hello</servlet-name>
              <servlet-class>com.locke.servlet.HelloServlet</servlet-class>
          </servlet>
          <servlet-mapping>
              <servlet-name>hello</servlet-name>
              <url-pattern>/hello</url-pattern>
          </servlet-mapping>
      
          <!--配置超時時間-->
          <session-config>
              <session-timeout>15</session-timeout>
          </session-config>
      
          <!--配置歡迎頁面-->
          <welcome-file-list>
              <welcome-file>index.jsp</welcome-file>
          </welcome-file-list>
      
      
      </web-app>
      
      1. 配置 Tomcat,并啟動測試
        1. localhost:8080/hello?method=add
        2. localhost:8080/hello?method=delete

      MVC 框架要做哪些事情?

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

      什么是 SpringMVC

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

      img

      中心控制器

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

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

      執行原理

      HelloSpring

      原理版

      1. 新建一個 Moudle, springmvc-02-hello , 添加 web 的支持!
      <!--導入依賴-->
      <dependencies>
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.13.2</version>
          </dependency>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-webmvc</artifactId>
              <version>5.2.0.RELEASE</version>
          </dependency>
          <dependency>
              <groupId>javax.servlet</groupId>
              <artifactId>servlet-api</artifactId>
              <version>2.5</version>
          </dependency>
          <dependency>
              <groupId>javax.servlet.jsp</groupId>
              <artifactId>jsp-api</artifactId>
              <version>2.2</version>
          </dependency>
          <dependency>
              <groupId>javax.servlet</groupId>
              <artifactId>jstl</artifactId>
              <version>1.2</version>
          </dependency>
      </dependencies>
      
      1. 配置 web.xml,注冊 DispatcherServlet
      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
               version="4.0">
      
          <!--1.注冊 DispatcherServlet-->
          <servlet>
              <servlet-name>springmvc</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
              <!--關聯一個 springmvc 的配置文件:【servlet-name】-servlet.xml-->
              <init-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath:springmvc-servlet.xml</param-value>
              </init-param>
              <!--啟動級別-1-->
              <load-on-startup>1</load-on-startup>
          </servlet>
          <!--/ 匹配所有的請求;(不包括.jsp)-->
          <!--/* 匹配所有的請求;(包括.jsp)-->
          <servlet-mapping>
              <servlet-name>springmvc</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>
      </web-app>
      
      1. 編寫 SpringMVC 的配置文件!名稱:springmvc-servlet.xml : [servletname]-servlet.xml,在 resources 包內
      <?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">
      
          <!--添加處理映射器-->
          <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
          <!--添加處理器適配器-->
          <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
      
          <!--視圖解析器: DispatcherServlet 給他的 ModelAndView
          1. 獲取 ModelAndView 的數據
          2. 解析 ModelAndView 的視圖名字
          3. 拼接視圖名字,找到對應的視圖 /WEB-INF/jsp/hello.jsp
          4. 將數據渲染到這個視圖上
          -->
          <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
              <!--前綴-->
              <property name="prefix" value="/WEB-INF/jsp/"/>
              <!--后綴-->
              <property name="suffix" value=".jsp"/>
          </bean>
      
          <!--Handler-->
          <bean id="/hello" class="com.locke.controller.HelloController"/>
      
      </beans>
      
      1. 編寫我們要操作的業務 Controller,要么實現 Controller 接口,要么增加注解;需要返回一個 ModelAndView,裝數據,封視圖:
      // 注意:這里我們先導入 Controller 接口
      public class HelloController implements Controller {
      
          @Override
          public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
              // ModelAndView 模型和視圖
              ModelAndView mv = new ModelAndView();
              // 封裝對象,放在 ModelAndView 中 Model
              mv.addObject("msg","HelloSpringMVC!");
              // 封裝要跳轉的視圖,放在 ModelAndView 中
              mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp
              return mv;
          }
      
      }
      
      1. 將自己的類交給 SpringIOC 容器,注冊 bean
      <!--Handler-->
      <bean id="/hello" class="com.locke.controller.HelloController"/>
      
      1. 寫要跳轉的 hello.jsp 頁面,顯示 ModelandView 存放的數據,以及我們的正常頁面;
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      	${msg}
      </body>
      </html>
      
      1. 配置 Tomcat 啟動測試:

      注意,可能遇到的問題如下:

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

      注解版

      1. 由于 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>
      
      1. pom.xml 文件中引入相關的依賴:主要有 Spring 框架核心庫、SpringMVC、servlet,JSTL 等,我們已經在父依賴中引入了
      2. 配置 web.xml
        1. 注意 web.xml 版本問題,要最新版!
        2. 注冊 DispatcherServlet
        3. 關聯 SpringMVC 的配置文件
        4. 啟動級別為 1
        5. 映射路徑為 / 【不要用 /*,會 404】
      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
               version="4.0">
      
          <!--1.注冊 DispatcherServlet-->
          <servlet>
              <servlet-name>springmvc</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
              <!--關聯一個 springmvc 的配置文件:【servlet-name】-servlet.xml-->
              <init-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath:springmvc-servlet.xml</param-value>
              </init-param>
              <!--啟動級別-1-->
              <load-on-startup>1</load-on-startup>
          </servlet>
          <!--/ 匹配所有的請求;(不包括.jsp)-->
          <!--/* 匹配所有的請求;(包括.jsp)-->
          <servlet-mapping>
              <servlet-name>springmvc</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>
      </web-app>
      
      1. 添加 Spring MVC 配置文件:在 resource 目錄下添加 springmvc-servlet.xml 配置文件,配置的形式與 Spring 容器配置基本類似,為了支持基于注解的 IOC,設置了自動掃描包的功能,具體配置信息如下:
        1. 讓 IOC 注解生效
        2. 靜態資源過濾:HTML 等
        3. MVC 的注解驅動
        4. 配置視圖解析器
      <?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.locke.controller"/>
          <!-- 讓 Spring MVC 不處理靜態資源 -->
          <mvc:default-servlet-handler />
          <!--
          支持 mvc 注解驅動
              在 spring 中一般采用 @RequestMapping 注解來完成映射關系
              要想使 @RequestMapping 注解生效
              必須向上下文中注冊 DefaultAnnotationHandlerMapping
              和一個 AnnotationMethodHandlerAdapter 實例
              這兩個實例分別在類級別和方法級別處理。
              而 annotation-driven 配置幫助我們自動完成上述兩個實例的注入。
           -->
          <mvc:annotation-driven />
          <!-- 視圖解析器 -->
          <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
                id="internalResourceViewResolver">
              <!-- 前綴 -->
              <property name="prefix" value="/WEB-INF/jsp/" />
              <!-- 后綴 -->
              <property name="suffix" value=".jsp" />
          </bean>
      </beans>
      

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

      1. 創建 Controller:編寫一個 Java 控制類 com.locke.controller.HelloController, 注意編碼規范
        1. @Controller 是為了讓 Spring IOC 容器初始化時自動掃描到;
        2. @RequestMapping 是為了映射請求路徑,這里因為方法上都有映射所以訪問時應該是 /HelloController/hello;
        3. 方法中聲明 Model 類型的參數是為了把 Action 中的數據帶到視圖中;
        4. 方法返回的結果是視圖的名稱 hello,加上配置文件中的前后綴變成 WEB-INF/jsp/hello.jsp。
      @Controller
      // 父路徑
      @RequestMapping("/HelloController")
      public class HelloController {
          // 真實訪問地址: 項目名/HelloController/hello
          // 子路徑
          @RequestMapping("/hello")
          public String sayHello(Model model){
              // 向模型中添加屬性 msg 與值,可以在 JSP 頁面中取出并渲染
              model.addAttribute("msg","hello,SpringMVC");
              // web-inf/jsp/hello.jsp
              return "hello";
          }
      }
      
      1. 創建視圖層:在 WEB-INF/jsp 目錄中創建 hello.jsp , 視圖可以直接取出并展示從 Controller 帶回的信息;
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>SpringMVC</title>
      </head>
      <body>
          ${msg}
      </body>
      </html>
      
      1. 配置 Tomcat 運行:HelloController/hello

      實現步驟:

      1. 新建一個 web 文件
      2. 導入相關 jar 包
      3. 編寫 web.xml,注冊 DispatcherServlet
      4. 編寫 springmvc 配置文件
      5. 接下來就是去創建對應的控制類 Controller
      6. 最后完善前端視圖和 Controller 之間的對應
      7. 測試運行調試

      小結:

      使用 SpringMVC 必須配置的三大件:處理器映射器、處理器適配器、視圖解析器

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

      RestFul 風格

      Restful 就是一個資源定位及資源操作的風格。不是標準也不是協議,只是一種風格?;谶@個風格設計的軟件可以更簡潔,更有層次,更易于實現緩存等機制。

      功能

      1. 資源:互聯網所有的事物都可以被抽象為資源
      2. 資源操作:使用 POST、DELETE、PUT、GET,使用不同方法對資源進行操作。
      3. 分別對應 添加、 刪除、修改、查詢。

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

      1. http://127.0.0.1/item/queryItem.action?id=1 查詢,GET
      2. http://127.0.0.1/item/saveItem.action 新增,POST
      3. http://127.0.0.1/item/updateItem.action 更新,POST
      4. http://127.0.0.1/item/deleteItem.action?id=1 刪除,GET 或 POST

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

      1. http://127.0.0.1/item/1 查詢,GET
      2. http://127.0.0.1/item 新增,POST
      3. http://127.0.0.1/item 更新,PUT
      4. http://127.0.0.1/item/1 刪除,DELETE

      實現:

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

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

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

      1. 使路徑變得更加簡潔、高效(支持緩存)、安全
      2. 獲得參數更加方便,框架會自動進行類型轉換
      3. 通過路徑變量的類型可以約束訪問參數,如果類型不一樣,則訪問不到對應的請求方法,如這里訪問的路徑是 /commit/1/a,則路徑與方法不匹配,而不會是參數轉換失敗

      使用 method 屬性請求指定類型:

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

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

      使用瀏覽器地址欄進行訪問默認是 Get 請求,會報錯 405。需要將 POST 修改為 GET:

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

      結果跳轉方式

      通過 SpringMVC 來實現轉發和重定向:無需視圖解析器

      重定向和轉發的區別

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

      @Controller
      public class ResultSpringMVC {
          @RequestMapping("/rsm/t1")
          public String test1(){
              // 轉發
              return "/index.jsp";
          }
          @RequestMapping("/rsm/t2")
          public String test2(){
              // 轉發二
              return "forward:/index.jsp";
          }
          @RequestMapping("/rsm/t3")
          public String test3(){
              // 重定向
              return "redirect:/index.jsp";
          }
      }
      

      通過 SpringMVC 來實現轉發和重定向:有視圖解析器

      @Controller
      public class ResultSpringMVC2 {
          @RequestMapping("/rsm2/t1")
          public String test1(){
              // 轉發
              return "test";
          }
          @RequestMapping("/rsm2/t2")
          public String test2(){
              // 重定向
              return "redirect:/index.jsp";
          }
      }
      

      數據處理

      處理提交數據

      1. 提交的域名稱和處理方法的參數名一致
        1. 提交數據:http://localhost:8080/hello?name=locke
        2. 后臺輸出:locke
      @RequestMapping("/hello")
      public String hello(String name){
          System.out.println(name);
          return "hello";
      }
      
      1. 提交的域名稱和處理方法的參數名不一致
        1. 提交數據:http://localhost:8080/hello?username=locke
        2. 后臺輸出:locke
      @RequestMapping("/hello")
      // @RequestParam("username"): username 提交的域的名稱
      public String hello(@RequestParam("username") String name){
          System.out.println(name);
          return "hello";
      }
      
      1. 提交的是一個對象
        1. 要求提交的表單域和對象的屬性名一致,參數使用對象即可
        2. 提交數據:http://localhost:8080/mvc04/user?name=locke&id=1&age=15
        3. 后臺輸出:User
      public class User {
          private int id;
          private String name;
          private int age;
          //構造
          //get/set
          //tostring()
      }
      
      @RequestMapping("/user")
      public String user(User user){
          System.out.println(user);
          return "hello";
      }
      

      如果使用對象的話,前端傳遞的參數名和對象名必須一致,否則就是 null

      數據顯示到前端

      1. 通過 ModelAndView
      public class ControllerTest1 implements Controller {
          public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
              // 返回一個模型視圖對象
              ModelAndView mv = new ModelAndView();
              mv.addObject("msg","ControllerTest1");
              mv.setViewName("test");
              return mv;
          }
      }
      
      1. 通過 ModelMap
      @RequestMapping("/hello")
      public String hello(@RequestParam("username") String name, ModelMap model){
          // 封裝要顯示到視圖中的數據
          // 相當于 req.setAttribute("name",name);
          model.addAttribute("name",name);
          System.out.println(name);
          return "hello";
      }
      
      1. 通過 Model
      @RequestMapping("/ct2/hello")
      public String hello(@RequestParam("username") String name, Model model){
          // 封裝要顯示到視圖中的數據
          // 相當于 req.setAttribute("name",name);
          model.addAttribute("msg",name);
          System.out.println(name);
          return "test";
      }
      

      區別:

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

      亂碼問題

      首先在首頁編寫一個提交的表單:

      <form action="/e/t" method="post">
        <input type="text" name="name">
        <input type="submit">
      </form>
      

      然后后臺編寫對應的處理類:

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

      輸入中文測試,發現亂碼!

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

      注意:修改了 xml 文件需要重啟服務器!

      <filter>
          <filter-name>encoding</filter-name>
          <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
          <init-param>
              <param-name>encoding</param-name>
              <param-value>utf-8</param-value>
          </init-param>
      </filter>
      <filter-mapping>
          <filter-name>encoding</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
      

      但是在一些極端情況下,這個過濾器對 get 的支持不好。

      處理方法:

      1. 修改 tomcat 配置文件 conf/server.xml:設置編碼
      <Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"
                 connectionTimeout="20000"
                 redirectPort="8443" />
      
      1. 自定義過濾器:com.locke.filter
      /**
       * 解決 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;
          }
      }
      
      1. 然后在 web.xml 中配置這個過濾器
      <!--配置 SpringMVC 的亂碼過濾-->
      <filter>
          <filter-name>encoding</filter-name>
          <filter-class>com.locke.filter.GenericEncodingFilter</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>encoding</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
      

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

      Json

      前后端分類時代:

      • 后端部署后端,提供接口,提供數據
      • json 連接前端和后端
      • 前端獨立部署,負責渲染后端的數據

      代碼測試

      1. 新建一個 module ,springmvc-04-json , 添加 web 的支持
      2. 在 web 目錄下新建一個 jsontest.html , 編寫測試內容
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>JSON_LK</title>
      </head>
      <body>
      <script type="text/javascript">
          // 編寫一個 js 的對象
          var user = {
              name: "LK",
              age: 26,
              sex: "Female"
          };
          // console.log(user);
      
          // 將 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>
      
      1. 在 IDEA 中使用瀏覽器打開,查看控制臺輸出!

      Controller 返回 JSON 數據

      1. 導入 Jacksonjar
      <dependencies>
          <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
          <dependency>
              <groupId>com.fasterxml.jackson.core</groupId>
              <artifactId>jackson-databind</artifactId>
              <version>2.14.1</version>
          </dependency>
          <dependency>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
              <version>1.18.10</version>
              <scope>provided</scope>
          </dependency>
      </dependencies>
      
      1. 配置 SpringMVC 的 web.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
               version="4.0">
          <!--1.注冊 servlet-->
          <servlet>
              <servlet-name>SpringMVC</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
              <!--通過初始化參數指定 SpringMVC 配置文件的位置,進行關聯-->
              <init-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath:springmvc-servlet.xml</param-value>
              </init-param>
              <!-- 啟動順序,數字越小,啟動越早 -->
              <load-on-startup>1</load-on-startup>
          </servlet>
          <!--所有請求都會被 springmvc 攔截 -->
          <servlet-mapping>
              <servlet-name>SpringMVC</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>
          <filter>
              <filter-name>encoding</filter-name>
              <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
              <init-param>
                  <param-name>encoding</param-name>
                  <param-value>utf-8</param-value>
              </init-param>
          </filter>
          <filter-mapping>
              <filter-name>encoding</filter-name>
              <url-pattern>/</url-pattern>
          </filter-mapping>
      </web-app>
      
      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">
          <!-- 自動掃描指定的包,下面所有注解類交給 IOC 容器管理 -->
          <context:component-scan base-package="com.locke.controller"/>
          <!-- 視圖解析器 -->
          <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
                id="internalResourceViewResolver">
              <!-- 前綴 -->
              <property name="prefix" value="/WEB-INF/jsp/" />
              <!-- 后綴 -->
              <property name="suffix" value=".jsp" />
          </bean>
      </beans>
      
      1. 寫一個 User 的實體類,然后我們去編寫我們的測試 Controller
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      public class User {
          private String name;
          private int age;
          private String sex;
      }
      
      // @RestController: 如果使用這個,就不需要再配合使用 @ResponseBody
      @Controller
      public class UserController {
          @RequestMapping("/json1")
          @ResponseBody // 它就不會走視圖解析器,會直接返回一個字符串
          public String json1() throws JsonProcessingException {
              // 創建一個 jackson 的對象映射器,用來解析數據
              ObjectMapper mapper = new ObjectMapper();
              // 創建一個對象
              User user = new User("LK", 26, "Female");
              // 將我們的對象解析成為 json 格式
              String str = mapper.writeValueAsString(user);
              // 由于 @ResponseBody 注解,這里會將 str 轉成 json 格式返回;十分方便
              return str;
          }
      }
      
      1. 配置 Tomcat,如果有亂碼問題,再設置一下編碼格式為 utf-8,以及它的返回類型
      // produces: 指定響應體返回類型和編碼
      @RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")
      

      代碼優化

      亂碼統一解決

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

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

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

      返回 json 字符串統一解決

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

      @RestController
      public class UserController {
          // produces: 指定響應體返回類型和編碼
          @RequestMapping(value = "/json1")
          public String json1() throws JsonProcessingException {
              // 創建一個 jackson 的對象映射器,用來解析數據
              ObjectMapper mapper = new ObjectMapper();
              // 創建一個對象
              User user = new User("LK", 26, "Female");
              // 將我們的對象解析成為 json 格式
              String str = mapper.writeValueAsString(user);
              // 由于 @ResponseBody 注解,這里會將 str 轉成 json 格式返回;十分方便
              return str;
          }
      }
      

      測試集合輸出

      增加一個新的方法:

      @RequestMapping("/json2")
      public String json2() throws JsonProcessingException {
          // 創建一個 jackson 的對象映射器,用來解析數據
          ObjectMapper mapper = new ObjectMapper();
          // 創建一個對象
          User user1 = new User("LK1", 1, "Female");
          User user2 = new User("LK2", 2, "Female");
          User user3 = new User("LK3", 3, "Female");
          User user4 = new User("LK4", 4, "Female");
          List<User> list = new ArrayList<User>();
          list.add(user1);
          list.add(user2);
          list.add(user3);
          list.add(user4);
          // 將我們的對象解析成為json格式
          String str = mapper.writeValueAsString(list);
          return str;
      }
      

      輸出時間對象

      增加一個新的方法:

      @RequestMapping("/json3")
      public String json3() throws JsonProcessingException {
          ObjectMapper mapper = new ObjectMapper();
          // 創建時間一個對象,java.util.Date
          Date date = new Date();
          // 將我們的對象解析成為json格式
          String str = mapper.writeValueAsString(date);
          return str;
      }
      
      • 默認日期格式會變成一個數字,是 1970 年 1 月 1 日到當前日期的毫秒數!
      • Jackson 默認是會把時間轉成 timestamps 形式

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

      @RequestMapping("/json4")
      public String json4() throws JsonProcessingException {
          ObjectMapper mapper = new ObjectMapper();
          // 不使用時間戳的方式
          mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
          // 自定義日期格式對象
          SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
          // 指定日期格式
          mapper.setDateFormat(sdf);
          Date date = new Date();
          String str = mapper.writeValueAsString(date);
          return str;
      }
      

      抽取為工具類

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

      public class JsonUtils {
          public static String getJson(Object object) {
              return getJson(object,"yyyy-MM-dd HH:mm:ss");
          }
          public static String getJson(Object object,String dateFormat) {
              ObjectMapper mapper = new ObjectMapper();
              // 不使用時間差的方式
              mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
              // 自定義日期格式對象
              SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
              // 指定日期格式
              mapper.setDateFormat(sdf);
              try {
                  return mapper.writeValueAsString(object);
              } catch (JsonProcessingException e) {
                  e.printStackTrace();
              }
              return null;
          }
      }
      
      @RequestMapping("/json5")
      public String json5() throws JsonProcessingException {
          Date date = new Date();
          String json = JsonUtils.getJson(date);
          return json;
      }
      

      FastJson

      fastjson.jar 是阿里開發的一款專門用于 Java 開發的包,可以方便的實現 json 對象與 JavaBean 對象的轉換,實現 JavaBean 對象與 json 字符串的轉換,實現 json 對象與 json 字符串的轉換。實現 json 的轉換方法很多,最后的實現結果都是一樣的。

      fastjson 的 pom 依賴:

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

      fastjson 三個主要的類:

      • JSONObject 代表 json 對象

        • JSONObject 實現了 Map 接口,猜想 JSONObject 底層操作是由 Map 實現的。
        • JSONObject 對應 json 對象,通過各種形式的 get() 方法可以獲取 json 對象中的數據,也可利用諸如 size(),isEmpty() 等方法獲取 "鍵:值" 對的個數和判斷是否為空。其本質是通過實現 Map 接口并調用接口中的方法完成的。
      • JSONArray 代表 json 對象數組

        • 內部是有 List 接口中的方法來完成操作的。
      • JSON 代表 JSONObject 和 JSONArray 的轉化

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

      新建一個 FastJsonDemo 類:

      package com.kuang.controller;
      import com.alibaba.fastjson.JSON;
      import com.alibaba.fastjson.JSONObject;
      import com.kuang.pojo.User;
      import java.util.ArrayList;
      import java.util.List;
      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);
          }
      }
      

      整合 SSM:非常重要!

      img

      op=>operation: 需求分析
      db=>operation: 設計數據庫
      se=>operation: 業務
      ht=>operation: 前端界面
      op(right)->db(right)->se(right)->ht
      
      ht=>operation: 前端
      ct=>operation: Controller
      sv=>operation: Service
      do=>operation: Dao
      db=>operation: 數據庫
      ht(right)->ct(right)->sv(right)->do(right)->db
      
      1. 讀代碼:從前往后
      2. 寫代碼:從后往前

      數據庫環境

      1. 創建一個存放書籍數據的數據庫表:
      CREATE DATABASE `ssmbuild`;
      USE `ssmbuild`;
      DROP TABLE IF EXISTS `books`;
      CREATE TABLE `books` (
        `bookID` INT(10) NOT NULL AUTO_INCREMENT COMMENT '書id',
        `bookName` VARCHAR(100) NOT NULL COMMENT '書名',
        `bookCounts` INT(11) NOT NULL COMMENT '數量',
        `detail` VARCHAR(200) NOT NULL COMMENT '描述',
        KEY `bookID` (`bookID`)
      ) ENGINE=INNODB DEFAULT CHARSET=utf8;
      INSERT INTO `books`(`bookID`,`bookName`,`bookCounts`,`detail`) VALUES
      (1,'Java',1,'從入門到放棄'),
      (2,'MySQL',10,'從刪庫到跑路'),
      (3,'Linux',5,'從進門到進牢');
      

      基本環境搭建

      1. 新建一 Maven 項目! 添加 web 的支持
        1. 導入相關的 pom 依賴!
        2. Maven 資源過濾設置
      <dependencies>
          <!--Junit-->
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.13.1</version>
          </dependency>
          <!--數據庫驅動-->
          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <version>8.0.32</version>
          </dependency>
          <!--數據庫連接池-->
          <dependency>
              <groupId>com.mchange</groupId>
              <artifactId>c3p0</artifactId>
              <version>0.9.5.2</version>
          </dependency>
          <!--Servlet - JSP -->
          <dependency>
              <groupId>javax.servlet</groupId>
              <artifactId>servlet-api</artifactId>
              <version>2.5</version>
          </dependency>
          <dependency>
              <groupId>javax.servlet.jsp</groupId>
              <artifactId>jsp-api</artifactId>
              <version>2.2</version>
          </dependency>
          <dependency>
              <groupId>javax.servlet</groupId>
              <artifactId>jstl</artifactId>
              <version>1.2</version>
          </dependency>
          <!--Mybatis-->
          <dependency>
              <groupId>org.mybatis</groupId>
              <artifactId>mybatis</artifactId>
              <version>3.5.6</version>
          </dependency>
          <dependency>
              <groupId>org.mybatis</groupId>
              <artifactId>mybatis-spring</artifactId>
              <version>2.0.2</version>
          </dependency>
          <!--Spring-->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-webmvc</artifactId>
              <version>5.2.0.RELEASE</version>
          </dependency>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-jdbc</artifactId>
              <version>5.2.0.RELEASE</version>
          </dependency>
          <!--Lombok-->
          <dependency>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
              <version>1.18.10</version>
              <scope>provided</scope>
          </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>
      
      1. 建立基本結構和配置框架

        1. com.locke.pojo
        2. com.locke.dao
        3. com.locke.service
        4. com.locke.controller
        5. 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>
        </configuration>
        
        1. applicationContext.xml
        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd">
        </beans>
        

      Mybatis 層編寫

      1. 數據庫配置文件 database.properties:IDEA 關聯數據庫
      jdbc.driver=com.mysql.cj.jdbc.Driver
      # 如果使用的是 MySQL8.0+,還需要增加一個時區的配置 &serverTimezone=Asia/Shanghai
      jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
      jdbc.username=root
      jdbc.password=130914
      
      1. 編寫 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>
          <typeAliases>
              <package name="com.locke.pojo"/>
          </typeAliases>
          <mappers>
              <mapper resource="com/locke/dao/BookMapper.xml"/>
          </mappers>
      </configuration>
      
      1. 編寫數據庫對應的實體類 com.locke.pojo.Books,注意使用 lombok 插件
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      public class Books {
          private int bookID;
          private String bookName;
          private int bookCounts;
          private String detail;
      }
      
      1. 編寫 Dao 層的 BookMapper 接口
      public interface BookMapper {
          // 增加一個 Book
          int addBook(Books book);
      
          // 根據 id 刪除一個 Book
          // int deleteBookById(@Param("bookId") int id);
          int deleteBookById(int id);
      
          // 更新 Book
          int updateBook(Books books);
      
          // 根據 id 查詢,返回一個 Book
          Books queryBookById(int id);
      
          // 查詢全部 Book, 返回 list 集合
          List<Books> queryAllBook();
      
          // 根據 id 查詢,返回一個Book
          Books queryBookByName(String bookName);
      }
      
      1. 編寫接口對應的 Mapper.xml 文件,需要導入 MyBatis 的包:
      <?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.locke.dao.BookMapper">
          <!--增加一個 Book-->
          <insert id="addBook" parameterType="Books">
              insert into ssmbuild.books(bookName, bookCounts, detail)
              values (#{bookName}, #{bookCounts}, #{detail})
          </insert>
          <!--根據 id 刪除一個 Book-->
          <delete id="deleteBookById" parameterType="int">
              delete
              from ssmbuild.books
              where bookID = #{bookID}
          </delete>
          <!--更新 Book-->
          <update id="updateBook" parameterType="Books">
              update ssmbuild.books
              set bookName   = #{bookName},
                  bookCounts = #{bookCounts},
                  detail     = #{detail}
              where bookID = #{bookID}
          </update>
          <!--根據 id 查詢,返回一個Book-->
          <select id="queryBookById" resultType="Books">
              select *
              from ssmbuild.books
              where bookID = #{bookID}
          </select>
          <!--查詢全部 Book-->
          <select id="queryAllBook" resultType="Books">
              SELECT *
              from ssmbuild.books
          </select>
      </mapper>
      
      1. 編寫 Service 層的接口和實現類
      // BookService: 底下需要去實現, 調用 dao 層
      public interface BookService {
          // 增加一個 Book
          int addBook(Books book);
      
          // 根據 id 刪除一個Book
          int deleteBookById(int id);
      
          // 更新 Book
          int updateBook(Books books);
      
          // 根據 id 查詢, 返回一個 Book
          Books queryBookById(int id);
      
          // 查詢全部 Book, 返回 list 集合
          List<Books> queryAllBook();
      
          // 根據 id 查詢,返回一個Book
          Books queryBookByName(String bookName);
      }
      
      public class BookServiceImpl implements BookService {
          // 調用 dao 層的操作,設置一個 set 接口,方便 Spring 管理
          private BookMapper bookMapper;
      
          public void setBookMapper(BookMapper bookMapper) {
              this.bookMapper = bookMapper;
          }
      
          public int addBook(Books book) {
              return bookMapper.addBook(book);
          }
      
          public int deleteBookById(int id) {
              return bookMapper.deleteBookById(id);
          }
      
          public int updateBook(Books books) {
              return bookMapper.updateBook(books);
          }
      
          public Books queryBookById(int id) {
              return bookMapper.queryBookById(id);
          }
      
          public List<Books> queryAllBook() {
              return bookMapper.queryAllBook();
          }
      }
      

      至此,底層需求編寫完畢。

      Spring 層

      1. 配置 Spring 整合 MyBatis,我們這里數據源使用 c3p0 連接池;
        1. 編寫 Spring 整合 Mybatis 的相關的配置文件:spring-dao.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context
              https://www.springframework.org/schema/context/spring-context.xsd">
          <!-- 配置整合 mybatis -->
          <!-- 1.關聯數據庫文件 -->
          <context:property-placeholder location="classpath:database.properties"/>
          <!-- 2.數據庫連接池 -->
          <!-- 數據庫連接池
               dbcp  半自動化操作  不能自動連接
               c3p0  自動化操作(自動的加載配置文件 并且設置到對象里面)
          -->
          <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
              <!-- 配置連接池屬性 -->
              <property name="driverClass" value="${jdbc.driver}"/>
              <property name="jdbcUrl" value="${jdbc.url}"/>
              <property name="user" value="${jdbc.username}"/>
              <property name="password" value="${jdbc.password}"/>
              <!-- c3p0 連接池的私有屬性 -->
              <property name="maxPoolSize" value="30"/>
              <property name="minPoolSize" value="10"/>
              <!-- 關閉連接后不自動 commit -->
              <property name="autoCommitOnClose" value="false"/>
              <!-- 獲取連接超時時間 -->
              <property name="checkoutTimeout" value="10000"/>
              <!-- 當獲取連接失敗重試次數 -->
              <property name="acquireRetryAttempts" value="2"/>
          </bean>
          <!-- 3.配置 SqlSessionFactory 對象 -->
          <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
              <!-- 注入數據庫連接池 -->
              <property name="dataSource" ref="dataSource"/>
              <!-- 配置 MyBatis 全局配置文件:mybatis-config.xml -->
              <property name="configLocation" value="classpath:mybatis-config.xml"/>
          </bean>
          <!-- 4.配置掃描 Dao 接口包,動態實現 Dao 接口注入到 spring 容器中 -->
          <!-- 解釋 : http://www.rzrgm.cn/jpfss/p/7799806.html-->
          <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
              <!-- 注入 sqlSessionFactory -->
              <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
              <!-- 給出需要掃描 Dao 接口包 -->
              <property name="basePackage" value="com.locke.dao"/>
          </bean>
      </beans>
      
      1. Spring 整合 service 層:spring-service.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd">
          <!-- 掃描 service 相關的 bean -->
          <context:component-scan base-package="com.locke.service"/>
          <!-- BookServiceImpl 注入到 IOC 容器中 -->
          <bean id="BookServiceImpl" class="com.locke.service.BookServiceImpl">
              <property name="bookMapper" ref="bookMapper"/>
          </bean>
          <!-- 配置事務管理器 -->
          <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
              <!-- 注入數據庫連接池 -->
              <property name="dataSource" ref="dataSource"/>
          </bean>
      </beans>
      

      SpringMVC 層

      1. 編寫 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: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>
          <!--encodingFilter-->
          <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>
          <!--Session 過期時間-->
          <session-config>
              <session-timeout>15</session-timeout>
          </session-config>
      </web-app>
      
      1. 編寫 spring-mvc.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:mvc="http://www.springframework.org/schema/mvc"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd
          http://www.springframework.org/schema/mvc
          https://www.springframework.org/schema/mvc/spring-mvc.xsd">
          <!-- 配置 SpringMVC -->
          <!-- 1.開啟 SpringMVC 注解驅動 -->
          <mvc:annotation-driven/>
          <!-- 2.靜態資源默認 servlet 配置-->
          <mvc:default-servlet-handler/>
          <!-- 3.配置 jsp 顯示 ViewResolver 視圖解析器 -->
          <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
              <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
              <property name="prefix" value="/WEB-INF/jsp/"/>
              <property name="suffix" value=".jsp"/>
          </bean>
          <!-- 4.掃描 web 相關的 bean -->
          <context:component-scan base-package="com.locke.controller"/>
      </beans>
      
      1. Spring 配置整合文件:applicationContext.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd">
          <import resource="classpath:spring-dao.xml"/>
          <import resource="classpath:spring-service.xml"/>
          <import resource="classpath:spring-mvc.xml"/>
      </beans>
      
      1. 編寫 BookController
      @Controller
      @RequestMapping("/book")
      public class BookController {
          @Autowired
          @Qualifier("BookServiceImpl")
          private BookService bookService;
      
          // 查詢全部的書籍,并且返回到一個書籍展示頁面
          @RequestMapping("/allBook")
          public String list(Model model) {
              List<Books> list = bookService.queryAllBook();
              model.addAttribute("list", list);
              return "allBook";
          }
      }
      
      1. 編寫首頁 index.jsp
      <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
      <!DOCTYPE HTML>
      <html>
      <head>
          <title>首頁</title>
          <style type="text/css">
              a {
                  text-decoration: none;
                  color: #fdfdfd;
                  font-size: 18px;
              }
      
              h3 {
                  width: 180px;
                  height: 38px;
                  margin: 100px auto;
                  text-align: center;
                  line-height: 38px;
                  background: #0b6c76;
                  border-radius: 4px;
              }
          </style>
      </head>
      <body>
      <h3>
          <a href="${pageContext.request.contextPath}/book/allBook">點擊進入列表頁</a>
      </h3>
      </body>
      </html>
      
      1. 編寫書籍列表 allbook.jsp
      <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>書籍列表</title>
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <!-- 引入 Bootstrap -->
          <link  rel="stylesheet">
      </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">
              <div class="col-md-4 column">
                  <a class="btn btn-primary" href="${pageContext.request.contextPath}/book/toAddBook">新增書籍</a>
                  <a class="btn btn-primary" href="${pageContext.request.contextPath}/book/allBook">顯示全部書籍</a>
              </div>
              <div class="col-md-8 column">
                  <%--class="form-inline" 可以讓組件橫著排版--%>
                  <form class="form-inline" action="${pageContext.request.contextPath}/book/queryBook" method="post" style="float: right">
                      <span style="color: red;font-weight: bold">${error}</span>
                      <input type="text" name="queryBookName" class="form-control" placeholder="輸入查詢書名" required>
                      <input type="submit" value="查詢" class="btn btn-primary">
                  </form>
              </div>
          </div>
          <div class="row clearfix">
              <div class="col-md-12 column">
                  <table class="table table-hover table-striped">
                      <thead>
                      <tr>
                          <th>書籍編號</th>
                          <th>書籍名字</th>
                          <th>書籍數量</th>
                          <th>書籍詳情</th>
                          <th>書籍操作</th>
                      </tr>
                      </thead>
      
                      <tbody>
                      <c:forEach var="book" items="${requestScope.get('list')}">
                          <tr>
                              <td>${book.getBookID()}</td>
                              <td>${book.getBookName()}</td>
                              <td>${book.getBookCounts()}</td>
                              <td>${book.getDetail()}</td>
                              <td>
                                  <%--取出當前 bookID,傳給 toUpdateBook--%>
                                  <a href="${pageContext.request.contextPath}/book/toUpdateBook/${book.getBookID()}">更改</a>
                                  |
                                  <a href="${pageContext.request.contextPath}/book/del/${book.getBookID()}">刪除</a>
                              </td>
                          </tr>
                      </c:forEach>
                      </tbody>
                  </table>
              </div>
          </div>
      </div>
      </body>
      
      1. BookController 類編寫 , 方法二:添加書籍
      // 跳轉到增加書籍頁面
      @RequestMapping("/toAddBook")
      public String toAddPaper() {
          return "addBook";
      }
      
      // 添加書籍的請求
      @RequestMapping("/addBook")
      public String addPaper(Books books) {
          System.out.println(books);
          bookService.addBook(books);
          // 重定向
          return "redirect:/book/allBook";
      }
      
      1. 添加書籍頁面:addBook.jsp
      <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>新增書籍</title>
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <!-- 引入 Bootstrap -->
          <link  rel="stylesheet">
      </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>
          <form action="${pageContext.request.contextPath}/book/addBook" method="post">
              <%--required 表示此字段不可以為空--%>
              書籍名稱:<input type="text" name="bookName" required><br><br><br>
              書籍數量:<input type="text" name="bookCounts" required><br><br><br>
              書籍詳情:<input type="text" name="detail" required><br><br><br>
              <input type="submit" value="添加">
          </form>
      </div>
      
      1. BookController 類編寫 , 方法三:修改書籍
      // 跳轉到修改頁面
      @RequestMapping("/toUpdateBook/{bookId}")
      public String toUpdateBook(Model model, @PathVariable("bookId") int id) {
          Books books = bookService.queryBookById(id);
          System.out.println(books);
          model.addAttribute("book", books);
          return "updateBook";
      }
      
      // 修改書籍
      @RequestMapping("/updateBook")
      public String updateBook(Model model, Books book) {
          System.out.println(book);
          // 調業務層去修改
          bookService.updateBook(book);
          Books books = bookService.queryBookById(book.getBookID());
          model.addAttribute("books", books);
          return "redirect:/book/allBook";
      }
      
      1. 修改書籍頁面:updateBook.jsp
      <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>修改信息</title>
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <!-- 引入 Bootstrap -->
          <link  rel="stylesheet">
      </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>
          <form action="${pageContext.request.contextPath}/book/updateBook" method="post">
              <%--出現問題:我們提交了修改的 SQL 請求,但是修改失敗,初次考慮是事務問題,但配置完事務后依舊失敗--%>
              <%--看一下 SQL 語句能否執行成功,SQL 執行失敗,修改未完成--%>
              <%--前端傳遞隱藏域--%>
              書籍名稱:<input type="text" name="bookName" value="${book.bookName}" required/><br><br><br>
              書籍數量:<input type="text" name="bookCounts" value="${book.bookCounts}" required/><br><br><br>
              書籍詳情:<input type="text" name="detail" value="${book.detail}" required/><br><br><br>
              <input type="submit" value="提交"/>
              <input type="hidden" name="bookID" value="${book.bookID}"/><br><br><br>
          </form>
      </div>
      
      1. BookController 類編寫 , 方法四:刪除書籍
      // 刪除書籍
      @RequestMapping("/del/{bookId}")
      public String deleteBook(@PathVariable("bookId") int id) {
          bookService.deleteBookById(id);
          return "redirect:/book/allBook";
      }
      
      1. 配置 Tomcat 運行

      注意:如果遇到啟動過濾器異常的問題(被它坑了好久),去項目結構 \(\to\) 工件 中添加和 class 同級別的文件夾 lib,并導入相應的 library。

      如果遇到問題:bean 不存在

      1. 查看這個 bean 注入是否成功
      2. Junit 單元測試,看我們的代碼是否能夠查詢出來結果
      3. 問題一定不在我們的底層,是 spring 出了問題
      4. SpringMVC 整合的時候沒調到我們的 service 層的 bean
        1. applicationContext.xml 沒有注入 bean
        2. web.xml 中,我們也綁定過配置文件:發現問題,我們配置的是 Spring-mvc.xml,這里面確實沒有 service bean,所以報錯

      整個項目的結構圖如下:

      img

      SSM 框架的重要程度是不言而喻的,學到這里,大家已經可以進行基本網站的單獨開發,但這只是增刪改查的基本操作,還遠遠不夠。

      實現查詢書籍功能

      1. 前端頁面增加一個輸入框和查詢按鈕
      <div class="col-md-8 column">
          <%--class="form-inline" 可以讓組件橫著排版--%>
          <form class="form-inline" action="${pageContext.request.contextPath}/book/queryBook" method="post"
                    style="float: right">
              <span style="color: red;font-weight: bold">${error}</span>
              <input type="text" name="queryBookName" class="form-control" placeholder="輸入查詢書名" required>
              <input type="submit" value="查詢" class="btn btn-primary">
          </form>
      </div>
      
      1. 編寫查詢的 Controller
      // 查詢
      @RequestMapping("/queryBook")
      public String queryBook(String queryBookName, Model model) {
          System.out.println("要查詢的書籍:" + queryBookName);
          // 業務邏輯還沒有寫
          return "allBook";
      }
      
      1. 搞定底層代碼

        1. Mapper 接口
        //根據 id 查詢, 返回一個 Book
        Books queryBookByName(String bookName);
        
        1. Mapper.xml
        <!--根據書名查詢, 返回一個 Book-->
        <select id="queryBookByName" resultType="Books">
            select * from ssmbuild.books
            where bookName = #{bookName}
        </select>
        
        1. Service 接口
        // 根據 id 查詢, 返回一個 Book
        Books queryBookByName(String bookName);
        
        1. Service 實現類
        public Books queryBookByName(String bookName) {
            return bookMapper.queryBookByName(bookName);
        }
        
        1. 完善 Controller
        // 查詢
        @RequestMapping("/queryBook")
        public String queryBook(String queryBookName, Model model) {
            System.err.println("要查詢的書籍:" + queryBookName);
            Books books = bookService.queryBookByName(queryBookName);
            List<Books> list = new ArrayList<Books>();
            list.add(books);
            // 如果查詢為空,返回全部的書籍
            if (books == null) {
                list = bookService.queryAllBook();
                model.addAttribute("error", "所查詢書籍不在數據庫中,請重新輸入!");
            }
        
            model.addAttribute("list", list);
            return "allBook";
        }
        

      Ajax

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

      • Ajax 是一種無需重新加載整個網頁的情況下,能夠更新部分網頁的技術。
      • Google Suggest 使用 Ajax 創造出動態性極強的 web 界面:當您在谷歌的搜索框輸入關鍵字時,JavaScript 會把這些字符發送到服務器,然后服務器會返回一個搜索建議的列表。
      • 傳統的網頁想要更新內容或者提交一個表單,都需要重新加載整個網頁;
      • 使用 Ajax 技術的網頁,通過在后臺服務器進行少量的數據交換,就可以實現異步局部更新。
      • 使用 Ajax,用戶可以創建接近本地桌面應用的直接、高可用、更豐富、更動態的 Web 用戶界面。

      利用 AJAX 可以做:

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

      偽造 Ajax

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

      jQuery.ajax

      • Ajax 的核心是 XMLHttpRequest 對象 (XHR)。XHR 為向服務器發送請求和解析服務器響應提供了接口,能夠以異步方式從服務器獲取新數據。
      • jQuery 提供多個與 AJAX 有關的方法。
      • 通過 jQuery AJAX 方法,您能夠使用 HTTP Get 和 HTTP Post 從遠程服務器上請求文本、HTML、XML 或 JSON – 同時您能夠把這些外部數據直接載入網頁的被選元素中。
      • jQuery 不是生產者,而是大自然搬運工。
      • jQuery Ajax 本質就是 XMLHttpRequest,對他進行了封裝,方便調用!
      jQuery.ajax(...)
             部分參數:
                    url:請求地址
                   type:請求方式,GET、POST(1.9.0之后用 method)
                headers:請求頭
                   data:要發送的數據
            contentType:即將發送信息至服務器的內容編碼類型(默認: "application/x-www-form-urlencoded; charset=UTF-8")
                  async:是否異步
                timeout:設置請求超時時間(毫秒)
             beforeSend:發送請求前執行的函數(全局)
               complete:完成之后執行的回調函數(全局)
                success:成功之后執行的回調函數(全局)
                  error:失敗之后執行的回調函數(全局)
                accepts:通過請求頭發送給服務器,告訴服務器當前客戶端課接受的數據類型
               dataType:將服務器端返回的數據轉換成指定類型
                  "xml": 將服務器端返回的內容轉換成xml格式
                 "text": 將服務器端返回的內容轉換成普通文本格式
                 "html": 將服務器端返回的內容轉換成普通文本格式,在插入DOM中時,如果包含JavaScript標簽,則會嘗試去執行。
               "script": 嘗試將返回值當作JavaScript去執行,然后再將服務器端返回的內容轉換成普通文本格式
                 "json": 將服務器端返回的內容轉換成相應的JavaScript對象
                "jsonp": JSONP 格式使用 JSONP 形式調用函數時,如 "myurl?callback=?" jQuery 將自動替換 ? 為正確的函數名,以執行回調函數
      
      1. 配置 web.xml 和 springmvc 的配置文件
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:mvc="http://www.springframework.org/schema/mvc"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd
          http://www.springframework.org/schema/mvc
          https://www.springframework.org/schema/mvc/spring-mvc.xsd">
          <!-- 配置 SpringMVC -->
          <!-- 1.開啟 SpringMVC 注解驅動 -->
          <mvc:annotation-driven/>
          <!-- 2.靜態資源默認 servlet 配置-->
          <mvc:default-servlet-handler/>
          <!-- 3.配置 jsp 顯示 ViewResolver 視圖解析器 -->
          <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
              <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
              <property name="prefix" value="/WEB-INF/jsp/"/>
              <property name="suffix" value=".jsp"/>
          </bean>
          <!-- 4.掃描 web 相關的 bean -->
          <context:component-scan base-package="com.locke.controller"/>
      </beans>
      
      1. 編寫一個 AjaxController
      @Controller
      public class AjaxController {
          @RequestMapping("/a1")
          public void ajax1(String name , HttpServletResponse response) throws IOException {
              if ("admin".equals(name)){
                  response.getWriter().print("true");
              }else{
                  response.getWriter().print("false");
              }
          }
      }
      
      1. 導入 jQuery,可以使用在線的 CDN , 也可以下載導入
      <script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
      <script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.3.js"></script>
      
      1. 編寫 index.jsp
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>$Title$</title>
          <%--<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>--%>
          <script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.3.js"></script>
          <script>
              function a1() {
                  $.post({
                      url: "${pageContext.request.contextPath}/a1",
                      data: {'name': $("#txtName").val()},
                      success: function (data) {
                          alert(data);
                      }
                  });
              }
          </script>
      </head>
      <body>
      <%--onblur:失去焦點觸發事件--%>
      用戶名: <input type="text" id="txtName" onblur="a1()"/>
      </body>
      </html>
      

      啟動 tomcat 測試! 打開瀏覽器的控制臺,當我們鼠標離開輸入框的時候,可以看到發出了一個 ajax 的請求!是后臺返回給我們的結果!測試成功!

      SpringMVC 實現

      1. 實體類 User
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      public class User {
          private String name;
          private int age;
          private String sex;
      }
      
      1. 獲取一個集合對象,展示到前端頁面
      @RequestMapping("/a2")
      public List<User> ajax2(){
          List<User> list = new ArrayList<User>();
          list.add(new User("LK 1 號",1,"女"));
          list.add(new User("LK 2 號",2,"女"));
          list.add(new User("LK 3 號",3,"女"));
          return list; //由于 @RestController 注解,將 list 轉成 json 格式返回
      }
      
      1. 前端頁面
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      <input type="button" id="btn" value="獲取數據"/>
      <table width="80%" align="center">
          <tr>
              <td>姓名</td>
              <td>年齡</td>
              <td>性別</td>
          </tr>
          <tbody id="content">
          </tbody>
      </table>
      <script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.3.js"></script>
      <script>
          $(function () {
              $("#btn").click(function () {
                  $.post("${pageContext.request.contextPath}/a2", function (data) {
                      console.log(data)
                      var html = "";
                      for (var i = 0; i < data.length; i++) {
                          html += "<tr>" +
                              "<td>" + data[i].name + "</td>" +
                              "<td>" + data[i].age + "</td>" +
                              "<td>" + data[i].sex + "</td>" +
                              "</tr>"
                      }
                      $("#content").html(html);
                  });
              })
          })
      </script>
      </body>
      </html>
      

      可以成功實現數據回顯!

      注冊提示效果

      1. 寫一個 Controller
      @RequestMapping("/a3")
      public String ajax3(String name,String pwd){
          String msg = "";
          // 模擬數據庫中存在數據
          if (name!=null){
              if ("admin".equals(name)){
                  msg = "OK";
              }else {
                  msg = "用戶名輸入錯誤";
              }
          }
          if (pwd!=null){
              if ("123456".equals(pwd)){
                  msg = "OK";
              }else {
                  msg = "密碼輸入有誤";
              }
          }
          return msg; //由于 @RestController 注解,將 msg 轉成 json 格式返回
      }
      
      1. 前端頁面 login.jsp
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>ajax</title>
          <script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.3.js"></script>
          <script>
              function a1(){
                  $.post({
                      url:"${pageContext.request.contextPath}/a3",
                      data:{'name':$("#name").val()},
                      success:function (data) {
                          if (data.toString()=='OK'){
                              $("#userInfo").css("color","green");
                          }else {
                              $("#userInfo").css("color","red");
                          }
                          $("#userInfo").html(data);
                      }
                  });
              }
              function a2(){
                  $.post({
                      url:"${pageContext.request.contextPath}/a3",
                      data:{'pwd':$("#pwd").val()},
                      success:function (data) {
                          if (data.toString()=='OK'){
                              $("#pwdInfo").css("color","green");
                          }else {
                              $("#pwdInfo").css("color","red");
                          }
                          $("#pwdInfo").html(data);
                      }
                  });
              }
          </script>
      </head>
      <body>
      <p>
          用戶名:<input type="text" id="name" onblur="a1()"/>
          <span id="userInfo"></span>
      </p>
      <p>
          密碼:<input type="text" id="pwd" onblur="a2()"/>
          <span id="pwdInfo"></span>
      </p>
      </body>
      </html>
      

      記得處理 json 亂碼的問題。

      可以測試一下效果:動態請求響應,局部刷新,就是如此!

      攔截器

      概述

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

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

      • 過濾器
        • servlet 規范中的一部分,任何 java web 工程都可以使用
        • 在 url-pattern 中配置了 /* 之后,可以對所有要訪問的資源進行攔截
      • 攔截器
        • 攔截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能使用
        • 攔截器只會攔截訪問的控制器方法,如果訪問的是 jsp/html/css/image/js 是不會進行攔截的

      自定義攔截器

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

      1. 新建一個 Moudule, springmvc-07-Interceptor, 添加 web 支持
      2. 配置 web.xml 和 springmvc-servlet.xml 文件
      3. 編寫一個攔截器
      package com.locke.interceptor;
      import org.springframework.web.servlet.HandlerInterceptor;
      import org.springframework.web.servlet.ModelAndView;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      public class MyInterceptor implements HandlerInterceptor {
          // 在請求處理的方法之前執行
          // 如果返回 true 執行下一個攔截器
          // 如果返回 false 就不執行下一個攔截器
          public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
              System.out.println("------------處理前------------");
              return true;
          }
          // 在請求處理方法執行之后執行
          public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
              System.out.println("------------處理后------------");
          }
          // 在 dispatcherServlet 處理后執行,做清理工作.
          public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
              System.out.println("------------清理------------");
          }
      }
      
      1. 在 springmvc 的配置文件中配置攔截器
      <!--關于攔截器的配置-->
      <mvc:interceptors>
          <mvc:interceptor>
              <!--/** 包括路徑及其子路徑-->
              <!--/admin/* 攔截的是/admin/add等等這種 , /admin/add/user不會被攔截-->
              <!--/admin/** 攔截的是/admin/下的所有-->
              <mvc:mapping path="/**"/>
              <!--bean配置的就是攔截器-->
              <bean class="com.locke.interceptor.MyInterceptor"/>
          </mvc:interceptor>
      </mvc:interceptors>
      
      1. 編寫一個 Controller,接受請求
      // 測試攔截器的控制器
      @Controller
      public class InterceptorController {
          @RequestMapping("/interceptor")
          @ResponseBody
          public String testFunction() {
              System.out.println("控制器中的方法執行了");
              return "hello";
          }
      }
      
      1. 前端 index.jsp
      <a href="${pageContext.request.contextPath}/interceptor">攔截器測試</a>
      

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

      實現思路

      1. 有一個登陸頁面,需要寫一個 controller 訪問頁面。
      2. 登陸頁面有一提交表單的動作。需要在 controller 中處理。判斷用戶名密碼是否正確。如果正確,向 session 中寫入用戶信息。返回登陸成功。
      3. 攔截用戶請求,判斷用戶是否登陸。如果用戶已經登陸。放行, 如果用戶未登陸,跳轉到登陸頁面

      具體實現

      1. 編寫 login.jsp
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <h1>登錄頁面</h1>
      <hr>
      <body>
      <%--在 web-inf 下的所有頁面或者資源,只能通過 controller 或者 servlet 進行訪問--%>
      <form action="${pageContext.request.contextPath}/user/login">
          用戶名:<input type="text" name="username"> <br>
          密碼: <input type="password" name="pwd"> <br>
          <input type="submit" value="提交">
      </form>
      </body>
      </html>
      
      1. 編寫 Controller
      @Controller
      @RequestMapping("/user")
      public class LoginController {
          // 跳轉到登陸頁面
          @RequestMapping("/jumplogin")
          public String jumpLogin() throws Exception {
              return "login";
          }
      
          // 跳轉到成功頁面
          @RequestMapping("/jumpSuccess")
          public String jumpSuccess() throws Exception {
              return "success";
          }
      
          // 登陸提交
          @RequestMapping("/login")
          public String login(HttpSession session, String username, String pwd) throws Exception {
              // 向 session 記錄用戶身份信息
              System.out.println("接收前端===" + username);
              session.setAttribute("user", username);
              return "success";
          }
      
          // 退出登陸
          @RequestMapping("logout")
          public String logout(HttpSession session) throws Exception {
              // session 過期
              session.invalidate();
              return "login";
          }
      }
      
      1. 編寫登錄成功的頁面 success.jsp
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
          <h1>登錄成功頁面</h1>
          <hr>
          ${user}
          <a href="${pageContext.request.contextPath}/user/logout">注銷</a>
      </body>
      </html>
      
      1. 在 index 頁面上測試跳轉!啟動 Tomcat 測試,未登錄也可以進入主頁
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
        <head>
          <title>$Title$</title>
        </head>
        <body>
        <h1>首頁</h1>
        <hr>
        <%--登錄--%>
        <a href="${pageContext.request.contextPath}/user/jumplogin">登錄</a>
        <a href="${pageContext.request.contextPath}/user/jumpSuccess">成功頁面</a>
        </body>
      </html>
      
      1. 編寫用戶登錄攔截器
      public class LoginInterceptor implements HandlerInterceptor {
          public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
              // 如果是登陸頁面則放行
              System.out.println("uri: " + request.getRequestURI());
              if (request.getRequestURI().contains("login")) {
                  return true;
              }
              HttpSession session = request.getSession();
              // 如果用戶已登陸也放行
              if (session.getAttribute("user") != null) {
                  return true;
              }
              // 用戶沒有登陸跳轉到登陸頁面
              request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
              return false;
          }
      
          public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
          }
      
          public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
          }
      }
      
      1. 在 SpringMVC 的配置文件中注冊攔截器
      <!--關于攔截器的配置-->
      <mvc:interceptors>
          <mvc:interceptor>
              <mvc:mapping path="/**"/>
              <bean id="loginInterceptor" class="com.locke.interceptor.LoginInterceptor"/>
          </mvc:interceptor>
      </mvc:interceptors>
      

      再次重啟 Tomcat 測試!會發現點擊成功頁面按鈕后不會跳轉到登錄成功頁面,而是跳轉到登錄頁面!這就是攔截器!

      文件上傳和下載

      文件上傳是項目開發中最常見的功能之一,springMVC 可以很好的支持文件上傳,但是 SpringMVC 上下文中默認沒有裝配 MultipartResolver,因此默認情況下其不能處理文件上傳工作。如果想使用 Spring 的文件上傳功能,則需要在上下文中配置 MultipartResolver。

      前端表單要求:為了能上傳文件,必須將表單的 method 設置為 POST,并將 enctype 設置為 multipart/form-data。只有在這樣的情況下,瀏覽器才會把用戶選擇的文件以二進制數據發送給服務器;

      文件上傳

      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>
      
      1. 配置 bean:multipartResolver
      <!--文件上傳配置-->
      <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>
      

      注意?。?!這個 bena 的 id 必須為:multipartResolver , 否則上傳文件會報 400 的錯誤!

      CommonsMultipartFile 的 常用方法:

      • String getOriginalFilename():獲取上傳文件的原名
      • InputStream getInputStream():獲取文件流
      • void transferTo(File dest):將上傳文件保存到一個目錄文件中
      1. 編寫前端頁面
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>$Title$</title>
      </head>
      <body>
          <form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
              <input type="file" name="file"/>
              <input type="submit" value="upload">
          </form>
      </body>
      </html>
      
      1. Controller
      import java.io.*;
      
      // 注意 RestController 和 Controller 之間的區別
      @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);
      
              // 上傳路徑保存設置:在 out/artifacts/項目/upload 中找到
              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";
          }
      }
      
      1. 測試上傳文件,OK

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

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

      文件下載

      文件下載步驟:

      1. 設置 response 響應頭
      2. 讀取文件:InputStream
      3. 寫出文件:OutputStream
      4. 執行操作
      5. 關閉流:先開后關

      代碼實現:

      @RequestMapping(value = "/download")
      public String downloads(HttpServletResponse response, HttpServletRequest request) throws Exception {
          // 要下載的圖片地址
          String path = request.getServletContext().getRealPath("/upload");
          String fileName = "IEEE 投稿樣式對照.pdf";
          // 1. 設置 response 響應頭
          response.reset(); // 設置頁面不緩存,清空 buffer
          response.setCharacterEncoding("UTF-8"); // 字符編碼
          response.setContentType("multipart/form-data"); // 二進制傳輸數據
          // 設置響應頭
          response.setHeader("Content-Disposition",
                             "attachment;fileName=" + URLEncoder.encode(fileName, "UTF-8"));
          File file = new File(path, fileName);
          // 2. 讀取文件--輸入流
          InputStream input = new FileInputStream(file);
          // 3. 寫出文件--輸出流
          OutputStream out = response.getOutputStream();
          byte[] buff = new byte[1024];
          int index = 0;
          // 4. 執行 寫出操作
          while ((index = input.read(buff)) != -1) {
              out.write(buff, 0, index);
              out.flush();
          }
          out.close();
          input.close();
          return null;
      }
      

      前端:

      <a href="/download">點擊下載</a>
      
      posted @ 2024-02-10 23:15  Lockegogo  閱讀(482)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产超高清麻豆精品传媒麻豆精品| 国产91色综合久久高清| 无码AV无码免费一区二区| 国产成AV人片久青草影院| 18分钟处破好疼哭视频在线观看| 久久人人妻人人爽人人爽| 日韩人妻一区中文字幕| 中文字幕日韩国产精品| 精品一区二区三区四区五区| 波多野结衣免费一区视频| 在线观看无码av五月花| 精品国产污污免费网站入口| 熟女精品色一区二区三区| 亚洲AV蜜桃永久无码精品 | 农村老熟女一区二区三区| 亚洲AV日韩AV永久无码下载| 夜夜躁狠狠躁日日躁| 欧美男男作爱videos可播放| 美乳丰满人妻无码视频| 国产成人一区二区三区影院动漫| 国产亚洲精品久久久久秋霞| 91色老久久精品偷偷性色| 少妇高潮喷潮久久久影院| 亚洲国产精品综合久久2007| 麻豆精品一区二区综合av| 亚洲精品一区二区二三区| 亚洲av无码成人精品区一区| 思热99re视热频这里只精品| 免费观看激色视频网站| 九九电影网午夜理论片| 在线涩涩免费观看国产精品| 亚洲日韩国产二区无码| 免费av深夜在线观看| 鲁大师在线视频播放免费观看| 最新亚洲av日韩av二区| 久青草国产在视频在线观看| 欧美人与zoxxxx另类| 久热这里只有精品视频3| 精品中文字幕人妻一二| 狠狠色丁香婷婷综合尤物| 国产自拍偷拍视频在线观看|