針對spring boot,網上已有不少優質的系列教程,我就再也不班門弄斧了(其實是擔憂沒別人寫的好,哈哈哈!)。可是仍是想蹭蹭spring boot的熱度,即便不考慮微服務,spring boot仍是有不少可取優勢的,好比自動化配置、系列Starters簡化maven的依賴管理等。本系列主要是將工做中涉及到的一些功能利用spring boot整合到一塊兒(工做中還沒用到spring-boot)。java
maven-ssm-web中的內容會陸續集成進來,最近幾篇博客會先介紹一些maven-ssm-web中沒有的新內容(由於比較熟嘛!);maven-ssm-web最近會停更,若是有朋友仍須要,仍是會繼續更新的;spring boot的集成工程是:spring-boot-integrate,系列工程則是: spring-boot-2.0.3。git
該系列工程都是基於spring-boot-2.0.3;本文是第一篇,先來點簡單的,講講spring boot中的國際化,工程地址:spring-boot-i18ngithub
pom.xml:web
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com .lee</groupId> <artifactId>spring-boot-i18n</artifactId> <version>1.0-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.3.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
application.ymlspring
server: port: 8880 spring: #國際化配置 messages: encoding: utf-8 basename: i18n/messages #thymeleaf配置 thymeleaf: cache: false
I18nConfig.javaapache
package com.lee.i18n.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.i18n.CookieLocaleResolver; import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; @Configuration public class I18nConfig { // 配置cookie語言解析器 @Bean public LocaleResolver localeResolver() { CookieLocaleResolver resolver = new CookieLocaleResolver(); resolver.setCookieMaxAge(3600); // cookie有效時長,單位秒 resolver.setCookieName("Language"); //設置存儲的Cookie的name爲Language return resolver; } // 配置一個攔截器,攔截國際化語言的變化 @Bean public WebMvcConfigurer webMvcConfigurer() { return new WebMvcConfigurer() { //攔截器 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LocaleChangeInterceptor()).addPathPatterns("/**"); } }; } }
LoginController.javasegmentfault
package com.lee.i18n.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class LoginController { @RequestMapping("/login") public String login() { return "login"; } @RequestMapping("/index") public String index() { return "index"; } }
messages.propertiescookie
index.welcome=歡迎 login.username=登陸名 login.password=密碼 login.login=登陸
messages_en_US.propertiesmvc
index.welcome=welcome login.username=username login.password=password login.login=login
messages_zh_CN.propertiesapp
index.welcome=歡迎 login.username=登陸名 login.password=密碼 login.login=登陸
當如上文件配置好以後(其餘的能夠去spring-boot-i18n拉取),都配置好後,工程跑起來,咱們來看看結果,是否達到國際化效果呢? 答案是確定的嘛!
基本版有一個缺點,就是國際化資源都寫在了一個文件中:messages*.properties,內容都寫在一個文件中有一個致命的缺點:文件越大,越難以維護;
那麼高級版高級在哪了? 你想的沒錯,就是將資源按某種性質或者功能劃分紅資源文件夾,再在資源文件夾下放具體的資源文件,以下圖
改動的內容已標明,具體改動的內容能夠去spring-boot-i18n拉取;工程跑起來,咱們看看結果
從兩個容器的初始化來看整個過程,是哪兩個容器了,一個是spring根容器、一個是spring mvc容器,spring根容器也就是根上下文:WebApplicationContext,spring mvc容器便是:DispatcherServlet;
咱們從main函數入手,以下圖
initMessageSource():初始化國際化資源,finishBeanFactoryInitialization(beanFactory) 實例化非延遲初始化的bean;spring容器初始化的內容仍是很是多的,有興趣的朋友能夠跟着斷點調試詳細看看初始化話過程; 最終所有bean定義都放在了DefaultListableBeanFactory的beanDefinitionMap中了,後續則從beanDefinitionMap中獲取bean定義進行實例化。
咱們都知道spring mvc的核心類就是DispatcherServlet,咱們就從他入手,以下圖:
從DispatcherServlet繼承關係可知,HttpServletBean繼承HttpServlet,所以在Web容器啓動時將調用它的init方法,咱們能夠以此爲入口來追蹤DispatcherServlet的初始化過程;DispatcherServlet中的initStrategies方法比較重要,而其中initLocaleResolver(context)和initHandlerMappings(context)和本文的國際化有直接關係,initLocaleResolver(context)將咱們本身定義的localeResolver綁到了DispatcherServlet的屬性localeResolver中;而initHandlerMappings(context)又將咱們本身新增的攔截器LocaleChangeInterceptor添加到了DispatcherServlet的handlerMappings中;
是否是有種很美妙的預感,咱們自定義的一些bean都關聯到了DispatcherServlet中,而咱們的請求url又必須通過DispatcherServlet,這是否是巧合? 很顯然這不是!若是你仍是一頭霧水,對不起! 咱們接着往下看......
從DispatcherServlet的繼承關係可知,請求會通過DispatcherServlet的doService方法,doService會將DispatcherServlet中的localeResolver(也就是咱們定義的CookieLocaleResolver對象)綁定到當前request對象中,而後再調用doDispatch進行請求的轉發;
LocaleChangeInterceptor的類繼承圖
可知它繼承了HandlerInterceptor,並重寫了preHandle,咱們就從LocaleChangeInterceptor的preHandle方法開始(請求確定會通過此方法)閱讀源碼,打斷點追蹤,以下如
既然能經過locale參數感知語言的變化,那麼確定也能根據語言加載對應的資源,從而實現國際化(具體如何加載的須要你們本身去閱讀源碼了!)
源碼閱讀就此告一段落,不是特別細,只是提供了一個主體流程;強烈建議你們閱讀源碼的時候,進行斷點調試跟蹤,不容易跟丟!