Spring Boot 2.7.8 集成 Thymeleaf的最佳實(shí)踐與常見問(wèn)題討論
前言
在當(dāng)今快速發(fā)展的軟件開發(fā)領(lǐng)域,構(gòu)建高效、可維護(hù)且功能強(qiáng)大的 Web 應(yīng)用是每個(gè)開發(fā)團(tuán)隊(duì)的追求目標(biāo)。Spring Boot 作為一款備受推崇的 Java 基礎(chǔ)框架,憑借其簡(jiǎn)潔的配置、強(qiáng)大的依賴管理和快速開發(fā)的特性,已經(jīng)成為眾多開發(fā)者的首選。與現(xiàn)在流行的Vue和React不同,Thymeleaf也是一種比較常見的模板引擎技術(shù), Thymeleaf,作為一種現(xiàn)代的、功能豐富的模板引擎,以其自然模板的特性、與 HTML 的無(wú)縫兼容以及對(duì)靜態(tài)原型的支持,成為與 Spring Boot 搭配構(gòu)建 Web 應(yīng)用的理想選擇。

為了幫助廣大開發(fā)者更好地掌握 Spring Boot 2.7.8 與 Thymeleaf 的集成,本文將深入探討這一主題。我們將從集成的基礎(chǔ)開始,詳細(xì)介紹如何在 Spring Boot 項(xiàng)目中引入 Thymeleaf,并進(jìn)行必要的配置以確保它們能夠協(xié)同工作。我們會(huì)分享一些最佳實(shí)踐,包括如何組織模板文件、如何利用 Thymeleaf 的變量表達(dá)式和條件語(yǔ)句來(lái)構(gòu)建動(dòng)態(tài)頁(yè)面,以及如何優(yōu)化模板的加載和渲染性能。除了介紹集成的方法和技巧,本文還將重點(diǎn)關(guān)注開發(fā)過(guò)程中可能遇到的常見問(wèn)題。我們會(huì)通過(guò)實(shí)際案例,分析這些問(wèn)題產(chǎn)生的原因,并提供有效的解決方案。無(wú)論是處理模板路徑的沖突、解決視圖解析的錯(cuò)誤,還是優(yōu)化應(yīng)用的啟動(dòng)時(shí)間,我們都會(huì)給出詳細(xì)的步驟和代碼示例,幫助讀者快速定位并解決問(wèn)題。當(dāng)然現(xiàn)在Thymeleaf并不是前后端分離架構(gòu)的最優(yōu)解,因此本文給一些想學(xué)習(xí)SpringBoot的朋友提供示例說(shuō)明和參考。
通過(guò)閱讀本文,你將能夠更加深入地理解 Spring Boot 2.7.8 和 Thymeleaf 的集成機(jī)制,掌握最佳實(shí)踐,避免常見的陷阱,并且能夠快速應(yīng)對(duì)開發(fā)過(guò)程中遇到的各種挑戰(zhàn)。讓我們一起踏上這段學(xué)習(xí)之旅,探索如何利用這兩個(gè)強(qiáng)大的工具構(gòu)建出卓越的 Web 應(yīng)用。
一、如何構(gòu)建SpringBoot應(yīng)用
Spring Boot 2.7.8 版本的發(fā)布,為開發(fā)者帶來(lái)了更加穩(wěn)定和優(yōu)化的開發(fā)環(huán)境。它在性能、安全性以及兼容性等方面都有顯著的提升,使得基于該版本構(gòu)建的應(yīng)用能夠更好地適應(yīng)各種復(fù)雜的業(yè)務(wù)場(chǎng)景。在這樣的背景下,將 Thymeleaf 與 Spring Boot 2.7.8 進(jìn)行集成,不僅可以充分發(fā)揮 Spring Boot 的優(yōu)勢(shì),還能利用 Thymeleaf 強(qiáng)大的模板渲染能力,打造出用戶體驗(yàn)出色、開發(fā)效率高的 Web 應(yīng)用。本節(jié)將重點(diǎn)介紹如何快速構(gòu)建SpringBoot應(yīng)用,包括Pom.xml的定義、如何創(chuàng)建控制器類,如何創(chuàng)建Thyemleaf模板文件和主應(yīng)用程序啟動(dòng)類。
1、項(xiàng)目依賴 (pom.xml)
這里使用的JDK是1.8。因此這里使用SpringBoot2.7.8作為開發(fā)框架。如果對(duì)最新的SpringBoot有需要,也可以使用新版的springboot,集成過(guò)程大同小異。這里我們使用Maven的方式進(jìn)行依賴管理。在Pom.xml中添加以下引用:
<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>org.yelang</groupId> <artifactId>baidu-sse-client</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.18</version> <!-- 兼容JDK 8的Spring Boot版本 --> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <java.version>1.8</java.version> <!-- 使用JDK 8 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> </properties> <dependencies> <!-- Spring Boot WebFlux (包含WebClient) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <!-- Spring Boot Web (可選,如果也需要傳統(tǒng)Web MVC) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Jackson JSON處理 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> <!-- 測(cè)試依賴 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <!-- 確保使用JDK 8編譯 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
2、控制器類
使用SpringBoot可以極大的簡(jiǎn)化我們開發(fā)Web應(yīng)用后臺(tái)。在Maven中引入了SpringBoot之后,我們就可以來(lái)創(chuàng)建控制器類,這里我們使用最簡(jiǎn)潔的方式來(lái)創(chuàng)建相關(guān)類。核心代碼比較簡(jiǎn)單,這里直接給出源代碼:
package org.yelang.controller;
import java.util.HashMap;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class TestController {
@GetMapping("/test")
public String test() {
// 現(xiàn)在Thymeleaf會(huì)查找test.html
return "test";
}
@GetMapping("/testa")
@ResponseBody
public Object testA() {
HashMap<String, Object> data = new HashMap<String, Object>();
data.put("name", "springboot");
data.put("version", "v2.7.18");
return data;
}
}關(guān)于如何在SpringBoot中創(chuàng)建普通的接口和Restful接口,SpringBoot都是非常簡(jiǎn)單的,這里不做更多的贅述。上面第一個(gè)方式即是標(biāo)準(zhǔn)的MVC接口,最后返回一個(gè)頁(yè)面給前端進(jìn)行展示,第二個(gè)方式是返回一個(gè)對(duì)象信息。
3、Thymeleaf 模板
接下來(lái)我們實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的Thymeleaf html頁(yè)面,核心代碼如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>測(cè)試頁(yè)面</title>
</head>
<body>
<h1>測(cè)試頁(yè)面</h1>
<p>如果這個(gè)頁(yè)面能正常顯示,說(shuō)明Thymeleaf配置正確。</p>
<a href="/" rel="external nofollow" >返回首頁(yè)</a>
</body>
</html>通過(guò)前面的Controller中,通過(guò)test請(qǐng)求方法,就會(huì)跳轉(zhuǎn)到這個(gè)具體的頁(yè)面中。
4、配置文件 (application.yml)
在SpringBoot中,約定大于配置是一條優(yōu)化的規(guī)則,因此我們需要使用配置文件來(lái)進(jìn)行應(yīng)用程序的運(yùn)行設(shè)置。比如程序運(yùn)行端口號(hào)、訪問(wèn)路徑、還有MVC模式下的訪問(wèn)頁(yè)面配置,yml頁(yè)面代碼如下:
server:
port: 8088
servlet:
context-path: /bdsse
spring:
thymeleaf:
cache: false
prefix: classpath:/templates/
suffix: .html
mode: HTML
encoding: UTF-8
check-template-location: true
mvc:
static-path-pattern: /static/**
logging:
level:
com.example.sse: DEBUG5、主應(yīng)用啟動(dòng)類
在springboot中,啟動(dòng)應(yīng)用程序的方法很簡(jiǎn)單,直接就是Main的方法方便快捷。
package org.yelang;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SseClientApplication {
public static void main(String[] args) {
SpringApplication.run(SseClientApplication.class, args);
}
}二、項(xiàng)目運(yùn)行
完成上述代碼之后,我們就可以來(lái)運(yùn)行項(xiàng)目。在啟動(dòng)應(yīng)用程序后,同步測(cè)試一下應(yīng)用接口的功能。
1、項(xiàng)目啟動(dòng)
系統(tǒng)啟動(dòng)后,在控制臺(tái)中可以看到以下內(nèi)容,說(shuō)明應(yīng)用程序啟動(dòng)成功。

2、Restful接口測(cè)試
在控制臺(tái)中看到以下消息就表示啟動(dòng)成功,大家可以訪問(wèn)應(yīng)用接口。
Started SseClientApplication in 4.953 seconds (JVM running for 5.594)
在瀏覽器中輸入以下地址,回車看到以下內(nèi)容:

三、Thymeleaf集成的問(wèn)題
盡管 Spring Boot 和 Thymeleaf 的結(jié)合在理論上是完美的,但在實(shí)際開發(fā)過(guò)程中,開發(fā)者仍可能會(huì)遇到各種各樣的問(wèn)題。這些問(wèn)題可能源于對(duì)框架特性的理解不夠深入,也可能是因?yàn)殚_發(fā)環(huán)境的復(fù)雜性導(dǎo)致的配置沖突,甚至可能是由于一些隱藏的兼容性問(wèn)題。這些問(wèn)題如果不加以解決,可能會(huì)嚴(yán)重影響開發(fā)進(jìn)度,降低應(yīng)用的性能和穩(wěn)定性。
1、異常詳情
如果是集成了MVC方法時(shí),我們需要跳轉(zhuǎn)到具體的頁(yè)面,需要跳轉(zhuǎn)到test.html中。在瀏覽器中輸入訪問(wèn)地址后,看到的并不是我們的預(yù)期,而是以下錯(cuò)誤:

同時(shí)在我們的后臺(tái)可以看到以下錯(cuò)誤:
2025-11-21 22:23:49.561 ERROR 11996 --- [nio-8088-exec-7] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [/bdsse] threw exception [Circular view path [test]: would dispatch back to the current handler URL [/bdsse/test] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)] with root cause javax.servlet.ServletException: Circular view path [test]: would dispatch back to the current handler URL [/bdsse/test] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.) at org.springframework.web.servlet.view.InternalResourceView.prepareForRendering(InternalResourceView.java:210) ~[spring-webmvc-5.3.31.jar:5.3.31] at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:148) ~[spring-webmvc-5.3.31.jar:5.3.31] at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:316) ~[spring-webmvc-5.3.31.jar:5.3.31] at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1406) ~[spring-webmvc-5.3.31.jar:5.3.31] at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1150) ~[spring-webmvc-5.3.31.jar:5.3.31] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) ~[spring-webmvc-5.3.31.jar:5.3.31] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965) ~[spring-webmvc-5.3.31.jar:5.3.31] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.31.jar:5.3.31] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.31.jar:5.3.31] at javax.servlet.http.HttpServlet.service(HttpServlet.java:529) ~[tomcat-embed-core-9.0.83.jar:4.0.FR] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.31.jar:5.3.31] at javax.servlet.http.HttpServlet.service(HttpServlet.java:623) ~[tomcat-embed-core-9.0.83.jar:4.0.FR] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209) ~[tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-9.0.83.jar:9.0.83] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.83.jar:9.0.83] at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.31.jar:5.3.31] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.31.jar:5.3.31] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.83.jar:9.0.83] at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.31.jar:5.3.31] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.31.jar:5.3.31] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.83.jar:9.0.83] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.31.jar:5.3.31] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.31.jar:5.3.31] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:168) ~[tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) [tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481) [tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130) [tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) [tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) [tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) [tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:928) [tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1794) [tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) [tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.83.jar:9.0.83] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.83.jar:9.0.83] at java.lang.Thread.run(Unknown Source) [na:1.8.0_171]
那么到底是什么原因?qū)е碌哪兀客ㄟ^(guò)排查問(wèn)題來(lái)進(jìn)行解決。
2、問(wèn)題解決
如果大家在搜索引擎上查找問(wèn)題,可以看到一下內(nèi)容,

方法雖然多,但是基本很多都沒(méi)有解決問(wèn)題,都是把控制器的類型進(jìn)行修改的,也有說(shuō)明要調(diào)整配置文件。根據(jù)我的實(shí)測(cè),都不是。在我這個(gè)場(chǎng)景中,實(shí)際問(wèn)題是沒(méi)有正確的引入Thymeleaf庫(kù),因此需要解決的問(wèn)題就是在Pom.xml中引入相關(guān)資源,核心代碼如下:
<!-- SpringBoot集成thymeleaf模板 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>引入以上資源后,在此運(yùn)行程序后,再次在瀏覽器中輸入訪問(wèn)地址后可以看到以下效果:

能看到以上頁(yè)面,說(shuō)明成功集成并且成功解決了以上的問(wèn)題。
四、總結(jié)
以上就是本文的主要內(nèi)容,為了幫助廣大開發(fā)者更好地掌握 Spring Boot 2.7.8 與 Thymeleaf 的集成,我們將從集成的基礎(chǔ)開始,詳細(xì)介紹如何在 Spring Boot 項(xiàng)目中引入 Thymeleaf,并進(jìn)行必要的配置以確保它們能夠協(xié)同工作。本文的目標(biāo)讀者是那些已經(jīng)具備一定 Java 開發(fā)基礎(chǔ),并且對(duì) Spring Boot 和 Thymeleaf 有一定了解的開發(fā)者。行文倉(cāng)促,定有不足之處,歡迎各位朋友在評(píng)論區(qū)批評(píng)指正,不勝感激。
到此這篇關(guān)于Spring Boot 2.7.8 集成 Thymeleaf的最佳實(shí)踐與常見問(wèn)題討論的文章就介紹到這了,更多相關(guān)Spring Boot集成 Thymeleaf內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot之Refresh流程的簡(jiǎn)單說(shuō)明
這篇文章主要介紹了SpringBoot之Refresh流程的簡(jiǎn)單說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
IDEA使用學(xué)生郵箱無(wú)法注冊(cè)問(wèn)題:JetBrains Account connection error: 拒絕連接
這篇文章主要介紹了IDEA使用學(xué)生郵箱無(wú)法注冊(cè)問(wèn)題:JetBrains Account connection error: 拒絕連接,文中通過(guò)圖文及示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
Spring+SpringMVC+Hibernate項(xiàng)目環(huán)境搭建的步驟(圖文)
這篇文章主要介紹了Spring+SpringMVC+Hibernate項(xiàng)目環(huán)境搭建的步驟(圖文),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05

