05、spring

項羽齊發表於2018-03-27

     

Spring MVC

 

1. Spring MVC 概述 1-2

1.1. 企業級應用基本架構 1-2

1.2. Web MVC架構及分析 1-3

1.3. Spring MVC 架構及分析 1-4

2. Spring MVC 程式設計基礎 2-5

2.1. 程式設計基本步驟 2-5

2.2. 基於xml程式設計實現 2-5

2.2.1. 建立Maven WEB 專案 2-5

2.2.2. 新增Spring MVC 專案依賴及配置檔案 2-5

2.2.3. 配置前端控制器 2-7

2.2.4. 建立後端控制器 2-7

2.2.5. 建立JSP頁面 2-8

2.2.6. 配置後端控制及檢視解析 2-8

2.2.7. 部署到tomcat執行 2-9

2.2.8. 執行原理分析 2-9

2.3. 基於註解程式設計實現 2-10

2.3.1. 建立Maven WEB 專案 2-10

2.3.2. 新增Spring MVC 專案依賴及配置檔案 2-10

2.3.3. 配置前端控制器 2-11

2.3.4. 建立後端控制器 2-12

2.3.5. 配置元件掃描與檢視解析 2-12

2.3.6. 部署與執行 2-12

3. Spring MVC 程式設計請求處理進階 3-13

3.1. 請求路徑對映 3-13

3.1.1. 普通url對映 3-13

3.1.2. Rest風格url對映 3-13

3.2. 請求方式對映 3-14

3.2.1. 請求方式限定 3-14

3.2.2. 請求方式組合 3-14

3.3. 請求引數對映(重點) 3-14

3.3.1. 標準Servlet API 3-14

3.3.2. 直接量儲存 3-15

3.3.3. Java bean物件 3-15

3.3.4. Rest url資料 3-16

3.3.5. 請求頭資料 3-16

4. Spring MVC 響應處理進階 4-17

4.1. 響應資料封裝 4-17

4.1.1. ModelAndView 物件 4-17

4.1.2. Model物件 4-17

4.1.3. Map物件 4-18

4.2. 響應資料轉換JSON 4-18

4.2.1. JSON 應用概述 4-18

4.2.2. 客戶端JSON資料操作 4-19

4.2.3. JAVAJSON資料操作 4-19

4.2.4. Spring 整合jackson 4-23

4.2.5. Spring 整合fastjson 4-24

5. Spring 攔截器應用 5-25

5.1. 攔截器概述 5-25

5.2. 攔截器編寫及配置 5-26

6. Spring MVC異常處理 6-28

6.1. Spring MVC 異常概述 6-28

6.2. Spring MVC 異常處理 6-29

7. 總結 7-29

7.1. 重點和難點分析 7-29

7.2. 常見FAQ 7-30

7.3. 作業 7-30

 

1. Spring MVC 概述

  1.1. 企業級應用基本架構

    企業級應用基本架構(C/S)以及SPRING在架構中的作用。

 

    此架構圖中spring要解決什麼問題?

      1) 物件的構建,物件的依賴管理。(重點是從資源使用角度進行分析)

      2) 擴充套件業務的動態切入。(基於OCP更好實現功能擴充套件,同時進行解耦)

      3) 簡化傳統web mvc架構中的一些細節處理問題(引數獲取,校驗,值的注入,響應方式及資料格式的轉換)。

 

    問題:

      1)我們一般說的解耦是沒有耦合嗎?不是,所有軟體系統中的物件之間都會存在耦合,只是要把耦合降低。

      2) 降低耦合的最主要目的是什麼?就是要提高系統的可維護性,便於系統進行更好的升級擴充套件。

      3) 降低耦合的主要實現方式?

      3.1)物件之間的耦合儘量耦合與介面與工廠

      3.2)程式碼的重用盡量使用組合而非繼承。(has a 取代 is a

 

  1.2. Web MVC架構及分析

      基於servletjspjavabean技術實現的MVC架構

     

 

     問題:

      1) 假如我們沒有使用spring mvc,你如何對系統採用mvc思想進行分層?(參考jsp+servlet+javabean奇數)

       2) 傳統的web mvc 程式設計架構中有什麼優勢,劣勢?

        優勢:結構層次更加清晰,可讀性,可維護性相對較好

        劣勢:引數獲取,型別轉換,流程呼叫相對都比較複雜

       3)市場上相對比較成熟的mvc框架:spring mvcstruts2,….

  1.3. Spring MVC 架構及分析

       Spring MVC是MVC架構模式的一種完美實現,它簡化了Java WEB 中基於MVC架構的程式設計過程,是Spring中的WEB應用模組。其官方MVC概要架構圖如下:

     

 

 

 

    Spring MVC 底層核心架構圖及工作流程(先了解,寫完專案案例再重點強化)

 

  Spring MVC 中的核心元件:

    1) DispatcherServlet (前端控制器, 處理請求的入口)

    2) HandlerMapping (對映器物件, 用於管理url與對應controller的對映關係)

    3) Controller (後端控制器, 負責處理請求的控制邏輯)

    4) ModelAndView (模型, 封裝業務處理結果和檢視)

    5) ViewResolver(檢視解析器,解析對應的檢視關係:字首+view+字尾)

 

    備註:假如希望瞭解Spring MVC的詳細處理流程可以基於斷點除錯法進行跟蹤。

