微服務專題02-Spring Web MVC 視圖技術

前言

前面的章節我們講了Spring Application。本節,繼續微服務專題的內容分享,共計16小節,分別是:

  • 微服務專題01-Spring Application
  • 微服務專題02-Spring Web MVC 視圖技術
  • 微服務專題03-REST
  • 微服務專題04-Spring WebFlux 原理
  • 微服務專題05-Spring WebFlux 運用
  • 微服務專題06-雲原生應用(Cloud Native Applications)
  • 微服務專題07-Spring Cloud 配置管理
  • 微服務專題08-Spring Cloud 服務發現
  • 微服務專題09-Spring Cloud 負載均衡
  • 微服務專題10-Spring Cloud 服務熔斷
  • 微服務專題11-Spring Cloud 服務調用
  • 微服務專題12-Spring Cloud Gateway
  • 微服務專題13-Spring Cloud Stream (上)
  • 微服務專題14-Spring Cloud Bus
  • 微服務專題15-Spring Cloud Stream 實現
  • 微服務專題16-Spring Cloud 整體回顧

本節內容重點爲:

  • Thymeleaf 視圖技術:介紹新一代視圖技術 Thymeleaf ,包括其使用場景、實際應用以及技術優勢
  • 視圖解析:介紹 Spring Web MVC 視圖解析的過程和原理、以及內容協調視圖處理器的使用場景
  • 國際化:利用Locale技術,實現視圖內容的國際化

上節回顧

在上一節,主要針對於SpringBoot的main class -> SpringApplication進行了詳細說明,在Spring 註解編程模型我們提到了一個元註解 @Component ,所以這裏我想補充一下Spring關於這個註解的實際應用是怎麼樣的一個流程?

@ComponentScan -> @Confiugration Class -> basePackages -> @Component Beans ->

@ComponentScan掃描帶有 @Confiugration 的類

BeanDefinition -> BeanDefinitionRegistry ->

DI

Beans -> BeanFactory -> getBean or @Autowired

IOC

實際上就是我們所謂的IoC/DI -> 注入Bean後再獲取Bean,現在很多人過分強調IOC/DI,其實沒必要,在IOC/DI背後更核心的內容重要的我們要理解Bean的生命週期

Bean 生命週期

實例化 :Bean Class -> Bean Object

初始化前 -> Bean before/pre init()

  • org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization

初始化 -> init()

  • org.springframework.beans.factory.InitializingBean#afterPropertiesSet()

初始化後

  • org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization()

銷燬

  • org.springframework.beans.factory.DisposableBean#destroy()

主要內容

Thymeleaf 視圖技術

推薦一個開源項目,Spring Boot Starter 支持模板引擎 velocity 以及 velocity tools,該Starter是官方Starter的補充https://github.com/alibaba/velocity-spring-boot-project

渲染上下文(模型) Model

  • Spring Web MVC
    • 接口類型
      • Model
      • ModelMap
      • ModelAndView
        • Model -> ModelMap
        • View
    • 註解類型
      • @ModelAttrtibute

EL 表達式

  • 字符值
  • 多種數據類型
  • 邏輯表達式
    • if else
  • 迭代表達式
    • for each / while
  • 反射
    • Java Reflection
    • CGLib

視圖解析

模板尋址

prefix + view-name + suffix

->
在這裏插入圖片描述

classpath:/templates/thymeleaf/index.dota2
view.setUrl(getPrefix() + viewName + getSuffix())

模板緩存

在這裏插入圖片描述
默認 Cache = true

Cache = false -> 設置緩存時間

Spring MVC 模板渲染邏輯

Spring MVC 核心總控制器 DispatcherServlet

C

DispatcherServlet

M

  • Spring MVC(部分)

    • Model / ModelMap / ModelAndView(Model 部分)
    • @ModelAttribute

在這裏插入圖片描述

  • 模板引擎(通常)

    • 通用的方式

      • 模板上下文
        • 內建/內嵌自己工具變量
    • JSP 內置( built-in )九大變量

所謂內置,指的是通過JSP模板引擎控制的

