Spring基础知识(29)- Spring Boot (十)


整合 Thymeleaf 模板、国际化


1. 整合 Thymeleaf 模板

    Spring Boot 推荐使用 Thymeleaf 作为其模板引擎。SpringBoot 为 Thymeleaf 提供了一系列默认配置,项目中一但导入了 Thymeleaf 的依赖,相对应的自动配置 (ThymeleafAutoConfiguration) 就会自动生效,因此 Thymeleaf 可以与 Spring Boot 完美整合 。

    Spring Boot 通过 ThymeleafAutoConfiguration 自动配置类对 Thymeleaf 提供了一整套的自动化配置方案,该自动配置类的部分源码如下。

1         @Configuration(proxyBeanMethods = false)
2         @EnableConfigurationProperties({ThymeleafProperties.class})
3         @ConditionalOnClass({TemplateMode.class, SpringTemplateEngine.class})
4         @AutoConfigureAfter({WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class})
5         public class ThymeleafAutoConfiguration {
6 
7         }


    ThymeleafAutoConfiguration 使用 @EnableConfigurationProperties 注解导入了 ThymeleafProperties 类,该类包含了与 Thymeleaf 相关的自动配置属性,其部分源码如下。

 1         @ConfigurationProperties(prefix = "spring.thymeleaf")
 2         public class ThymeleafProperties {
 3             private static final Charset DEFAULT_ENCODING;
 4             public static final String DEFAULT_PREFIX = "classpath:/templates/";
 5             public static final String DEFAULT_SUFFIX = ".html";
 6             private boolean checkTemplate = true;
 7             private boolean checkTemplateLocation = true;
 8             private String prefix = "classpath:/templates/";
 9             private String suffix = ".html";
10             private String mode = "HTML";
11             private Charset encoding;
12             private boolean cache;
13             
14             ...
15         }


    ThymeleafProperties 通过 @ConfigurationProperties 注解将配置文件(application.properties/application.yml) 中前缀为 spring.thymeleaf 的配置和这个类中的属性绑定。

    在 ThymeleafProperties 中还提供了以下静态变量:

        DEFAULT_ENCODING:默认编码格式
        DEFAULT_PREFIX:视图解析器的前缀
        DEFAULT_SUFFIX:视图解析器的后缀

    与 Spring Boot 其他自定义配置一样,我们可以在 application.properties/application.yml 中修改以 spring.thymeleaf 为前缀的属性,以实现修改 Spring Boot 对 Thymeleaf 的自动配置。

    Spring Boot 整合 Thymeleaf 模板引擎,需要以下步骤:

        引入依赖
        创建模板文件,并放在在指定目录下

    1) 引入依赖

        修改 pom.xml:

 1             
 2                 ...
 3                 
 4                     ...
 5 
 6                     
 7                     
 8                         org.springframework.boot
 9                         spring-boot-starter-thymeleaf
10                     
11                     
12                     ...
13                 
14             
15                 ...    
16             


        在IDE中项目列表 -> SpringbootWeb -> 点击鼠标右键 -> Maven -> Reload Project

    2) 创建模板文件

        根据 ThymeleafProperties 配置属性可知,Thymeleaf 模板的默认位置在 resources/templates 目录下,默认的后缀是 html,即只要将 HTML 页面放在“classpath:/templates/”下,Thymeleaf 就能自动进行渲染。

      示例,在 “” 里 SpringbootWeb 项目基础上,修改如下。

        (1) 创建 src/main/resources/templates/common.html 文件

 1             
"fragment-header" id="fragment-header-id"> 2

Header

3
4
"fragment-banner" id="fragment-banner-id"> 5

Banner

6
7
8
"fragment-footer(var)" id="fragment-footer-id"> 9
10

Footer

11


            注:若 src/main/resources/templates 目录不存在,手动创建各级目录,下同。

        (2) 创建 src/main/resources/templates/demo.html 文件   

 1             
 2             "en" xmlns:th="http://www.thymeleaf.org">
 3             
 4                 "UTF-8">
 5                 Demo
 6             
 7             
 8 
 9                 
"common::fragment-header">
10 11
"common::fragment-banner">
12 13
"content"> 14 15

"'Welcome ' + ${name}">Welcome

16 17
object="${user}" > 18

"*{firstName}">firstName

