Spring Boot + Thymeleaf + Maven 示例

x33g5p2x  于2022-09-19 转载在 Spring  
字(18.7k)|赞(0)|评价(0)|浏览(349)

本文将介绍Spring Boot + Thymeleaf + Maven的例子。我们将在此提供如何使用Spring Boot与Thymeleaf进行国际化(i18n)、表单验证和日志记录。如果Spring Boot在classpath中扫描到Thymeleaf库,它将自动配置Thymeleaf。我们可以使用application.properties改变默认的Thymeleaf配置。Thymeleaf是一个服务器端的模板引擎,可以处理XML、HTML等。Thymeleaf可以从i18n消息文件中访问类字段和消息属性。我们可以使用Thymeleaf将我们的类字段与HTML表单元素绑定。我们可以使用Thymeleaf迭代我们的java集合。在我们的例子中,我们将使用Thymeleaf执行表单验证和解除i18n消息。如果Spring Boot启动器使用的是较低版本的Thymeleaf,我们还将提供如何使用Maven来使用Thymeleaf的高版本。我们还将在Thymeleaf视图中使用CSS文件。现在让我们一步一步地讨论这个完整的例子。

使用的技术

找到我们的应用程序中使用的技术。

  1. Java 8
  2. Spring Boot 1.5.3.RELEASE
  3. Thymeleaf 3.0
  4. Maven 3.3
  5. Eclipse Mars

Thymeleaf 3与Spring Boot集成

为了将Thymeleaf与Spring Boot集成,我们需要在构建工具中使用以下Spring Boot启动器,如Maven和Gradle。假设我们使用的是Maven,那么我们将使用以下Maven依赖项。

&ltdependency>
    &ltgroupId&gtorg.springframework.boot</groupId>
    &ltartifactId&gtspring-boot-starter-thymeleaf</artifactId>
</dependency>

这就是在Spring Boot中配置Thymeleaf的全部内容。当Spring Boot在classpath中找到Thymeleaf库时,Spring Boot会自动为Thymeleaf进行必要的配置。
在写这篇文章时,Thymeleaf启动器的最新版本是1.5.3.RELEASE,它使用Thymeleaf 2.1版本。如果我们想使用更高版本的Thymeleaf,例如Thymeleaf 3.0,那么我们需要在pom.xml中配置以下属性。
1. thymeleaf.version
2. thymeleaf-layout-dialect.version

假设我们使用的是Maven,那么上述属性将被配置为如下。

&ltproperties>
   &ltthymeleaf.version&gt3.0.6.RELEASE</thymeleaf.version>
   &ltthymeleaf-layout-dialect.version&gt2.2.2</thymeleaf-layout-dialect.version>
   &ltjava.version&gt1.8</java.version>        
</properties>

现在Spring Boot将使用Thymeleaf版本3.0.6.RELEASE和Thymeleaf布局方言版本2.2.2和java版本1.8

使用Thymeleaf

如果Spring Boot在其classpath中扫描了Thymeleaf库,那么我们就可以使用Thymeleaf了。Spring Boot为Thymeleaf提供了属性,将在application.propertiesapplication.yml中进行配置,以改变Thymeleaf与Spring Boot的配置。我们在此列出其中一些。

spring.thymeleaf.mode: 模板模式,将应用于模板。默认是HTML 5
spring.thymeleaf.prefix。这是在视图名称前加上的值,用于建立URL。默认值是 classpath:/templates/
spring.thymeleaf.senix: 这是与视图名称相加的值,用于建立URL。默认值是.html

在默认的Spring Boot和Thymeleaf配置下,我们可以将带有html扩展名的Thymeleaf文件放在以下位置。

src\main\resources\templates

现在我们将讨论如何使用Thymeleaf创建表单元素。

使用Thymeleaf创建&ltform>

假设我们在控制器类中有一个方法。