在這裏插入圖片描述

  • Servlet Scope 上下文(Spring @Scope

    • PageContext(page 變量)
      • 關注當前頁面
      • A forward B
        • A 變量只能 A 頁面使用,不能共享給 B
        • A t 和 B t 可以採用同名變量,同時使用
    • Servlet Request(請求上下文) - WebApplicationContext#SCOPE_REQUEST
      • 關注當前請求
        • A forward B
          • A 請求變量可以用於 B 頁面
    • Servlet Session(會話上下文) - WebApplicationContext#SCOPE_SESSION
      • 關注當前會話
        • A forward / redirect B
          • A 請求變量可以用於 B 頁面
    • Servlet ServletContext(應用上下文) - WebApplicationContext#SCOPE_APPLICATION
      • 關注當前應用
        • 用戶 A 和 用戶 B 會話可以共享
    • JSP 內置變量( JSP = Servlet )
      • out(Writer = ServletResponse#getWriter())
      • exception ( Throwable)
      • config( ServletConfig )
      • page ( Jsp Servlet 對象)
      • response(ServletResponse)
  • Thymeleaf 內置變量

StandardExpressionObjectFactory -> 構建 IExpressionContext

  * 上下文(模型)
  * #strings
  * #numbers
  * ...

以strings內置變量爲例,打一個斷點在:

org.thymeleaf.standard.expression.StandardExpressionObjectFactory#buildObject()

在這裏插入圖片描述
斷點進入到此方法:
在這裏插入圖片描述

同樣的我們也可以自定義內置對象:

   public static class StringUtil {

        public StringUtil() {
        }

        public boolean isNotBlank(String value) {
            return StringUtils.hasText(value);
        }

    }

在頁面上引用:
在這裏插入圖片描述
頁面輸出:
在這裏插入圖片描述

V

  • 視圖對象

    • Servlet

      • RequestDispatcher#forward
      • RequestDispatcher#include
      • HttpServletResponse#sendRedirect
    • Spring MVC

      • View
        • forward:
          • InternalResourceView
        • redirect:
          • RedirectView
    • Struts

      • Action
        • ForwardAction
        • RedirectAction
  • 視圖處理對象

    • Spring MVC

      • 處理流程: *.do -> DispatcherServlet -> Controller -> View -> ViewResolver -> View#render -> HTML -> HttpServletResponse

        • Thymeleaf

          • ViewResolver -> ThymeleafViewResolver
          • View -> ThymeleafView
          • 通過模板名稱解析模板資源(ClassPathResource
            • TemplateResolution
          • 讀取資源,並且渲染內容 HTML
            • IEngineContext
            • ProcessorTemplateHandler
          • HTML 內容輸出到 Response
          • 源碼路徑
            • org.thymeleaf.TemplateEngine#process(org.thymeleaf.TemplateSpec, org.thymeleaf.context.IContext, java.io.Writer)
            • org.thymeleaf.engine.TemplateManager#parseAndProcess
        • JSP

          <bean id="viewResolver" 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>
          
          • ViewResolver ->InternalResourceViewResolver
          • View -> JstlView
            • Foward -> RequestDispatcher
    • Struts

      • 處理流程: *.do -> ActionServlet -> Action -> ForwardAction -> RequestDispatcher -> JSP(Servlet) -> HTML -> HttpServletResponse
        重點內容

學習方法

學會配置代碼

假設需要了解的技術是 thymeleaf -> thymeleaf Properties -> ThymeleafProperties

第一步:找到 @ConfigurationProperties,確認前綴

@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
    
}

比如:“spring.thymeleaf”

第二步:進一步確認,是否字段和屬性名一一對應

spring.thymeleaf.cache
spring.thymeleaf.mode=HTML
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
    ...
	private boolean cache = true;
    ...
    private String mode = "HTML";
    ...
}

MessageSource + Properties = MessageSourceProperties

配置項前綴 - spring.messages

有了這裏理論依據,我們就根據此仿造寫一個demo

demo

父子pom配置詳見本節末github地址。這裏給出核心代碼結構:
在這裏插入圖片描述
頁面渲染,index.html

<!DOCTYPE html>

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

<head>
    <title>Good Thymes Virtual Grocery</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link rel="stylesheet" type="text/css" media="all"
          href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
</head>

<body>

<p th:text="#{home.welcome}">Welcome to our grocery store!</p>

<p th:text="${!#strings.isEmpty(message)}">Message!</p>

</body>

</html>

IndexController

@Controller
public class IndexController {

    @GetMapping({"/", ""})
    public String index(Model model) {
        model.addAttribute("string",new StringUtil());
        return "index";
    }

    public static class StringUtil {

        public StringUtil() {
        }

        public boolean isNotBlank(String value) {
            return StringUtils.hasText(value);
        }

    }

    @ModelAttribute(name = "message")
    public String message() {
        return "Hello,World";
    }
}

index.dota2
在這裏插入圖片描述
走你!
在這裏插入圖片描述
成功渲染頁面!

學會打斷點

DispatcherServlet#doDispatch -> 攔截請求
在這裏插入圖片描述
Controller -> 執行業務,並且控制視圖
在這裏插入圖片描述
DispatcherServlet#resolveViewName -> 視圖解析

在這裏插入圖片描述
DispatcherServlet#render -> 視圖渲染

在這裏插入圖片描述

接着調用DispatcherServlet#renderFragment ,處理請求地址:
在這裏插入圖片描述
進入實現類:

org.thymeleaf.TemplateEngine#process(org.thymeleaf.TemplateSpec, org.thymeleaf.context.IContext, java.io.Writer)

在這裏插入圖片描述
真正解析地址處理方法:

回到org.thymeleaf.engine.TemplateManager#parseAndProcess主流程:
在這裏插入圖片描述
View渲染,看看OutputBuffer(ob)裏的內容不就是視圖層H5頁面麼!
在這裏插入圖片描述
兩相對比,不能發現,這就是整個SpringMVC的處理流程:
在這裏插入圖片描述

國際化

關於Locale(國際化)
在這裏插入圖片描述

Spring MVC

看看 Locale 在Spring MVC中的處理

  • Servlet
    • ServletRequest#getLocale()
      在這裏插入圖片描述
      • Accept-Language: en,zh;q=0.9,zh-TW;q=0.8
        locale()應用於瀏覽器中的常見字段
  • LocaleContextHolder
    • 來自於
      • DispatcherServlet
        • FrameworkServlet#initContextHolders
    • 存儲是ThreadLocal

以之前演示的demo爲例:
在這裏插入圖片描述
在頁面配置引入:
在這裏插入圖片描述
最終的頁面展示:
在這裏插入圖片描述

Spring Boot

看看 Locale 在Spring Boot中的處理

  • MessageSource

    • MessageSourceAutoConfiguration
      • MessageSourceProperties
        • message.properties
        • message_en.properties
        • message_zh.properties
        • message_zh_CN.properties
        • message_zh_TW.properties
  • Thymeleaf

    • #key => messageSource.get()

思考人生

JSP爲什麼被Spring拋棄?

  • Java EE 和 Spring 競爭關係的

  • Spring 想獨立門戶
    所以Spring搞了一個WebFlux~

    • WebFlux支持的功能
      • Servlet 3.1
      • Reactor +Netty
    • @Controller@RequestParam
      • Spring Web MVC
      • Spring WebFlux
      • 不再看到 Servlet API
        • ServletRequest
        • ServletResponse

JSP爲什麼性能要好?

JSP -> JSP 模板 -> 翻譯 Servlet Java 源文件 -> 編譯 Servlet Class -> Servlet 加載 -> Servlet 執行(字節碼執行)

不同於JSP,Thymeleaf 的作用機制:Thymeleaf -> Thymeleaf 模板 -> 解釋執行模板表達式(動態運行時)

解釋型語言要比編譯型語言慢!

後記

下節預告:REST理論(英文)

本節示例代碼:https://github.com/harrypottry/microservices-project/spring-mvc-view

更多架構知識,歡迎關注本套Java系列文章Java架構師成長之路

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章