Spring 系列 (2) - 在 Spring Boot 项目里使用 Thymeleaf、JQuery+Bootstrap 和国际化
Thymeleaf 是新一代 Java 模板引擎,与 Velocity、FreeMarker 等传统 Java 模板引擎不同,Thymeleaf 支持 HTML 原型,其文件后缀为 “.html”,因此它可以直接被浏览器打开,此时浏览器会忽略未定义的 Thymeleaf 标签属性,展示 thymeleaf 模板的静态页面效果;当通过 Web 应用程序访问时,Thymeleaf 会动态地替换掉静态内容,使页面动态显示。
本文将结合实例讲讲如何在 Spring Boot 项目里使用 Thymeleaf、JQuery、Bootstrap 等。
Spring Boot: https://spring.io/projects/spring-boot/
Thymeleaf:https://www.thymeleaf.org/
JQuery: https://jquery.com/
Bootstrap: https://getbootstrap.com/
1. 开发环境
Windows版本:Windows 10 Home (20H2)
IntelliJ IDEA (https://www.jetbrains.com/idea/download/):Community Edition for Windows 2020.1.4
Apache Maven (https://maven.apache.org/):3.8.1
注:Spring 开发环境的搭建,可以参考 “ ”。
2. 创建 Spring Boot 项目
1) 运行 IDEA 创建项目
点击菜单 New 创建 Project:
New Project -> Project Type: Maven -> Project SDK: 1.8 -> Check "Create from archtype" -> select "org.apache.maven.archtypes:maven-archtype-quickstart" -> Next
Name: SpringbootExample02
GroupId: com.example
ArtifactId: SpringbootExample02
-> Finish
2) 生成的项目目录结构
|-- src
| |-- main
| | |-- java
| | |-- com
| | |-- example
| | |-- App.java
| |-- test
| |-- java
| |-- com
| |-- example
| |-- AppTest.java
|-- pom.xml
3) Spring Boot Web 配置
参考 “” 的 “3. 配置 Spring Boot Web” 部分,完成 Spring Boot Web 配置。
(1) 配置后的 pom.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0modelVersion> 6 7 <groupId>com.examplegroupId> 8 <artifactId>SpringbootExample02artifactId> 9 <version>1.0-SNAPSHOTversion> 10 11 <name>SpringbootExample02name> 12 13 <url>http://www.example.comurl> 14 15 <properties> 16 <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> 17 <maven.compiler.source>1.8maven.compiler.source> 18 <maven.compiler.target>1.8maven.compiler.target> 19 properties> 20 21 <packaging>jarpackaging> 22 23 <parent> 24 <groupId>org.springframework.bootgroupId> 25 <artifactId>spring-boot-starter-parentartifactId> 26 <version>2.6.6version> 27 <relativePath/> 28 parent> 29 30 <dependencies> 31 <dependency> 32 <groupId>junitgroupId> 33 <artifactId>junitartifactId> 34 <version>4.11version> 35 <scope>testscope> 36 dependency> 37 <dependency> 38 <groupId>org.springframework.bootgroupId> 39 <artifactId>spring-boot-starter-webartifactId> 40 dependency> 41 42 <dependency> 43 <groupId>org.springframework.bootgroupId> 44 <artifactId>spring-boot-starter-tomcatartifactId> 45 <scope>providedscope> 46 dependency> 47 <dependency> 48 <groupId>org.springframework.bootgroupId> 49 <artifactId>spring-boot-starter-testartifactId> 50 <scope>testscope> 51 dependency> 52 dependencies> 53 54 <build> 55 ... 56 build> 57 project>
在IDE中项目列表 -> SpringbootExample02 -> 点击鼠标右键 -> Maven -> Reload Project
(2) 修改 src/main/java/com/example/App.java 文件
1 package com.example; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 6 @SpringBootApplication 7 public class App { 8 public static void main(String[] args) { 9 SpringApplication.run(App.class, args); 10 System.out.println("Spring boot example02 project"); 11 } 12 }
(3) 创建 src/main/java/com/example/ServletInitializer.java 文件
1 package com.example; 2 3 import org.springframework.boot.builder.SpringApplicationBuilder; 4 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 5 6 public class ServletInitializer extends SpringBootServletInitializer { 7 8 @Override 9 protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 10 return application.sources(App.class); 11 } 12 13 }
(4) 创建 src/main/java/com/example/controller/IndexController.java 文件
1 package com.example.controller; 2 3 import org.springframework.stereotype.Controller; 4 import org.springframework.web.bind.annotation.RequestMapping; 5 import org.springframework.web.bind.annotation.ResponseBody; 6 7 @Controller 8 public class IndexController { 9 @ResponseBody 10 @RequestMapping("/test") 11 public String test() { 12 return "Test Page"; 13 } 14 }
(5) 创建 src/main/resources/application.properties 文件
1 spring.main.banner-mode=off 2 3 # Web server 4 server.display-name=SpringbootExample02-Test 5 server.address=localhost 6 server.port=9090
(6) 运行
Edit Configurations
Click "+" add new configuration -> Select "Maven"
Command line: clean spring-boot:run
Name: SpringbootExample02 [clean,spring-boot:run]
-> Apply / OK
Click Run "SpringbootExample02 [clean,spring-boot:run]"
...
Spring boot example02 project
访问 http://localhost:9090/test
Test Page
3. 导入 Thymeleaf 依赖包
访问 http://www.mvnrepository.com/,查询 Thymeleaf
修改 pom.xml:
1 <project ... > 2 ... 3 <dependencies> 4 ... 5 6 7 <dependency> 8 <groupId>org.springframework.bootgroupId> 9 <artifactId>spring-boot-starter-thymeleafartifactId> 10 dependency> 11 12 ... 13 dependencies> 14 15 ... 16 project>
在IDE中项目列表 -> SpringbootExample02 -> 点击鼠标右键 -> Maven -> Reload Project
4. 配置静态资源(jQuery、Bootstrap、Images)
本文使用 jQuery 3.6.0 和 Bootstrap 4.2.1,两者放到 src/main/resources/static/lib/ 目录下,图片放在 src/main/resources/static/images/ 目录下。
目录结构如下
static
|- images
| |- bootstrap-solid.svg
|
|- lib
|- jquery
| |- jquery-3.6.0.min.js
|
|- bootstrap-4.2.1-dist
|- css
| |- bootstrap.min.css
| ...
|
|- js
|- bootstrap.min.js
...
注:bootstrap-solid.svg 的下载自 https://v4.bootcss.com/docs/4.6/assets/brand/bootstrap-solid.svg
5. 配置 Thymeleaf 模版
Thymeleaf 模板的默认位置在 resources/templates 目录下,默认的后缀是 html,即只要将 HTML 页面放在 “classpath:/templates/” 下,Thymeleaf 就能自动进行渲染。
1) 创建 src/main/resources/templates/common.html 文件
1 <div th:fragment="header(var)"> 2 <meta charset="UTF-8"> 3 <title th:text="${var}">Titletitle> 4 <link rel="stylesheet" th:href="@{/lib/bootstrap-4.2.1-dist/css/bootstrap.min.css}" href="/lib/bootstrap-4.2.1-dist/css/bootstrap.min.css"> 5 <script language="javascript" th:src="@{/lib/jquery/jquery-3.6.0.min.js}" src="/lib/jquery/jquery-3.6.0.min.js">script> 6 <script language="javascript" th:src="@{/lib/bootstrap-4.2.1-dist/js/bootstrap.min.js}" src="/lib/bootstrap-4.2.1-dist/js/bootstrap.min.js">script> 7 div> 8 9 <div th:fragment="content-header" class="container" id="content-header-id"> 10 <nav class="navbar navbar-light bg-light"> 11 <a class="navbar-brand" href="#"> 12 <img th:src="@{/images/bootstrap-solid.svg}" src="/images/bootstrap-solid.svg" width="30" height="30" class="d-inline-block align-top" alt=""> 13 Thymeleaf Demo 14 a> 15 nav> 16 div> 17 18 <div th:fragment="content-footer(var)" class="container" id="content-footer-id"> 19 <p th:text="${var}">Content Footerp> 20 div>
2) 创建 src/main/resources/templates/home.html 文件
1 DOCTYPE html> 2 <html lang="en" xmlns:th="http://www.thymeleaf.org"> 3 <head th:include="common::header(var='Home Page')"> 4 head> 5 <body> 6 <div th:replace="common::content-header">div> 7 8 <div class="container" id="content" th:style="'min-height: 480px;'"> 9 <p> p> 10 <h3 th:text="'Welcome ' + ${name}">Welcomeh3> 11 12 <p> p> 13 <p>Message: <span id="message">span>p> 14 div> 15 16 <div th:replace="common::content-footer(var='Copyright © 2020')">div> 17 18 <script type="text/javascript"> 19 $(document).ready(function(){ 20 console.log("jQuery is running"); 21 22 $("#message").html("jQuery is running"); 23 }); 24 script> 25 body> 26 html>
3) 修改 src/main/java/com/example/controller/IndexController.java 文件
1 package com.example.controller; 2 3 import org.springframework.ui.Model; 4 import org.springframework.stereotype.Controller; 5 import org.springframework.web.bind.annotation.RequestMapping; 6 import org.springframework.web.bind.annotation.ResponseBody; 7 8 @Controller 9 public class IndexController { 10 @ResponseBody 11 @RequestMapping("/test") 12 public String test() { 13 return "Test Page"; 14 } 15 16 @RequestMapping("/home") 17 public String home(Model model) { 18 model.addAttribute("name", "admin"); 19 return "home"; 20 } 21 }
访问 http://localhost:9090/home
[Logo] Thymeleaf Demo
Welcome admin
Message: jQuery is running
Copyright ? 2020
6. 国际化
1) 编写国际化资源文件
在 src/main/resources 下创建一个 i18n 的目录,并在该目录中按照国际化资源文件命名格式分别创建以下三个文件:
home.properties:无语言设置时生效
home_en_US.properties:英语时生效
home_zh_CN.properties:中文时生效
以上国际化资源文件创建完成后,IDEA 会自动识别它们,并转换成 Resource Bundle 模式。
打开 home.properties,点击窗口底部 Resource Bundle 标签,然后点击 “+” 号,创建属性。
修改后的 home.properties 文件
home.title=Welcome(default)
home.message=Message(default)
home.status_on=jQuery is running(default)
home.status_off=jQuery is off (default)
修改后的 home_en_US.properties 文件
home.title=Welcome
home.message=Message
home.status_on=jQuery is running
home.status_off=jQuery is off
修改后的 home_zh_CN.properties 文件
home.title=欢迎
home.message=信息
home.status_on=jQuery 正在运行
home.status_off=jQuery 没有生效
2) 修改 src/main/resources/application.properties 文件,添加如下内容:
spring.messages.basename=i18n.home
spring.messages.encoding=UTF-8
3) 修改 src/main/resources/templates/home.html 文件
1 DOCTYPE html> 2 <html lang="en" xmlns:th="http://www.thymeleaf.org"> 3 <head th:include="common::header(var='Home Page')"> 4 head> 5 <body> 6 <div th:replace="common::content-header">div> 7 8 <div class="container" id="content" th:style="'min-height: 480px;'"> 9 <p> p> 10 <h3 th:text="#{home.title} + ' ' + ${name}">Welcomeh3> 11 12 <p> p> 13 <p><span th:text="#{home.message}">Messagespan>: 14 <span id="message" th:text="#{home.status_off}">span>p> 15 div> 16 17 <div th:replace="common::content-footer(var='Copyright © 2020')">div> 18 19 <script type="text/javascript" th:inline="javascript"> 20 $(document).ready(function(){ 21 console.log("jQuery is running"); 22 23 $("#message").html([[#{home.status_on}]]); 24 }); 25 script> 26 body> 27 html>
访问 http://localhost:9090/home
注:Spring Boot 根据浏览器放出的请求头的 Accept-Language 来自动选择资源文件,比如 Accept-Language: zh-CN 映射到 home_zh_CN.properties,Accept-Language: en-US 映射到 home_en_US.properties,其它值会默认映射到 home.properties。
6. 使用 spring-boot-maven-plugin 插件运行打包
1) 修改 pom.xml
1 <project ... > 2 ... 3 4 <build> 5 <finalName>SpringbootExample02finalName> 6 <plugins> 7 <plugin> 8 <groupId>org.springframework.bootgroupId> 9 <artifactId>spring-boot-maven-pluginartifactId> 10 <configuration> 11 <mainClass>com.example.AppmainClass> 12 <layout>JARlayout> 13 configuration> 14 <executions> 15 <execution> 16 <goals> 17 <goal>repackagegoal> 18 goals> 19 execution> 20 executions> 21 plugin> 22 plugins> 23 ... 24 build> 25 project>
layout 属性用来指定打成 jar 还是 war 文件,可用的值包括:ZIP 、JAR 、WAR、 NONE
在IDE中项目列表 -> SpringbootExample02 -> 点击鼠标右键 -> Maven -> Reload Project
2) 打包 jar
菜单 View -> Tool Windows -> Maven -> SpringbootExample02 -> Lifecycle -> Clean & Package
jar 包生成在目录 target/ 里
SpringbootExample02.jar
SpringbootExample02.jar.original
注:SpringbootExample02.jar 包含依赖包,可以直接运行。 SpringbootExample02.jar.original 里不包含依赖的包(要手动配置依赖环境),运行前要把文件名上的 “.original” 去掉。
点击 IDEA 底部 Terminal 标签页,执行如下命令。
$ java -jar target/SpringbootExample02.jar
...
Spring boot example project
访问 http://localhost:9090/test
Test Page
复制 src/main/resources/application.properties 文件到 target/ 目录下,修改 target/application.properties 配置如下:
spring.main.banner-mode=console
# Web server
server.display-name=SpringbootExample02-Test
server.address=localhost
server.port=8080
运行如下命令:
$ java -jar target/SpringbootExample02.jar --spring.config.location target/application.properties
...
Spring boot example project
访问 http://localhost:8080/test
Test Page
注:访问 http://localhost:9090/home 时,不能正常显示文字,因为需要国际化配置文件支持,这部分会在以后的外部配置文件实例中详细讲解。
3) 打包 war
把 pom.xml 里
菜单 View -> Tool Windows -> Maven -> SpringbootExample02 -> Lifecycle -> Clean & Package
war 包生成在目录 target/ 里
SpringbootExample02.war
SpringbootExample02.war.original
把 SpringbootExample02.war 放到独立运行的 Tomcat 的 webapp 目录下,假设 Tomcat 运行在 8080 端口。
访问 http://localhost:8080/SpringbootExample02/test
Test Page