1. 概述

本文将带你搭建一个前后端分离风格的轻量级 Web 应用:前端使用 Vue.js 渲染页面,后端由 Spring Boot 提供支持。虽然整体结构偏向前后端分离,但我们仍会借助 Thymeleaf 在服务端渲染阶段传递初始数据,实现服务端与客户端的平滑衔接。

这种架构在快速原型开发或 SSR(服务端渲染)过渡场景中非常实用,避免了复杂的构建流程,同时又能享受 Vue 的响应式优势。

2. Spring Boot 项目初始化

项目依赖中,我们引入 spring-boot-starter-webspring-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


原始标题:Vue.js Frontend with a Spring Boot Backend