19
20 21
22 23 24


        (3) 创建 src/main/java/com/example/entity/User.java 文件

 1             package com.example.entity;
 2 
 3             import org.springframework.stereotype.Component;
 4             import org.springframework.boot.context.properties.ConfigurationProperties;
 5 
 6             @Component
 7             @ConfigurationProperties(prefix = "user")
 8             public class User {
 9                 private String firstName;
10                 private Integer age;
11 
12                 public User() {
13 
14                 }
15 
16                 public String getFirstName() {
17                     return firstName;
18                 }
19                 public void setFirstName(String firstName) {
20                     this.firstName = firstName;
21                 }
22 
23                 public Integer getAge() {
24                     return age;
25                 }
26                 public void setAge(Integer age) {
27                     this.age = age;
28                 }
29                 @Override
30                 public String toString() {
31                     return "User {" +
32                             "firstName = " + firstName +
33                             ", age = " + age +
34                             '}';
35                 }
36             }


        (4) 创建 src/main/java/com/example/controller/IndexController.java 文件

 1             package com.example.controller;
 2 
 3             import java.util.Map;
 4             import org.springframework.stereotype.Controller;
 5             import org.springframework.web.bind.annotation.RequestMapping;
 6 
 7             import com.example.entity.User;
 8 
 9             @Controller
10             public class IndexController {
11                 @Autowired
12                 User user;  
13 
14                 @RequestMapping("/demo")
15                 public String demo(Map map) {
16 
17                     user.setFirstName("Tester");
18                     user.setAge(21);
19 
20                     map.put("name", "admin");
21                     map.put("user", user);
22                     return "demo";
23                 }
24             }


        访问 http://localhost:9090/demo,页面显示:

            Header

            Banner
            ----------------------
            Welcome admin
            
            Tester
            -----------------------
            Copyright 2020


2. 国际化


    国际化(Internationalization 简称 I18n,其中 “I” 和 “n” 分别为首末字符,18 则为中间的字符数)是指软件开发时应该具备支持多种语言和地区的功能。
    
    换句话说就是,开发的软件需要能同时应对不同国家和地区的用户访问,并根据用户地区和语言习惯,提供相应的、符合用具阅读习惯的页面和数据,例如,为中国用户提供汉语界面显示,为美国用户提供提供英语界面显示。

    在 Spring 项目中实现国际化,通常需要以下步骤:

        (1) 编写国际化资源(配置)文件;
        (2) 使用 ResourceBundleMessageSource 管理国际化资源文件;
        (3) 在页面获取国际化内容;

    1) 编写国际化资源文件

        在 src/main/resources 下创建一个 i18n 的目录,并在该目录中按照国际化资源文件命名格式分别创建以下三个文件:

            login.properties:无语言设置时生效
            login_en_US.properties:英语时生效
            login_zh_CN.properties:中文时生效

        以上国际化资源文件创建完成后,IDEA 会自动识别它们,并转换成 Resource Bundle 模式。

        打开 login.properties,点击窗口底部 Resource Bundle 标签,然后点击 “+” 号,创建 Username 和 Password 属性。
        
            修改后的 login.properties 文件

                login.title=Login(default)
                login.password=Password(default)
                login.username=Username(default)

            修改后的 login_en_US.properties 文件

                login.title=Login
                login.password=Password
                login.username=Username

            修改后的 login_zh_CN.properties 文件

                login.title=登录
                login.password=密码
                login.username=用户名

    2) 使用 ResourceBundleMessageSource 管理国际化资源文件

        Spring Boot 已经对国际化资源文件的管理提供了默认自动配置,我们这里只需要在 Spring Boot 全局配置文件中,使用配置参数 “spring.messages.basename” 指定我们自定义的国际资源文件的基本名即可,当指定多个资源文件时,用逗号分隔。

        修改 src/main/resources/application.properties 文件,添加如下内容:

            spring.messages.basename=i18n.login
            spring.messages.encoding=UTF-8

        注:Spring Boot 根据浏览器放出的请求头的 Accept-Language 来自动选择资源文件,比如 Accept-Language: zh-CN 映射到 login_zh_CN.properties,Accept-Language: en-US 映射到 login_en_US.properties,其它值会默认映射到 login.properties。

    3) 在页面获取国际化内容

        页面使用 Tymeleaf 模板,可以通过表达式 #{...} 获取国际化内容,例如:

           

Username




        示例,在上文 SpringbootWeb 项目基础上,代码如下。

        (1) 创建 src/main/resources/templates/login.html 文件

 1             
 2             "en" xmlns:th="http://www.thymeleaf.org">
 3             
 4                 "UTF-8">
 5                 Login
 6             
 7             
 8 
 9                 

"#{login.title}">Login

10 11

"#{login.username}">Username: 12 "text" name="username" value="" />

13

"#{login.password}">Password: 14 "text" name="password" value="" />

15 16 17


        (2) 创建 src/main/java/com/example/controller/UserController.java 文件

 1             package com.example.controller;
 2 
 3             import org.springframework.stereotype.Controller;
 4             import org.springframework.web.bind.annotation.RequestMapping;
 5 
 6             @Controller
 7             @RequestMapping("/user")
 8             public class UserController {
 9                 @RequestMapping("/login")
10                 public String login() {
11                     return "login";
12                 }
13             }


        访问 http://localhost:9090/user/login,中文浏览器会显示:

            登录
            
            用户名:

            密码: