← 返回 Java 后端知识路线
阶段 04Spring 与后端

DOM、JSON、Axios 与 Maven:把前后端交接做成可验证契约

从浏览器表单到 Java DTO,串起 DOM 事件、Axios 请求、JSON 结构和 Maven 生命周期。

第 24 / 35 篇
DOMJSONAxiosMaven依赖

先看这一课值不值得学

学完后,你手里多了哪些代码积木

从页面事件产生 JSON 请求,并用 Maven 管理 Java 构建。

本课正式新增

语法 / API / 命令你必须会到什么程度
querySelector / addEventListener选择 DOM 并响应事件
JSON.stringify / JSON.parse对象和 JSON 文本互转
axios.get / axios.post发送异步 HTTP 请求
pom.xml dependency声明 Maven 依赖

本课只借用,先别硬背

  • 跨域和后端 Controller 在后续 Spring MVC 课

学完必须能独立写

  • 点击按钮请求 JSON 并更新页面
  • 创建可编译测试的 Maven 项目
本课目录
  1. 1. 现实问题:后端说“接口没问题”,页面却显示空白
  2. 2. 最小可运行示例:输入、请求、渲染各有边界
  3. 3. 调用链与对象变化
  4. 4. 为什么这样设计
  5. 5. 项目落点:接口契约和构建契约一起写
  6. 6. 易错排查
  7. 7. 一页复习

1. 现实问题:后端说“接口没问题”,页面却显示空白

前端可能选错 DOM 节点、把数字当字符串、忘了发送 JSON Content-Type,或把后端的错误响应当成成功数据。后端又可能把 snake_casecamelCase 混用,Maven 依赖版本不一致导致本地能跑、CI 不能跑。全栈交接需要把浏览器、HTTP、DTO 和构建链连起来。

先写一个加载文章按钮:读取 input 的 id,Axios 发送 GET,按状态码更新 DOM。再用 Maven 说明依赖从哪里来、命令执行了哪些阶段。

2. 最小可运行示例:输入、请求、渲染各有边界

<input id="article-id" value="42" inputmode="numeric">
<button id="load">加载文章</button>
<p id="message" role="status"></p>
<article id="article"></article>
<script type="module">
  const button = document.querySelector('#load');
  const message = document.querySelector('#message');
  const article = document.querySelector('#article');
  button.addEventListener('click', async () => {
    const id = Number(document.querySelector('#article-id').value);
    if (!Number.isInteger(id) || id <= 0) { message.textContent = '请输入正整数'; return; }
    try {
      const response = await axios.get(`/api/articles/${id}`);
      article.textContent = response.data.title;
      message.textContent = '加载成功';
    } catch (error) {
      message.textContent = error.response?.data?.message ?? '请求失败';
    }
  });
</script>

实际页面要先加载 Axios 或使用 fetch,示例重点是调用顺序和错误分支。textContentinnerHTML 更安全,除非明确需要渲染受信任的 HTML。后端 DTO 约定 idtitlestatus 的类型与命名,前端不要靠字符串猜。

Maven 的最小命令是 mvn test:读取 pom、解析依赖、编译主代码和测试代码、执行测试。mvn package 在测试通过后生成 JAR;依赖由 groupId、artifactId、version 坐标确定,版本要由父 POM 或 BOM 统一管理。

3. 调用链与对象变化

用户点击事件拿到 DOM 节点值,Number 把文本转换成 JS number;Axios 组装 URL 和请求头,服务器返回 JSON,客户端把响应 body 解析成对象,代码读取 data.title 并写入 DOM。任意一层的字段名、状态码或 Content-Type 不一致,最后都可能表现成“页面空白”。

Maven 从 pom 的依赖声明解析本地仓库和远程仓库,建立依赖图;编译插件把 Java 源码交给 javac,测试插件启动 JUnit 平台,打包插件把 class 和资源写进 JAR。依赖冲突是图上的同一坐标多版本选择问题,不是“删 node_modules”能解决的 Java 构建问题。

4. 为什么这样设计

DOM 是页面状态,JSON 是跨进程表示,Java DTO 是服务内部输入输出,三者不应完全共用一个对象。前端负责交互反馈,后端负责规则和权限;错误结构统一后,Axios catch 才能稳定展示。用户输入在浏览器校验一次,在服务器仍必须再校验。

Maven 的生命周期让构建在本地、CI 和 IDE 中有同一套阶段;插件执行可重复,依赖传递可追踪。不要把依赖 JAR 手工拷贝进项目,也不要用 -DskipTests 把失败藏起来后宣布构建成功。

5. 项目落点:接口契约和构建契约一起写

博客系统可以把 API 示例、错误 JSON 和字段命名写进文档,前端用固定 fixture 做组件测试,后端用 MockMvc 验证 Controller。pom 中固定 Java 21、Spring Boot BOM 和插件版本,CI 执行 mvn test verify,把依赖树和测试报告作为证据。

练习:把 Axios 请求改为发送 POST /api/articles 的 JSON DTO,处理 400、401、409 三种响应;再执行 mvn dependency:tree 找出一个传递依赖,说明它来自哪个坐标。比较浏览器 Network 面板和后端日志中的同一个 traceId。

