详细讲解在Java Web应用中,如何使用JavaScript的Ajax技术(Fetch API与XMLHttpRequest)异步调用后端的JSP或Servlet进行数据交互、参数解析与JSON格式响应。
JavaScript通过Ajax调用JSP或Servlet处理数据
时间:2026-10-30
浏览:525
文章目录
一、Ajax 与 JSP / Servlet 交互的基本架构
Ajax(Asynchronous JavaScript and XML)本质上是一组客户端技术的统称,核心是允许浏览器通过后台线程与服务器进行数据交换。在 Java Web 体系中,接收处理并响应请求的后端组件通常是 Servlet 或 JSP:
- Servlet:纯 Java 类,继承自
HttpServlet,负责控制器角色。它擅长读取请求参数、调用业务层接口、组装纯文本或 JSON 格式并写入输出流。在现代规范中,它是提供 Ajax 数据接口的首选组件。 - JSP:本质上是会被编译为 Servlet 的模板页面。虽然 JSP 可以通过嵌入 Java 脚本输出数据,但由于模板中容易无意夹带换行符、HTML 标签及空白字符,直接作为数据 API 使用时容易导致前端解析异常,通常只在轻量维护场景下使用。
二、开发实施的关键步骤
实现一套完整的 Ajax 通信,通常遵循明确的前后端对接流程。按顺序包括:定义后端映射、接收清洗参数、组织业务数据并返回、客户端发起网络调用、捕获响应并安全渲染。
三、后端实现:编写 Servlet 接收并返回数据
以常见的“异步检查用户名是否已被注册”以及“提交用户信息”为例,在 Servlet 中我们需要分别支持 GET 和 POST 请求,设置编码规范,并将结果封装为 JSON 格式返回。
1. Servlet 完整示例代码
package com.example.web;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/api/user-check")
public class UserCheckServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1. 设置请求与响应字符集,防止中文乱码
request.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
// 2. 获取客户端通过 URL 传递的参数
String username = request.getParameter("username");
PrintWriter out = response.getWriter();
// 3. 业务逻辑判断并组装 JSON 字符串
if (username == null || username.trim().isEmpty()) {
out.print("{\"success\":false,\"code\":400,\"message\":\"用户名不能为空\"}");
out.flush();
return;
}
boolean exists = "admin".equalsIgnoreCase(username.trim()) || "test".equalsIgnoreCase(username.trim());
if (exists) {
out.print("{\"success\":true,\"code\":200,\"available\":false,\"message\":\"该用户名已被占用\"}");
} else {
out.print("{\"success\":true,\"code\":200,\"available\":true,\"message\":\"用户名可用\"}");
}
out.flush();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
String username = request.getParameter("username");
String role = request.getParameter("role");
PrintWriter out = response.getWriter();
// 模拟保存并返回操作成功状态
out.print("{\"success\":true,\"code\":201,\"data\":{\"username\":\""
+ (username != null ? username : "")
+ "\",\"role\":\""
+ (role != null ? role : "user")
+ "\"},\"message\":\"保存成功\"}");
out.flush();
}
}
response.getWriter() 之前设置 response.setContentType("application/json;charset=UTF-8");。若设置时机延后,Tomcat 容器可能已按默认 ISO-8859-1 或操作系统的默认字符集初始化输出流,导致客户端接收到的中文字符出现乱码或解析失败。
2. 若使用 JSP 作为数据返回源的注意事项
如果历史项目中必须通过 JSP 来返回 JSON,必须特别处理 JSP 默认生成的 HTML 框架与换行空白。请在 JSP 文件最顶部加入指令清除换行,且文件内严禁包含任何 HTML 标签:
<%@ page language="java" contentType="application/json; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page trimDirectiveWhitespaces="true" %>
<%
String username = request.getParameter("username");
boolean available = !"admin".equals(username);
out.print("{\"available\":" + available + "}");
%>
其中 trimDirectiveWhitespaces="true" 非常关键,否则 JSP 文件顶部的指令会导致输出流开头产生一个额外的换行符,在部分严格的客户端解析器中可能会直接触发 JSON 语法解析错误。
四、前端实现:使用 Fetch 与 XMLHttpRequest 发起调用
在前端,现代浏览器普遍推荐使用简洁的 Fetch API(基于 Promise),在需要支持较旧版本环境时,也可以使用经典的 XMLHttpRequest。
1. 现代标准:Fetch API 实现示例
// 1. 发起 GET 请求(参数拼接在 URL 中)
async function checkUsername(username) {
const resultDiv = document.getElementById("status-msg");
resultDiv.textContent = "正在校验中...";
try {
// 携带编码后的查询字符串
const url = `/api/user-check?username=${encodeURIComponent(username)}`;
const response = await fetch(url, {
method: "GET",
headers: {
"Accept": "application/json"
}
});
if (!response.ok) {
throw new Error(`HTTP 异常状态码: ${response.status}`);
}
const data = await response.json();
if (data.available) {
resultDiv.style.color = "#438A80";
resultDiv.textContent = `✓ ${data.message}`;
} else {
resultDiv.style.color = "#D97706";
resultDiv.textContent = `✗ ${data.message}`;
}
} catch (error) {
resultDiv.style.color = "#DC2626";
resultDiv.textContent = `请求失败: ${error.message}`;
}
}
// 2. 发起 POST 请求(通过表单编码传递参数)
async function submitUser(username, role) {
const params = new URLSearchParams();
params.append("username", username);
params.append("role", role);
try {
const response = await fetch("/api/user-check", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
},
body: params.toString()
});
const data = await response.json();
console.log("提交成功:", data);
} catch (err) {
console.error("提交异常:", err);
}
}
2. 传统兼容方案:XMLHttpRequest 示例
function checkUsernameLegacy(username) {
var xhr = new XMLHttpRequest();
var url = "/api/user-check?username=" + encodeURIComponent(username);
xhr.open("GET", url, true);
xhr.onreadystatechange = function () {
// readyState 为 4 代表请求已完全接收
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
try {
var data = JSON.parse(xhr.responseText);
console.log("返回数据:", data);
} catch (e) {
console.error("JSON 格式解析错误:", e);
}
} else {
console.error("服务端响应非成功状态:", xhr.status);
}
}
};
xhr.send(null);
}
五、GET 与 POST 传参机制与配置对比
在调用 Servlet 时,选择 GET 还是 POST 取决于操作的语义与数据特性。GET 主要用于获取、检索数据,参数显式暴露在 URL 中;POST 主要用于提交数据、修改服务端状态或传输较大体量的数据。
| 对比维度 | GET 请求 | POST 请求 (表单格式) | POST 请求 (JSON 格式) |
|---|---|---|---|
| 前端 Content-Type | 无需设置 | application/x-www-form-urlencoded | application/json;charset=UTF-8 |
| 参数传递方式 | URL 问号拼接 | body 字符串 (key1=v1&key2=v2) | body 字符串 (JSON.stringify) |
| 后端 Servlet 取值 | request.getParameter() |
request.getParameter() |
读取 request.getInputStream() |
| 浏览器历史记录 | 保留并可见 | 不保留敏感参数 | 不保留敏感参数 |
六、常见问题排查与关键排错方案
在实际联调过程中,开发者最常遇到的是 404 路径错误、中文字符乱码以及 JSON 解析失败等问题。根据以下要点可快速定位并修复:
1. 404 找不到资源的路径排查
在 Java Web 项目中,很多初学者常因混淆“应用上下文根(Context Path)”而导致 404 错误:
- 如果项目部署路径为
http://localhost:8080/myproject/,在前端使用绝对根路径fetch("/api/user-check"),实际请求地址会变成http://localhost:8080/api/user-check,导致找不到该 Servlet。 - 解决办法:在页面渲染时获取真实的 ContextPath(例如 JSP 中使用
${pageContext.request.contextPath}),拼接完整地址:`${contextPath}/api/user-check`;或者在页面同级目录下采用相对路径api/user-check。
2. 中文乱码处理准则
乱码分为“请求传参乱码”与“响应输出乱码”两类:
- 请求参数乱码:前端传中文时务必使用
encodeURIComponent()进行编码;在 Servlet 的doPost中必须第一时间执行request.setCharacterEncoding("UTF-8");。 - 响应数据乱码:在调用
response.getWriter()前,必须设置response.setContentType("application/json;charset=UTF-8");。
3. 前端报 “SyntaxError: Unexpected token < in JSON”
当浏览器控制台报该错误时,意味着前端调用 response.json() 时,接收到的其实并不是合法的 JSON,而是以 < 开头的 HTML 代码。
NullPointerException),Tomcat 拦截后直接向客户端输出了默认的 500 HTML 报错页面。前端期望解析 JSON,解析器遇到 <!DOCTYPE html> 即直接报错崩溃。此时应先在浏览器开发者工具的 Network 面板中查看 Response 原始返回内容,定位 Java 端异常堆栈。
七、全流程排查与技术矩阵总结
通过合理设计前后端通信契约,JavaScript 的异步调用能力能与 Java Web 后端稳定契合。在实际开发中,保持以下四个维度的核查即可保障接口健壮:
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。