真正解耦是让html回归语义本身,剥离数据生成逻辑,仅保留结构与语义标签,动态内容通过data-属性预埋并由前端js填充,接口契约需统一字段命名与格式,静态资源与api路径必须分离部署。

jsp 里混写 Java 逻辑、thymeleaf 模板中塞业务判断、freemarker 里直接调数据库——这些做法让 HTML 变成“伪静态文件”,实际是服务端渲染的黑盒。真正解耦不是把前端代码挪出去,而是让 HTML 回归语义本身。
HTML 不该承担数据组装职责
传统 MVC 模板(如 jsp、thymeleaf)常把 for 循环、if 判断、甚至 service 调用写进模板里,结果是:前端无法独立调试、样式改一处要后端发版、SEO 依赖服务端渲染但又难控制输出结构。
关键动作是剥离所有「数据生成逻辑」:把 ${user.name} 改成 data-user-name 属性占位,把 th:each="item : ${list}" 改成空 <ul class="list"></ul>,由前端 JS 通过 fetch 拉取 JSON 后填充。
- 模板只保留结构、语义标签(
article、nav、section),不出现任何th:或${}表达式 - 所有动态内容用
data-属性预埋上下文(如data-api-endpoint="/api/users"),而非直接渲染数据 - 禁止在模板里调用
service、repository、utils等后端类
前后端接口契约必须提前约定好字段名
解耦失败最常见原因不是技术问题,而是接口字段命名随意:userName vs username vs user_name,isDeleted vs deleted vs status —— 前端拿到 JSON 后要写一堆映射逻辑,等于换种方式耦合。
推荐做法是用 OpenAPI 3.0 写死 schema,生成 types.d.ts 或 Java @Data 类,双方按同一份 JSON 结构开发。
- 字段名统一用
snake_case(后端友好)或camelCase(前端友好),全项目强制一致 - 布尔字段不用
isXxx开头(避免 JS 解构时和is关键字冲突),统一用xxx_enabled或xxx_active - 分页字段固定为
page、size、total、items,不出现pageNum、pageSize、list等变体
静态资源部署路径与 API 路径必须分离且可配置
前端打包后扔进 src/main/resources/static,后端还用 @Controller 返回 index.html —— 这只是物理分离,不是逻辑解耦。真正的分离意味着:HTML 是纯静态文件,由 Nginx 直接 serve;API 请求走独立域名或路径前缀(如 /api/v1/)。
否则会出现:前端改了 main.js 要重启 Tomcat、Nginx 配置漏加 CORS 导致 fetch 失败、本地开发时后端没启就打不开页面。
- 前端构建产物(
dist/)不放进后端工程,由 CI/CD 单独部署到对象存储或 CDN - API 基地址通过环境变量注入(如
VUE_APP_API_BASE_URL或REACT_APP_API_URL),不在代码里硬编码"http://localhost:8080" - 后端 Spring Boot 禁用
WebMvcConfigurer.addViewControllers()自动映射/到index.html,交由反向代理处理
遗留系统渐进改造时,避免“假分离”陷阱
有些团队把 jsp 文件后缀改成 .html,内容不变,就宣称“已完成前后端分离”——这只会让问题更隐蔽:HTML 里依然有 ,JS 里依然用 window.contextPath 拼 URL,CSS 里还有 url('/img/logo.png')。
真正有效的渐进策略是“功能切片 + 接口下沉”:选一个非核心页面(如用户帮助页),把它从 jsp 完全重写为纯 HTML + fetch,后端为此新增一组 REST 接口,旧页面继续跑,新页面并行上线。
- 不追求一次性替换全部模板,优先切离高频、低耦合、无权限校验的页面
- 旧模板中逐步删除
<script></script>块里的业务逻辑,只留初始化脚本,数据全部走fetch - 引入
axios或fetch统一请求层,封装错误码处理、loading 状态、token 注入,别再每个页面手写XMLHttpRequest
data- 里塞东西而不是往 ${} 里拼字符串,你就已经站在解耦的起点上了。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