6. 易错排查

  • DOM 查询返回 null:脚本执行时机、id 拼写和组件渲染时机先确认。
  • Axios catch 没有 message:错误响应结构不稳定,先打印状态码和安全摘要。
  • JSON 字段为空:检查大小写、序列化命名策略、请求 Content-Type 和 DTO getter/setter。
  • Maven “本地能跑 CI 不能”:确认 JDK、settings、锁定依赖版本和是否跳过测试。

7. 一页复习

DOM 事件产生输入,Axios 发送 HTTP,JSON 跨进程表达,DTO 承接服务边界;Maven 解析依赖并按生命周期编译、测试、打包。每次排查都把浏览器 Network、HTTP 报文、Java 日志和构建命令放在同一条调用链上。

把一次点击的状态拆成四个对象:DOM input 的 value 是文本,Number 转换后是 JS number,Axios response.data 是 JSON 对象,textContent 最终把 title 写回页面。后端收到的 body 又会从字节变成 DTO,再回到 JSON。任何字段从 article_title 变成 title、从 number 变成字符串或从 200 变成 204,都可能让页面显示空白。

项目中可以把前端请求封装在 article-api.js,页面组件只负责状态和渲染;后端用 DTO 和错误响应契约固定字段,Maven 的 pom.xml 固定 Java release、Boot BOM 和测试插件。浏览器 Network 看到的是一个具体请求,CI 的 Maven 日志看到的是一条具体构建,两份证据用 commit 和接口版本关联。

排错时 DOM 为空先检查脚本加载时机和 selector;请求未发送查事件监听与校验返回;收到 400 查发送的 JSON、Content-Type 和后端错误字段;Maven 依赖冲突查 dependency:tree 和 effective-pom;本地成功 CI 失败查 JDK、settings、profile 和是否跳过测试。不要用刷新页面掩盖异步状态没有清理的问题。

练习是把加载按钮改成创建草稿:输入 title/body,发送 JSON,按 201 渲染 id,按 400 显示字段错误,按 409 显示 slug 冲突。后端和前端各写一个 fixture,运行 mvn test 与浏览器请求后比较字段,记录哪一层做了类型转换和哪一层负责用户反馈。

前端交互的每一步都可测试:输入框从空字符串到合法 id,点击后按钮进入 loading,Axios 得到 200 后把 data 转成展示状态,得到 400 后把字段错误映射到提示,得到网络异常后保留重试入口。后端 DTO 的类型不能因为浏览器能发送字符串就放宽,服务端仍需拒绝非法数字、超长正文和未知权限字段。

Maven 的对象变化也要有证据:pom 是依赖声明,依赖树是解析结果,target/classes 是编译产物,surefire 报告是测试结果,JAR 是交付包。删除 target 后再执行同一命令能证明构建不是依赖上一次残留;mvn testmvn package 的差异要写进项目 README,不要在 CI 中默默加 -DskipTests

项目文件可将 API 调用、DTO fixture 和页面渲染分别放前端模块,将 Java DTO、ControllerTest 和 Maven pom 放后端模块。字段命名转换要在序列化配置或显式映射中固定,不能让一个页面组件和另一个页面各自猜。traceId 从浏览器 header 进入后端日志,排查时能把 Network 和服务器串起来。

排错时页面空白先看 DOM 是否更新,更新但内容为空查 response.data 结构,服务返回 400 查 DTO 错误字段,Maven 编译错查 release/JDK 和依赖,运行时 NoClassDefFoundError 查依赖 scope。练习是给创建草稿接口做成功、字段错误、冲突和网络重试四种 UI 状态,并把同一份 JSON fixture 用在前后端测试。

验证清单:把创建草稿的输入设为 title、body 和 clientRequestId,依次测试合法请求、空标题、超长正文、重复幂等键和网络断开;浏览器端记录按钮状态与发送的 JSON,服务端记录 DTO 字段、校验结果、状态码和响应 body。201 应把新 id 写回页面,400 应按字段显示,409 应保留用户输入而不是清空表单,网络失败应提供可控重试。再删除 target 后执行固定 Maven 命令,核对依赖树、编译产物、Surefire 报告和 JAR 时间,证明结果来自当前源码而不是上次构建残留。

调用链复盘还要区分两个世界的“对象”:DOM 节点和 JavaScript 状态不会自动等于后端 DTO,Axios 的 response.data 也只是解析后的普通对象;后端 Jackson 再把 JSON 字节绑定成 Java 类型。字段命名、数字精度、null/缺省、204 空 body 都必须在 fixture 中写出。Maven 则把 pom 声明变成依赖图、class 文件和测试报告,每一步失败都应指向具体命令和文件。

练习复盘:同一份创建草稿 fixture 同时驱动前端状态测试和后端 DTO 测试,比较成功、字段错误、冲突、超时四种输出。前端断言 DOM 文本、按钮 loading 和重试入口,后端断言状态码、错误字段和持久化输入;Maven 清理 target 后再构建,保存 dependency tree、Surefire 报告和 JAR。这样能证明字段命名、类型转换和构建环境没有靠页面刷新或旧产物掩盖。

进阶附录:Maven 多模块与前端构建

多模块项目用 parent 管理版本、module 管理边界,依赖方向要保持清晰。前端 Node 构建可以由 CI 单独执行,或通过 Maven 插件编排;无论采用哪种方式,都要锁定 Node/包管理器版本并保留可复现的构建日志。

本课按「浏览器 DOM/JSON/Axios 与 Maven 构建基础」的学习范围组织,正文与示例均为本站原创整理。