@Controller
@RequestMapping("app")
public class UserController {
  @GetMapping("create-user")
  public ModelAndView createUserView() {
    ModelAndView mav = new ModelAndView();
    mav.setViewName("user-creation");
    mav.addObject("user", new User());
    mav.addObject("allProfiles", getProfiles());
    return mav;
  }
  ---
}

当我们访问/app/create-user URL时,名为user-creation.html的Thymeleaf文件将会打开,在那里我们将创建一个表单来创建用户。现在看看下面的代码片段。

mav.addObject("user", new User());

属性名称user将在&ltform>中与Thymeleaf th:object属性一起使用。

&ltform action="#" th:action="@{/app/create-user}" th:object="${user}" method="POST">

th:action被指定为行动URL,将在表单提交时被调用。在表单提交时,URL /app/create-user将访问控制器类中的以下方法。

@Controller
@RequestMapping("app")
public class UserController {
  ---
  @PostMapping("create-user")
  public ModelAndView createUser(@Valid User user, BindingResult result) {
    ---
  }
}

现在我们将创建一些表单元素。假设我们有一个类,它有对应表单元素的字段。

public class User { 
   private String userId;
   private String userName;
   private String gender;
   private Boolean married;
   private String profile;
}

与表单元素的数据绑定,如&ltinput>和&ltselect>是通过Thymeleaf th:field属性实现的。假设我们想创建一个输入文本框来获取用户ID。User类的字段userId将使用Thymeleaf th:field绑定到输入文本框,如下所示。

&ltinput type="text" th:field="*{userId}" />

以同样的方式,其他表单元素也将与User类字段绑定。找到User类的userName字段的输入框。

&ltinput type="text" th:field="*{userName}" />

User类的gender字段找到单选按钮。

&ltinput type="radio" th:field="*{gender}" value="Male"/>
&ltinput type="radio" th:field="*{gender}" value="Female"/>

找到married类中User字段的复选框。

&ltinput type="checkbox" th:field="*{married}" />

User类的profile字段找到选择元素。

&ltselect th:field="*{profile}">
         &ltoption th:each="profile : ${allProfiles}" th:value="${profile}" th:text="${profile}"&gtProfile</option>
</select>

Thymeleaf th:each将遍历集合。Thymeleaf th:value属性赋值。allProfiles是属性名称,将在ModelAndView中为每个请求添加。

mav.addObject("allProfiles", getProfiles());

getProfiles()方法将返回所有配置文件的列表。

private List&ltString> getProfiles() {
   List&ltString> list = new ArrayList<>();
   list.add("Developer");
   list.add("Manager");
   list.add("Director");
   return list;
}

Thymeleaf提供了th:text="${...}"语法,可以用来访问java对象中的一个值。如果我们想显示一个表格中所有项目的报告,我们写代码如下。

&lttable>
 &lttr th:each="user : ${allUsers}">
    &lttd th:text="${user.userId}"&gtId</td>
    &lttd th:text="${user.userName}"&gtTitle</td>
 </tr>	
</table>

在Thymeleaf中,我们可以使用th:href="@{..}"语法的href来加载CSS或者创建一个链接来重定向一个URL。

国际化(i18n)

当我们使用Spring Boot启动器时,我们的Spring Boot应用程序就可以使用国际化(i18n)。我们需要在以下位置创建属性文件。

src\main\resources\messages.properties
src\main\resources\messages_en.properties

如果locale是en,那么Spring应用程序将选择messages_en.properties文件。默认的i18n文件将是messages.properties
我们可以使用application.properties文件中的spring属性改变默认的spring消息配置。例如。
spring.messages.basename。它为消息文件配置了逗号分隔的基础名称。默认是messages
spring.messages.encoding: 它配置了消息包的编码。默认为UTF-8

为了显示i18n消息,我们需要使用Thymeleaf th:text="#{...}"语法。假设我们想为我们的页面标题显示i18n消息,为此我们在消息属性文件中定义了一个键,如下所示。

