Springboot基础知识(10)- 整合 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             <project ... >
 2                 ...
 3                 <dependencies>
 4                     ...
 5 
 6                     <!-- Thymeleaf -->
 7                     <dependency>
 8                         <groupId>org.springframework.boot</groupId>
 9                         <artifactId>spring-boot-starter-thymeleaf</artifactId>
10                     </dependency>
11                     
12                     ...
13                 </dependencies>
14             
15                 ...    
16             </project>


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

    2) 创建模板文件

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

      示例,在 “ Springboot基础知识(08)- spring-boot-starter-web(Web启动器)” 里 SpringbootWeb 项目基础上,修改如下。

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

 1             <div th:fragment="fragment-header" id="fragment-header-id">
 2                 <p>Header</p>
 3             </div>
 4             <div th:fragment="fragment-banner" id="fragment-banner-id">
 5                 <p>Banner</p>
 6                 <hr />
 7             </div>
 8             <div th:fragment="fragment-footer(var)" id="fragment-footer-id">
 9                 <hr />
10                 <p th:text="${var}">Footer</p>
11             </div>   


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

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

 1             <!DOCTYPE html>
 2             <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3             <head>
 4                 <meta charset="UTF-8">
 5                 <title>Demo</title>
 6             </head>
 7             <body>
 8 
 9                 <div th:replace="common::fragment-header"></div>
10 
11                 <div th:include="common::fragment-banner"></div>
12 
13                 <div id="content">
14                     <h3 th:text="'Welcome ' + ${name}">Welcome</h3>
15 
16                     <div th:object="${user}" >
17                         <p th:text="*{firstName}">firstName</p>
18                     </div>
19                 </div>
20 
21                 <div th:insert="common::fragment-footer(var='Copyright 2020')"></div>
22 
23             </body>
24             </html>

 

        (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<String, Object> 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 模板,可以通过表达式 #{...} 获取国际化内容,例如:

            <p th:text="#{login.username}">Username</p>


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

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

 1             <!DOCTYPE html>
 2             <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3             <head>
 4                 <meta charset="UTF-8">
 5                 <title>Login</title>
 6             </head>
 7             <body>
 8 
 9                 <h3 th:text="#{login.title}">Login</h3>
10 
11                 <p><span th:text="#{login.username}">Username</span>:
12                     <input type="text" name="username" value="" /></p>
13                 <p><span th:text="#{login.password}">Password</span>:
14                     <input type="text" name="password" value="" /></p>
15 
16             </body>
17             </html>


        (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,中文浏览器会显示:

            登录
            
            用户名:

            密码:


posted @ 2022-04-18 21:18  垄山小站  阅读(323)  评论(0编辑  收藏  举报