1. 概述
本文将带你搭建一个前后端分离风格的轻量级 Web 应用:前端使用 Vue.js 渲染页面,后端由 Spring Boot 提供支持。虽然整体结构偏向前后端分离,但我们仍会借助 Thymeleaf 在服务端渲染阶段传递初始数据,实现服务端与客户端的平滑衔接。
这种架构在快速原型开发或 SSR(服务端渲染)过渡场景中非常实用,避免了复杂的构建流程,同时又能享受 Vue 的响应式优势。
2. Spring Boot 项目初始化
项目依赖中,我们引入 spring-boot-starter-web
和 spring-boot-starter-thymeleaf
,前者用于构建 Web 接口,后者负责模板渲染。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.1.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>3.1.5</version>
</dependency>
⚠️ Thymeleaf 默认会从 src/main/resources/templates/
目录下查找模板文件。因此,我们在此路径创建一个 index.html
(初始可为空)。
接下来,编写一个简单的控制器,用于渲染首页并传递数据:
@Controller
public class MainController {
@GetMapping("/")
public String index(Model model) {
model.addAttribute("eventName", "FIFA 2018");
return "index";
}
}
✅ model.addAttribute
是将后端数据注入模板的标准方式。这里我们传入赛事名称 "FIFA 2018"
,前端可通过 Thymeleaf 表达式 ${eventName}
获取。
启动项目:
mvn spring-boot:run
访问 http://localhost:8080
,页面目前为空,接下来我们逐步填充内容,目标是渲染如下结构:
Name of Event: FIFA 2018
Lionel Messi
Argentina's superstar
Christiano Ronaldo
Portugal top-ranked player
3. 使用 Vue.js 组件渲染数据
3.1 模板基础配置
在 index.html
中,我们需要引入 Vue.js 和可选的 Bootstrap 样式库(用于快速美化 UI)。
<!-- head 标签内,可选引入 Bootstrap -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<!-- body 结束前引入 JS -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
📌 说明:
- 使用 CDN 引入 Vue.js,适合演示或简单项目。生产环境建议通过 Webpack 打包管理。
- 引入 Babel Standalone 是为了支持在
<script>
中直接写 ES6 语法(如箭头函数、模板字符串),无需本地构建流程。
接着,在页面中创建一个挂载点:
<div id="contents"></div>
然后初始化 Vue 实例:
<script type="text/babel">
var app = new Vue({
el: '#contents'
});
</script>
✅ 这段代码的作用是:创建一个 Vue 应用,并将其挂载到 #contents
元素上。此时 Vue 已接管该区域的渲染逻辑。
3.2 在模板中展示后端数据
我们先通过 Thymeleaf 渲染静态标题部分:
<div class="lead">
<strong>Name of Event:</strong>
<span th:text="${eventName}"></span>
</div>
这段会直接显示 FIFA 2018
,由 Spring Boot 在服务端渲染完成。
接着,在 Vue 实例中定义前端数据:
<script type="text/babel">
var app = new Vue({
el: '#contents',
data: {
players: [
{
id: "1",
name: "Lionel Messi",
description: "Argentina's superstar"
},
{
id: "2",
name: "Christiano Ronaldo",
description: "World #1-ranked player from Portugal"
}
]
}
});
</script>
✅ data
字段是 Vue 组件的状态中心,这里我们模拟了一个球员列表。实际项目中,这部分数据通常来自后端 API 接口。
3.3 使用 Vue 组件渲染列表
为了提高可维护性,我们将每个球员信息封装成一个可复用的组件。
⚠️ 注意:组件必须在 Vue 实例创建前注册,否则会报 Unknown custom element
错误。
Vue.component('player-card', {
props: ['player'],
template: `<div class="card mb-3">
<div class="card-body">
<h6 class="card-title">{{ player.name }}</h6>
<p class="card-text">
<div>{{ player.description }}</div>
</p>
</div>
</div>`
});
✅ props
用于接收外部传入的数据,这里是单个 player
对象。
✅ template
使用 ES6 模板字符串,支持多行 HTML,写起来更直观。
接下来,在页面中遍历 players
并渲染组件:
<ul>
<li style="list-style-type:none" v-for="player in players" :key="player.id">
<player-card :player="player"></player-card>
</li>
</ul>
📌 关键点解析:
v-for
:Vue 的列表渲染指令,遍历players
数组。:player="player"
:等价于v-bind:player
,将当前player
对象传递给子组件。:key="player.id"
:⚠️ 必须添加,用于帮助 Vue 高效追踪节点变化,提升渲染性能。建议使用唯一字段如id
。
刷新页面后,开发者工具中看到的 DOM 结构类似:
<ul>
<li style="list-style-type: none;">
<div class="card"> ... </div>
</li>
<li style="list-style-type: none;">
<div class="card"> ... </div>
</li>
</ul>
✅ 组件已成功渲染。
🔧 提示:频繁重启应用 + 刷新浏览器太低效。建议启用 Spring Boot Devtools 实现热部署,修改代码后自动重启,大幅提升开发体验。
4. 总结
本文演示了如何将 Vue.js 与 Spring Boot 结合,利用 Thymeleaf 作为桥梁传递初始数据,构建一个简单但结构清晰的全栈应用。
这种模式适合:
- ✅ 快速原型开发
- ✅ 不想引入复杂前端构建流程的项目
- ✅ 需要服务端渲染首屏内容的 SEO 场景
当然,更复杂的项目建议前后端完全分离,通过 REST API 通信。但本文的方案依然是一个不错的起点,尤其适合 Java 主栈开发者快速上手现代前端。
完整示例代码已托管至 GitHub:
👉 https://github.com/eugenp/tutorials/tree/master/spring-boot-modules/spring-boot-vue