app.title= Spring Boot + Thymeleaf

那么它将被Thymeleaf以如下方式显示。

&lttitle th:text="#{app.title}"> Title </title>

Thymeleaf提供了#locale的上下文,我们可以用它来显示语言、国家等特定地区的细节,如下所示。

&ltp th:text="${#locale.language}"> language</p>
&ltp th:text="${#locale.country}"> country</p>

验证

为了验证一个字段,我们可以使用Hibernate验证器。当我们使用Spring Boot启动器时,Hibernate验证器库被自动配置在classpath中。现在我们将在我们的类中使用验证器注解,以绑定表单。验证器注解有@NotNull@Size等,来自javax.validation库。

public class User { 
   @NotNull
   @Size(min=3, max=10)	
   private String userId;
   @NotNull
   @Size(min=5, max=20)	   
   private String userName;
   @NotNull   
   private String gender;
   private Boolean married;
   private String profile;
}

为了启用表单验证,我们需要在Spring控制器的方法参数中使用@Valid注解,该注解将在表单提交时被调用。我们还需要Spring BindingResult的实例来了解表单是否被验证。

@PostMapping("create-user")
public ModelAndView createUser(@Valid User user, BindingResult result) {
    ModelAndView mav = new ModelAndView();
    if(result.hasErrors()) {
       	logger.info("Validation errors while submitting form.");
       	mav.setViewName("user-creation");
        mav.addObject("user", user);
        mav.addObject("allProfiles", getProfiles());
        return mav;
    }		
    userService.addUser(user);
    mav.addObject("allUsers", userService.getAllUserArticles());
    mav.setViewName("user-info");
    logger.info("Form submitted successfully.");	    
    return mav;
}

如果表单有验证错误,那么result.hasErrors()将返回true。如果表单中存在验证错误,那么我们应该再次调用同一个Thymeleaf视图,如果没有验证错误,则执行业务逻辑并重定向到成功视图。

现在在Thymeleaf视图中,我们需要显示验证错误信息。为了检查给定字段名是否存在验证错误,Thymeleaf提供了#fields.hasErrors(...),它返回布尔值。

&ltlabel th:if="${#fields.hasErrors('userId')}" th:errors="*{userId}" th:class="'error'"&gtId Error</label>

th:errors将显示Spring的默认验证错误信息,其依据是我们在与表单元素绑定的类字段中使用的Hibernate验证器注释。如果我们想使用i18n消息来验证错误,那么就使用th:text="#{...}

&ltlabel th:if="${#fields.hasErrors('userId')}" th:text="#{error.user.id}" th:class="'error'"&gtId Error</label>

error.user.idmessages_en.properties文件中定义的i18n属性。

Logging

在Spring Boot应用程序中,Logback依赖性会自动解决。每个Spring Boot启动器都会自己解决spring-boot-starter-logging。要改变日志的默认配置,我们需要在application.properties文件中配置日志属性。找到其中的一些属性。
logging.level.*。它作为软件包名称的前缀,用于设置日志级别。
logging.file: 它配置了一个日志文件名来记录文件中的信息。
logging.path: 它只配置了日志文件的路径。Spring boot创建了一个名为spring.log的日志文件。

假设我们的类包是com.concretepage,那么可以用logging.level.*application.properties文件中定义日志级别,如下所示。

logging.level.com.concretepage= INFO

现在在任何com.concretepage包或其子包下的类中,日志级别INFO将被应用。我们可以按以下方式使用org.slf4j.Logger
**1.**在类级别上实例化org.slf4j.Logger

private static final Logger logger = LoggerFactory.getLogger(UserController.class);

2. 现在根据需要在类的任何地方使用记录器。

logger.info("Validation errors while submitting form.");

完整的例子

查看Spring boot与Thymeleaf的完整示例。我们将创建具有内部化(i18n)、表单验证和日志的应用程序。查找完整的代码。

1. 使用Eclipse的项目结构

