之前在 Eclipse 上使用 Tomcat 运行使用了 Spring Web 的应用一直正常,但是打包部署到 Jetty 运行就出现 404 的问题,查看日志 Spring 容器启动也一切正常,找不到原因。

换而使用 Maven Jetty Plugin 运行的时候也同样出现了问题。

1
2
3
4
5
@RequestMapping("/")
public String index(@RequestParam(defaultValue = "1", value = "p") int p,
Model model) {
return "/home/index"; // 在 Jetty 中运行会有多余的前置路径分隔符
}

404 显示找不到 webapp/WEB-INF/jsp//home/index.jsp 多了一层路径

查看 Servlet API

Returns a RequestDispatcher object that acts as a wrapper for the resource located at the given path. A RequestDispatcher object can be used to forward a request to the resource or to include the resource in a response. The resource can be dynamic or static.
The pathname specified may be relative, although it cannot extend outside the current servlet context. If the path begins with a “/“ it is interpreted as relative to the current context root. This method returns null if the servlet container cannot return a RequestDispatcher.
The difference between this method and ServletContext.getRequestDispatcher(java.lang.String) is that this method can take a relative path.

Spring Web 测试源码 spring-web/src/test/java/org/springframework/mock/web/test/MockServletContext.java

会在路径前面判断加上分隔符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* Build a full resource location for the given path, prepending the resource
* base path of this {@code MockServletContext}.
* @param path the path as specified
* @return the full resource path
*/
protected String getResourceLocation(String path) {
if (!path.startsWith("/")) {
path = "/" + path;
}
return this.resourceBasePath + path;
}
public RequestDispatcher getRequestDispatcher(String path) {
Assert.isTrue(path.startsWith("/"),
() -> "RequestDispatcher path [" + path + "] at ServletContext level must start with '/'");
return new MockRequestDispatcher(path);
}

Jetty 相对 Tomcat 两种写法有差异,所以导致使用 Spring MVC 运行的时候会叠加上多余的路径分隔符