2. Spring MVC 程式設計基礎

  2.1. 程式設計基本步驟

 

    Step01:建立maven web 專案並解決專案中的錯誤問題

    Step02:新增專案依賴(spring-webmvc)及spring核心配置檔案

    Step03:配置前端控制器DispatcherServletweb.xml

    Step04:建立後端控制器(Controller)及頁面

    Step05spring配置檔案中配置核心應用元件

    Step06:部署及測試springmvc 應用。

 

  2.2. 基於xml程式設計實現

    2.2.1. 建立Maven WEB 專案

      Web專案打包方式為war方式

      Web專案的target runtimestomcat

      Web 專案的編譯版本為JDK1.8

 

    可能會遇到的問題:

      1) war專案預設不會建立web.xml(需要自己生成)

      2) 專案建立好需要設定執行時環境tomcat(多個tomcat時選哪個)

      3) 統一編譯版本(版本不統一很有可能會出現專案不編譯)

      4) 統一編碼(UTF-8)

      5) 假如建立的專案還有問題,可對專案進行clean操作

 

2.2.2. 新增Spring MVC 專案依賴及配置檔案

開啟專案的pom.xml檔案,然後新增依賴(選擇組groupIdorg.springframework

 

<dependencies>
<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.3.9.RELEASE</version>
</dependency>
<dependencies>

 

 

假如新增好了依賴,都沒有找到對應的jar依賴,先檢測網路是否是通的.假如網路是通的,還沒有下載到具體的依賴,此時要右鍵專案,選擇maven/upate maven project/fore update…進行maven強制更新操作.

 

在專案的resource的目錄中新增核心配置檔案applicationContext.xml,例如:

 

<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true"
    xmlns="http://www.springframework.org/schema/beans" 
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xsi:schemaLocation="  
       http://www.springframework.org/schema/beans   
       http://www.springframework.org/schema/beans/spring-beans-4.3.xsd  
       http://www.springframework.org/schema/mvc   
       http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd   
       http://www.springframework.org/schema/tx   
       http://www.springframework.org/schema/tx/spring-tx-4.3.xsd   
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
       http://www.springframework.org/schema/util 
       http://www.springframework.org/schema/util/spring-util-4.3.xsd
       http://www.springframework.org/schema/data/jpa 
       http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.3.xsd" >
       
</beans>

 

    說明:配置檔案的名字需要自己定義,當這個空的配置檔案中的某行有相關錯誤

    時,先去檢測網路是不是通的。

 

  2.2.3. 配置前端控制器

    開啟web.xml,配置DispatcherServlet物件

<servlet>
     <servlet-name>dispatcherServlet</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>dispatcherServlet</servlet-name>
     <url-pattern>*.do</url-pattern>
  </servlet-mapping>

 

  前端控制器是spring mvc處理請求的入口,是springmvc的核心,這個控制器一般需要在伺服器啟動時即初始化。

    其中

      1) load-on-startup 表示啟動時則載入此servlet

      2) init-param 中的引數名不能變(此名字在DispatcherServlet父類中定義)

 

 

 

    2.2.4. 建立後端控制器

      後端控制器編寫時可以實現Controller介面,然後重寫handleRequest方法處理請求

      public class HelloController implements Controller{}

 

      其中:

        ModelAndView物件為一個模型與檢視物件,內建一個map物件,主要用於封裝業務資料和檢視名。

        ModelAndView構造方法中傳遞的為檢視名,addObject方法可以以key/value形式儲存資料。

        ModelAndView 物件返回時會被spring mvc自動儲存到請求作用域,在對應的檢視頁面可以直接從此作用域獲取對應的值。

 

    2.2.5. 建立JSP頁面

 

      在專案的WEB-INF/pages資料夾下建立hello.jsp檔案,然後設定其內容,例如

 

    2.2.6. 配置後端控制及檢視解析

      在spring mvc 核心配置檔案中添如下配置。

 