找到使用eclipse的演示项目结构。

2. Maven文件

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
&ltproject 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">
	&ltmodelVersion&gt4.0.0</modelVersion>
	&ltgroupId&gtcom.concretepage</groupId>
	&ltartifactId&gtspring-boot-demo</artifactId>
	&ltversion&gt0.0.1-SNAPSHOT</version>
	&ltpackaging&gtjar</packaging>
	&ltname&gtspring-demo</name>
	&ltdescription&gtSpring Boot Demo Project</description>
	&ltparent>
	   &ltgroupId&gtorg.springframework.boot</groupId>
	   &ltartifactId&gtspring-boot-starter-parent</artifactId>
	   &ltversion&gt1.5.3.RELEASE</version>
	</parent>
	&ltproperties>
	   &ltthymeleaf.version&gt3.0.6.RELEASE</thymeleaf.version>
           &ltthymeleaf-layout-dialect.version&gt2.2.2</thymeleaf-layout-dialect.version>
	   &ltjava.version&gt1.8</java.version>        
	</properties>
	&ltdependencies>
	    &ltdependency>
		&ltgroupId&gtorg.springframework.boot</groupId>
		&ltartifactId&gtspring-boot-starter-web</artifactId>
	    </dependency>
	    &ltdependency>
		&ltgroupId&gtorg.springframework.boot</groupId>
		&ltartifactId&gtspring-boot-starter-thymeleaf</artifactId>
	    </dependency>	  
    	    &ltdependency>
                &ltgroupId&gtorg.springframework.boot</groupId>
                &ltartifactId&gtspring-boot-devtools</artifactId>
                &ltoptional&gttrue</optional>
            </dependency> 
	</dependencies> 
	&ltbuild>
	    &ltplugins>
		&ltplugin>
		   &ltgroupId&gtorg.springframework.boot</groupId>
		   &ltartifactId&gtspring-boot-maven-plugin</artifactId>
		</plugin>
	     </plugins>
	</build>
</project>

找到我们例子中使用的Spring Boot启动器描述。
spring-boot-starter-parent。用于依赖性管理的父POM。
spring-boot-starter-web。用于构建Web、REST应用程序的启动器。它使用Tomcat服务器作为默认的嵌入式服务器。
spring-boot-starter-thymeleaf。用于Thymeleaf与Spring框架的集成。
spring-boot-devtools。它提供了开发者工具。这些工具在应用开发模式中很有帮助。开发者工具的一个特点是在代码有任何变化时自动重启服务器。

3. 创建域和服务

User.java

package com.concretepage.domain;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class User { 
   @NotNull
   @Size(min=3, max=10)	
   private String userId;
   @NotNull
   @Size(min=5, max=20)	   
   private String userName;
   @NotNull   
   private String gender;
   private Boolean married;
   private String profile;
   public String getUserId() {
	return userId;
   }
   public void setUserId(String userId) {
	this.userId = userId;
   }
   public String getUserName() {
	return userName;
   }
   public void setUserName(String userName) {
	this.userName = userName;
   }
   public String getGender() {
	return gender;
   }
   public void setGender(String gender) {
	this.gender = gender;
   }
   public Boolean getMarried() {
	return married;
   }
   public void setMarried(Boolean married) {
	this.married = married;
   }
   public String getProfile() {
	return profile;
   }
   public void setProfile(String profile) {
	this.profile = profile;
   }  
}

我们在上面的类中使用Hibernate验证器进行表单验证。现在找到服务类。
UserService.java

package com.concretepage.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import com.concretepage.domain.User;
@Service
public class UserService {
	private List&ltUser> allUsers = new ArrayList<>();
	public List&ltUser> getAllUserArticles(){
		return allUsers;
	}
	public void addUser(User user) {
		allUsers.add(user);
	}
}

4. 创建控制器

UserController.java

