1. 程式人生 > >SpringMVC(一)框架設計及流程

SpringMVC(一)框架設計及流程

Spring MVC(一)框架設計及流程

SpringMVC框架設計

框架設計圖如下
在這裡插入圖片描述

上圖是SpringMVC框架執行的流程。處理請求先到達控制器(Controller),控制器的作用是進行請求轉發,這樣它會根據請求的內容去訪問模型層(Model);在現今網際網路體系中,資料主要從資料庫和NoSQL中來,而且對於資料庫而言往往還存在事務的機制,為了適應這樣的變化,設計者會把模型層再細分為兩層,即服務層(Service)和資料訪問層(DAO);當控制器獲取到由模型層返回的資料後,將資料渲染到檢視中,這樣就能夠展示給使用者了。

SpringMVC流程

流程圖

流程圖

流程和元件是SpringMVC的核心。

SpringMVC的流程都是圍繞著DispatcherServlet而工作的。嚴格來說,springMVC處理請求並非一定需要經過全流程,有時候一些流程並不存在,比如我們加入@ResponseBody註解時,是沒有經過檢視解析器和檢視渲染的,關於這個後面會討論到。

首先,在Web伺服器啟動的過程中,如果在Spring Boot的機制下啟用SpirngMVC,它就開始初始化一些重要元件,如DispactherServlertHandlerAdatper的實現類RequestMappingHandlerAdatper等物件元件。關於元件的初始化,我們在spring-webmvc-xxx.jar

包的屬性檔案DispatcherServler.properties,它定義的物件都是在SpringMVC開始時就初始化,並且存放在SpringIoC容器中。其原始碼如下

DispatcherServler.properties原始碼

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

#國際化解析器
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

#主題解析器
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

# HandlerMapping例項
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

#處理器介面卡
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

#處理器異常解析器
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

#策略檢視名稱轉換器,當沒有返回檢視邏輯名稱的時候,通過它可以生成預設的檢視名稱
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

#檢視解析器
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

#FlashMap管理器,不常用
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

這些元件會在SpringMVC得到初始化,所以我們並不需要太多的配置就能夠開發SpringMVC程式。

普通檢視

定義控制器

@RequestMapping(value = "/person")
@Controller
public class PersonController {

    //注入使用者服務類
    @Autowired
    PersonService personService;
	
 	//展示人員詳情
    @RequestMapping("/details")
    public ModelAndView details(Long id) {
        //訪問模型層得到資料
        Person perosn = personService.getPerson(id);
        //模型和檢視
        ModelAndView mv = new ModelAndView();
        //定義模型檢視
        mv.setViewName("person/details");
        //加入資料模型
        mv.addObject("person", perosn);
        //返回檢視
        return mv;
    }
}

@Controller:表明這是一個控制器

@RequestMapping:代表請求路徑和控制器(或方法)的對映關係,它會在Web服務啟動SpringMVC的時,就被掃描到HandlerMapping的機制中儲存,之後再使用者發起請求被DispatcherServlert攔截後,通過URI和其他的條件,通過HandlerMapper機制就能夠找到對應的控制器或其方法進行響應。只是通過HandlerMapping返回的是一個HandlerExecutionChain物件,原始碼如下

HandlerExecutionChain原始碼

 public class HandlerExecutionChain {
    //日誌
    private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
    //處理器
    private final Object handler;
    //攔截器陣列
    @Nullable
    private HandlerInterceptor[] interceptors;
    //攔截器列表
    @Nullable
    private List<HandlerInterceptor> interceptorList;
    //攔截器當前下標
    private int interceptorIndex;
    //....
}

HandlerExecutionChain物件包含一個處理器(handler)。這裡的處理器就是對控制器(controller)的包裝。因為我們的控制器方法可能存在引數,那麼處理器就可以讀入http和上下文的相關引數,然後再傳遞給控制器方法。而在控制器執行完成返回後,處理器又可以通過配置資訊和對控制器的返回結果進行處理。可以看出,處理器包含了控制器方法的邏輯,此外還有處理器的攔截器(interceptor),這樣就能夠通過攔截處理器進一步增強處理器的功能。

得到了處理器(handler)。還需要去執行,但是我們有普通的http請求,也有按BeanName的請求,設定是WebSocket的請求,所以它還需要一個介面卡去執行HandlerExecutionChain物件包含的處理器,這就是HandlerAdapter介面定義的實現類。從原始碼中可以看到SpringMVC中最常用的HandlerAdapter的實現類,便是HttpRequestHandlerAdapter。通過請求的型別,DispatcherServlet就會找到它來執行Web請求的HandlerExecutionChain物件包含的內容,這樣就能夠執行我們的處理器(handler)了。

在處理器呼叫控制器時,它首先通過模型層得到資料,再放入資料模型中,最後將返回模型和檢視物件(ModelAndView),這裡控制器設定的檢視名稱設定為"person/details"這樣就走到了檢視解析器(ViewResolver),去解析檢視邏輯名稱了。

SpringMVC的ViewResolver的實現類是InternalResourceViewResolver,為了定製,我們可以在application.properties檔案中進行配置

spring.mvc.view.prefix=/
spring.mvc.view.suffix=.html

通過這樣的配置,就能能在Spring Boot機制下定織InternalResouceViwResolver這個檢視解析器的初始化,也就是在返回檢視名稱之後,它會以字首(prefix)和字尾(suffix)以及檢視的名稱組成全路徑定位檢視。例如,在控制器返回的"person/details",這裡字首為/,等於spring boot預設路徑"/src/main/resources/templates",那麼它就會找到"/src/main/resources/templates/person.html"作為檢視。

檢視解析器定位到檢視後,檢視的作用是將資料模型(Model)渲染,這樣就能夠響應資料的請求。這一步就是檢視將資料模型渲染(View)出來,用來展示給使用者看。

/person/details.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <meta charset="UTF-8">
    <title>使用者詳情</title>
</head>
<body>
<center>
    <table border="1">
        <tr>
            <td>標籤</td>
            <td></td>
        </tr>
        <tr>
            <td>使用者編號</td>
            <td th:text="${person.id}"></td>
        </tr>
        <tr>
            <td>使用者名稱稱</td>
            <td th:text="${person.personName}"></td>
        </tr>
        <tr>
            <td>使用者備註</td>
            <td th:text="${person.note}"></td>
        </tr>
    </table>
</center>

</body>
</html>

這裡因為我們的控制器裡繫結資料模型的時候,屬性名稱為person,而屬性為person物件,所以就有了${person.id}代表perosn物件的id屬性,其餘屬性是一樣的。

流程如下

例項流程

JSON檢視

有時候我們需要的只是JSON資料集,因為目前前後臺分離的趨勢,使用JSON已經是主流的方式。正如@ResponseBody註解表明方法一樣,springMVC會把資料轉換為JSON資料集,但是這裡不談@ResponseBody,因為它會採用處理器內部的機制。這裡先用MappingJackson2JsonView轉換出JSON。


    //使用json檢視
    @RequestMapping("/detailsForJson")
    public ModelAndView detailsForJson(Long id) {
        Person person = personService.getPerson(id);
        ModelAndView mv = new ModelAndView();
        MappingJackson2JsonView jsonView = new MappingJackson2JsonView();
        mv.setView(jsonView);
        mv.addObject("person", person);
        return mv;
    }

其流程如下
SpringMVC全流程使用JSON檢視
流程中我們可以看到並沒有檢視解析器,是因為MappingJackson2JsonView是一個非邏輯檢視。它不需要檢視解析器進行定位,它的作用只是將資料模型渲染為JSON資料集來響應請求。