<!-- 將Controller這個Bean物件交給Spring管理 -->
<bean id="helloController" class="spring.controller.XmlHelloController">
</bean>
<!-- 配置HandlerMapping 對映處理器配置url到具體的Controller之間的對映-->
 <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
             <property name="mappings">
                  <props>
                      <prop key="/hello.do">helloController</prop>
                  </props>
             </property>
  </bean>
  <!-- 配置檢視解析器 -->
 <bean  id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/pages/"/>
            <property name="suffix" value=".jsp"/>
</bean>

 

 

    2.2.7. 部署到tomcat執行

      將專案部署到tomcat,然後啟動執行,在位址列輸入具體url訪問對應controller

 

      問題:

        1) tomcat啟動時出現ClassNotFoundException,而這個class又不是我們自己的類,此時要重新maven update,重新發布(右鍵tomcat 重新publish),多次嘗試還是不可以,此時重啟eclipse

        2) 404異常,一般表示服務端資源沒找到,首先檢測訪問路徑是否正確,然後還可以在專案的部署目錄中去查詢對應的資源,必須確保資源是存在的,假如資源不存在,說明程式碼沒有正常編譯。(很常見)

        3) 如何解決這種專案不編譯的問題?

 

        step01) tomcat下的專案移除,clean你的tomcat伺服器

        step02) 將專案的jrebuildpath移除,然後重新新增

        step03) 對專案先進行maven clean操作(清除原先編譯結構,然後重新編譯)

        step04) 再次對專案進行clean操作

        step05) 重新部署專案,啟動tomcat執行

 

      4) 執行專案時儘量不要右鍵執行選在run as /run on server

 

    2.2.8. 執行原理分析

      本應用的簡易處理流程如下:

       

 

 

 

 

4.2. 響應資料轉換JSON

4.2.1. JSON 應用概述

JSON(JavaScript Object Notation):一種輕量級資料交換格式,通常用於實現客戶端與服務端之間的資料傳輸.

企業級Java專案資料傳輸方式:

 

 

 

 

5. Spring 攔截器應用

 

  5.1. 攔截器概述

    攔截器SpringMVC中的一個核心應用元件,主要用於處理多個Controller的共性問題.當我們的請求由DispatcherServlet派發到具體Controller之前首先要執行攔截器中一些相關方法,在這些方法中可以對請求進行相應預處理(例如許可權檢測,引數驗證),這些方法可以決定對這個請求進行攔截還是放行.通過spring mvc 架構圖分析,攔截器在Spring MVC中處理流程中的一個位置

 

    回顧Spring MVC詳細架構圖

 

     

 

 

  思考:假如對請求資料進行編碼,是應在過濾器還是攔截器?

 

  5.2. 攔截器編寫及配置

     攔截器如何編寫?

     我們自己編寫Spring MVC攔截器需要實現HandlerInterceptor介面或者繼承此介面的實現類 HandlerInterceptorAdapter(繼承這個類時可根據需求重寫必要的方法)

 

public class SysUserInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(
            HttpServletRequest request,
            HttpServletResponse response, Object handler)
            throws Exception {
            System.out.println("preHandle");
        return true;//表示放行
    }
    @Override
    public void postHandle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler,
            ModelAndView modelAndView) 
            throws Exception {
            System.out.println("postHandler"
                + ".modelAndView="+modelAndView);
    }
    @Override
    public void afterCompletion(
            HttpServletRequest request,
            HttpServletResponse response, 
            Object handler,
            Exception ex)
            throws Exception {
             System.out.println("afterCompletion.handler="+
            handler.getClass());
    }
}

 

 

這些方法的簡易執行流程點如下圖所示:

 

 

這些方法的詳細的執行時間點如下:

 

 

 

 

我們自己的攔截器編寫完成以後需要在spring配置檔案中進行配置,,

例如:

<mvc:interceptors>
           <mvc:interceptor>
             <!-- 指定攔截哪些請求路徑 -->
             <mvc:mapping path="/**"/>
             <!-- 排除要攔截的路徑 -->
             <mvc:exclude-mapping path="/sys/doLogin.do"/>
             <!-- 攔截器 -->
             <bean class="cn.spring.mvc.interceptor.SysUserInterceptor"/>
           </mvc:interceptor>
</mvc:interceptors>

 

    當我們系統中有多個攔截器時,這些攔截器可以構一個攔截器鏈.其原理類似過濾器中的過濾鏈。在多個攔截器應用中僅當所有匹配的攔截器的preHandle()都執行之後,才會呼叫Controller中處理請求的方法,然後再執行所有匹配的攔截器的postHandler(),再執行所有匹配的攔截器的afterCompletion()

 

    在攔截器鏈中,各攔截器的執行先後順序取決於配置檔案中配置的節點的先後順序!

 