package com.concretepage.controller;
import java.util.ArrayList;
import java.util.List;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.concretepage.domain.User;
import com.concretepage.service.UserService;
@Controller
@RequestMapping("app")
public class UserController {
	private static final Logger logger = LoggerFactory.getLogger(UserController.class);	
	@Autowired
	private UserService userService;
	@GetMapping("create-user")
	public ModelAndView createUserView() {
	    ModelAndView mav = new ModelAndView();
	    mav.setViewName("user-creation");
	    mav.addObject("user", new User());
	    mav.addObject("allProfiles", getProfiles());
	    return mav;
        }
	@PostMapping("create-user")
	public ModelAndView createUser(@Valid User user, BindingResult result) {
	    ModelAndView mav = new ModelAndView();
            if(result.hasErrors()) {
        	logger.info("Validation errors while submitting form.");
        	mav.setViewName("user-creation");
    	        mav.addObject("user", user);
    	        mav.addObject("allProfiles", getProfiles());
    	        return mav;
            }		
	    userService.addUser(user);
	    mav.addObject("allUsers", userService.getAllUserArticles());
	    mav.setViewName("user-info");
    	    logger.info("Form submitted successfully.");	    
	    return mav;
        }	
	private List&ltString> getProfiles() {
	    List&ltString> list = new ArrayList<>();
	    list.add("Developer");
	    list.add("Manager");
	    list.add("Director");
	    return list;
	}
}

5. 创建application.properties

application.properties

logging.level.root= WARN
logging.level.org.springframework.web= ERROR
logging.level.com.concretepage= INFO

我们已经在上述属性文件中配置了我们的日志级别。

6. 为国际化创建消息属性

找到en地区的消息属性。
messages_en.properties

app.title= Spring Boot + Thymeleaf
app.create-user= Create User
app.user-details= User Details

user.id= Id
user.name= Name
user.gender= Gender
user.married= Married
user.profile= Profile

user.gender.male= Male
user.gender.female= Female

user.form.submit= Submit 
user.form.reset= Reset  
user.add-more-users= Add More Users 

error.user.id= Id must be between 3 to 10 characters.
error.user.name= User name must be between 5 to 20 characters.
error.user.gender= Select  gender.

7. 创建Thymeleaf模板

当我们访问该应用程序时,将打开以下页面。
用户-创建.html

<!DOCTYPE html>
&lthtml xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    &lthead>
        &lttitle th:text="#{app.title}"> Title </title>
        &ltlink rel="stylesheet" th:href="@{/css/styles.css}"/>
    </head>
	&ltbody>
	    &lth1 th:text="#{app.create-user}"&gtCreate</h1>
	    &ltform action="#" th:action="@{/app/create-user}" th:object="${user}" method="POST">
	      &lttable>
	    	&lttr>&lttd th:text="#{user.id}"/></td>
	    	    &lttd>
	    	       &ltinput type="text" th:field="*{userId}" />
	    	       &ltlabel th:if="${#fields.hasErrors('userId')}" th:text="#{error.user.id}" th:class="'error'"&gtId Error</label>
	    	    </td>
	    	</tr>
	    	&lttr>&lttd th:text="#{user.name}"></td>
	    	    &lttd>
	    	      &ltinput type="text" th:field="*{userName}" />
	    	      &ltlabel th:if="${#fields.hasErrors('userName')}" th:text="#{error.user.name}" th:class="'error'"&gtName Error</label>
	    	    </td>
	    	</tr>
	    	&lttr>&lttd th:text="#{user.gender}"></td>
	    	   &lttd>
	    	       &ltinput type="radio" th:field="*{gender}" value="Male"/>&ltlabel th:text="#{user.gender.male}"&gtM</label>
	    	       &ltinput type="radio" th:field="*{gender}" value="Female"/>&ltlabel th:text="#{user.gender.female}"&gtF</label>
	    	       &ltlabel th:if="${#fields.hasErrors('gender')}" th:text="#{error.user.gender}" th:class="'error'"&gtGender Error</label>
	    	   </td>
	    	</tr>
	    	&lttr>&lttd th:text="#{user.married}+ '?'"></td>
	    	   &lttd>
	    	       &ltinput type="checkbox" th:field="*{married}" />
	    	   </td>
	    	</tr>	    	
	    	&lttr>&lttd th:text="#{user.profile}"></td>
	    	   &lttd>
	    	       &ltselect th:field="*{profile}">
	    	          &ltoption th:each="profile : ${allProfiles}" th:value="${profile}" th:text="${profile}"&gtProfile</option>
	    	       </select>
	    	   </td>
	    	</tr>	    		    	
	        &lttr>&lttd colspan="2">
	              &ltinput type="submit" th:value="#{user.form.submit}"/> 
	              &ltinput type="reset" th:value="#{user.form.reset}"/>
	            </td>
	        </tr>
	      </table>  
	    </form>
	</body>
