
本文详解如何在 Java Servlet 中通过 @WebServlet 注解匹配含多个路径变量(如 /organization/{orgId}/location/{locId})的 RESTful URL,并正确解析路径参数,避免因数组索引错误导致 404 或空值问题。
本文详解如何在 java servlet 中通过 `@webservlet` 注解匹配含多个路径变量(如 `/organization/{orgid}/location/{locid}`)的 restful url,并正确解析路径参数,避免因数组索引错误导致 404 或空值问题。
在构建基于 Servlet 的轻量级 REST API 时,常需支持类似 api.xxx.com/organization/5/location/50 这样语义清晰的嵌套路由。虽然 @WebServlet("/organization/*/location/*") 能成功注册并拦截该路径,但实际解析 request.getPathInfo() 时极易因忽略路径分割逻辑而引发索引越界或取值错误——这正是原始代码返回 404 的根本原因。
关键在于理解 getPathInfo() 的返回值结构:
- 对请求
GET /organization/5/location/50,request.getPathInfo()返回"/organization/5/location/50"(注意开头的/); - 调用
.split("/")后得到数组:["", "organization", "5", "location", "50"](长度为 5,非 4); - 因此
pathInfo[1] == "organization",pathInfo[2] == "5"(组织 ID),pathInfo[4] == "50"(位置 ID)。
但原始代码中 if (pathInfo.length == 4) 判断条件本身就不成立(实际为 5),且错误地尝试访问 pathInfo[2] 和 pathInfo[4] —— 前者指向 "5"(看似巧合正确),后者却越界(索引 4 存在,但条件未满足导致分支未执行),最终逻辑未进入而返回 404。
✅ 正确做法如下:
立即学习“Java免费学习笔记(深入)”;
-
修正数组长度判断:应为
pathInfo.length >= 5(确保至少包含["", "organization", "{org}", "location", "{loc}"]); -
精准提取 ID 值:组织 ID 在索引
2,位置 ID 在索引4; - 增强健壮性:校验非空、数字格式,避免运行时异常。
优化后的完整示例代码:
import java.io.IOException;
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("/organization/*/location/*")
public class LocationServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String pathInfo = request.getPathInfo();
if (pathInfo == null || pathInfo.isEmpty()) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write("Missing path info");
return;
}
String[] parts = pathInfo.split("/");
// Expected: ["", "organization", "<orgId>", "location", "<locId>"]
if (parts.length < 5) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write("Invalid path format: expected /organization/{id}/location/{id}");
return;
}
String organizationId = parts[2].trim();
String locationId = parts[4].trim();
// 可选:基础校验
if (organizationId.isEmpty() || locationId.isEmpty()) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write("Organization ID and Location ID must be non-empty");
return;
}
// ✅ 安全获取参数,后续可对接 Service 层
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(
String.format("{"organizationId":"%s","locationId":"%s"}",
organizationId, locationId)
);
}
}⚠️ 注意事项:
-
@WebServlet的通配符*仅支持单层匹配(即/organization/*/location/*可匹配/organization/5/location/50,但不匹配/organization/5/extra/location/50);如需更灵活路由(如 Spring MVC 的@PathVariable),建议迁移到现代框架; - 生产环境务必对 ID 做合法性校验(如正则
\d+)、空值防护及异常捕获; - 避免直接拼接响应字符串,推荐使用 Jackson/Gson 序列化 JSON;
- 若需支持 POST/PUT 等方法,需重写对应
doPost()等方法,并注意Content-Type处理。
通过以上调整,即可稳定支持双路径参数的 RESTful 接口,兼顾 Servlet 规范兼容性与业务可维护性。


