6. Spring MVC異常處理

   6.1. Spring MVC 異常概述

    實際專案中我們經常會採用分層架構設計程式,每一層都可能會有異常,假如異常資訊沒有處理,可能會選擇丟擲,假如這些被丟擲的異常與具體業務相關,那到控制層以後我們一般都進行相應的處理(處理方式應該相對友好)

 

    在Spring mvc 專案,邊界出現異常以後我們通常會在Controller中進行處理,常用層架構中的異常分析:

     在分層架構中,異常可能會從DAO層逐步丟擲到控制層,可以在控制層對異常進行相關處理。

 

6.2. Spring MVC 異常處理

 

 

   在spring中處理異常時,通常會在Controller中定義具體的異常處理方法,這個方法上使用@HandlerException註解進行描述.例如在指定Controller中定義異常處理方法:

@ExceptionHandler(value=Exception.class)
@ResponseBody
public String handleException(Exception e){
    System.out.println("區域性異常處理");
    return e.getMessage();
}

 

 

 

當Springcontroller中沒有定義具體的異常方法,我們外部定義一個全域性的異常處理類,這個使用@ControllerAdvice註解進行修飾.然後在這個中定義具體的異常處理方法,這些方法再使用@HandlerExcpeiton進行修飾,例如

@ControllerAdvice
public class AdviceExceptionHandler {
    @ExceptionHandler(Throwable.class)
    @ResponseBody
    public String handlerException(Throwable e){
        System.out.println("全域性的異常處理");
        return e.getMessage();
    }
}

 

 

 

1. Spring MVC 檔案上傳

  1.1. 檔案上傳業務場景

    在電子商務系統中具體商品採用圖片方式進行描述,這個圖片需要上傳到伺服器等等。

 

  1.2. Spring MVC 檔案上傳基本步驟

    Step01: 新增檔案上傳相關依賴jarcommons-fileupload

    Step02: 配置對上傳檔案物件的解析(spring的核心配置檔案)

    Step03: 編寫檔案上傳表單(請求方式post,enctype必須multipart/form-data)

    Step04: 編寫對應的控制層物件處理檔案上傳(通過mutilpartFile引數接收檔案)

 

  1.2.1. 新增依賴

 

<dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>1.3.3</version>
  </dependency>

 

 

1.2.2. 配置物件解析

在spring的核心配置檔案中新增物件解析

<bean id="multipartResolver" 
         class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 配置檔案編碼處理 -->
        <property name="defaultEncoding" value="utf-8"/>
        <!-- 配置檔案大小限制 -->
        <property name="maxUploadSize" value="4096000000"/>
        <!-- 配置記憶體緩衝區大小 -->
        <property name="maxInMemorySize" value="1024000"/>
   </bean>

 

說明:配置物件解析時,beanid一定要指定而且官方規定必須為multipartResolver

 

1.2.3. 定義upload.jsp

WEB-INF/pages目錄下建立一個upload.jsp,然後建立上傳表單

 

 

<body>
   <h1>檔案上傳</h1>
   <h1>${msg}</h1>
   <form action="doUpload.do" 
         method="post"
         enctype="multipart/form-data">
        <input type="file" name="upfile"/>
        <br/>
        <input type="submit" value="upload"> 
   </form>
</body>

 

 

說明定義表單時提交方式必須為postenctype必須為multipart/form-data

 

1.2.4. 定義UploadController

 

@RequestMapping("/upload/")
@Controller
public class UploadController {
       @RequestMapping("uploadUI")
       public String uploadUI(){
           return "upload";
       }
      
       @RequestMapping("doUpload")
       public ModelAndView doUpload(MultipartFile upfile)
                throws IOException{
           //獲取檔名以及檔案大小,檢測是否獲得檔案相關資料
           String fileName=upfile.getOriginalFilename();
           long size=upfile.getSize();
           System.out.println(fileName+"/"+size);
            //構建檔案目標物件,這個物件對應的檔案路徑必須是存在的或者通過file物件自己建立
           File dest=new File("D:/SSMWORK/"+fileName);
           //transferto實現檔案上傳
           upfile.transferTo(dest);
           //封裝資料返回
           ModelAndView mv=new ModelAndView("upload");
           mv.addObject("msg", "upload ok");
           return mv;
       }
}

 

說明:在控制層方法接收請求中file型別的資料時需要藉助MultipartFile 型別引數物件,引數名要求與表單中typefile的引數名相同。