</html>

在成功提交表单后,将打开以下页面。
用户信息.html

<!DOCTYPE html>
&lthtml xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
&lthead>
      &lttitle th:text="#{app.title}"> Title </title>
      &ltlink rel="stylesheet" th:href="@{/css/styles.css}"/>
</head>
&ltbody>
   &lth1 th:text="#{app.user-details}"&gtDetails</h1>
    &lttable>
        &lttr>
           &ltth th:text="#{user.id}"/></th>
           &ltth th:text="#{user.name}"></th>
           &ltth th:text="#{user.gender}"></th>
           &ltth th:text="#{user.married}+ '?'"></th>
           &ltth th:text="#{user.profile}"></th>
        </tr>
        &lttr th:each="user : ${allUsers}">
	      &lttd th:text="${user.userId}"&gtId</td>
		  &lttd th:text="${user.userName}"&gtTitle</td>
		  &lttd th:text="${user.gender}"&gtGender</td>
		  &lttd th:text="${user.married}"&gtMarried</td>
		  &lttd th:text="${user.profile}"&gtProfile</td>		  		  
	    </tr>	
	</table>
	&lta href="#" th:href="@{/app/create-user}" th:text="#{user.add-more-users}"&gtAdd User</a>
</body>
</html>

8. 创建CSS文件

styles.css

.error{
    color: red;
    font-size: 15px;
}
.user{
    color: blue;
    font-size: 15px;
}
table {
    border-collapse: collapse;
}

table, th, td {
    border: 1px solid black;
}

9. Spring Boot主类

找到Spring boot主类来运行应用程序。
MyApplication.java

package com.concretepage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {  
    public static void main(String[] args) {
	SpringApplication.run(MyApplication.class, args);
    }       
}

运行应用程序

我们可以通过以下方式运行我们的应用程序。

  1. 使用Eclipse。使用页末给出的下载链接下载项目源代码。将该项目导入到eclipse中。使用命令提示符,进入项目的根文件夹并运行。
mvn clean eclipse:eclipse

然后在eclipse中刷新该项目。通过点击运行为->Java应用程序来运行主类MyApplication。Tomcat服务器将被启动。

  1. 使用Maven命令。下载项目的源代码。使用命令提示符进入项目的根文件夹,运行命令。
mvn spring-boot:run

Tomcat服务器将被启动。

  1. 使用可执行JAR。使用命令提示符,进入项目的根文件夹并运行命令。
mvn clean package

我们将在target文件夹中得到可执行JAR spring-boot-demo-0.0.1-SNAPSHOT.jar。运行这个JAR的方式是

java -jar target/spring-boot-demo-0.0.1-SNAPSHOT.jar

Tomcat服务器将被启动。

现在我们准备好测试该应用程序。访问下面给出的URL。

http://localhost:8080/app/create-user

我们将得到以下视图来创建一个用户。

成功提交表单后,我们将得到用户的报告页面。

祝你学习Spring Boot愉快!

相关文章