java - Jetty:默认的 servlet 上下文路径

标签 java servlets jetty embedded-jetty

我需要设置 Servlet(由于某些原因只有 servlet 而不是处理程序)以在 war 之外处理文件。这里https://stackoverflow.com/a/28735121/5057736我找到了以下解决方案:

Server server = new Server(8080);

ServletContextHandler ctx = new ServletContextHandler();
ctx.setContextPath("/");

DefaultServlet defaultServlet = new DefaultServlet();
ServletHolder holderPwd = new ServletHolder("default", defaultServlet);
holderPwd.setInitParameter("resourceBase", "./src/webapp/");

ctx.addServlet(holderPwd, "/*");//LINE N
ctx.addServlet(InfoServiceSocketServlet.class, "/info");

server.setHandler(ctx);

此解决方案有效,这正是我所需要的。但是,一旦我将 LINE N 更改为 ctx.addServlet(holderPwd, "/foo/*");,它就会停止工作。我尝试了“/foo/”、“/foo”,但结果是一样的——我得到了not found。为什么?我怎样才能让它在这个特定的上下文中工作?出于同样的原因,我使用 jetty 9.2.15。

最佳答案

DefaultServlet旨在查看 contextPath 之后的请求 URI .

在您的示例代码中,当您将 servlet 的 url-pattern 从 / 更改为至 /foo/*在磁盘上查找的结果文件现在包括 /foo/部分。

换句话说,一个请求URI /css/main.css结果它期望找到的文件(在磁盘上)为 ./src/webapp/foo/css/main.css

您的示例有一些缺陷。为您的 ServletContextHandler 准备一个空的资源库是不明智的, 作为 ServletContext本身需要访问该配置值。

您可以通过删除...来解决这个问题

holderPwd.setInitParameter("resourceBase", "./src/webapp/");

并使用 ServletContextHandler.setBaseResource(Resource)相反......

ctx.setResourceBase(Resource.newResource(new File("./src/webapp")));

这将允许以下 ServletContext方法(被无数 servlet 库使用)也能正常工作

  • String getRealPath(String path)
  • URL getResource(String path)
  • InputStream getResourceAsStream(String path)
  • Set<String> getResources(String path)

最后,要使此设置在 ServletContextHandler 中正常运行,您将添加 default Servlet 名称,在“默认 url 模式”上,恰好实现为 DefaultServlet .

像这样:

// Lastly, the default servlet for root content
// It is important that this is added last.
String defName = "default"; // the important "default" name
ServletHolder holderDef = new ServletHolder(defName, DefaultServlet.class);
holderDef.setInitParameter("dirAllowed","true");
ctx.addServlet(holderDef,"/"); // the servlet spec "default url-pattern"

现在,如果您需要从请求 URI /foo/* 提供静态内容从不属于 webapp 的目录中,你也可以这样做。 这将需要您设置另一个 DefaultServlet不参加 ServletContext .

此设置的示例是...

package jetty;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.resource.PathResource;

import java.io.File;
import java.nio.file.Path;

public class ManyDefaultServlet
{
    public static void main(String[] args) throws Exception {
        Server server = new Server();
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(8080);
        server.addConnector(connector);

        // The filesystem paths we will map
        Path homePath = new File(System.getProperty("user.home")).toPath().toRealPath();
        Path pwdPath = new File(System.getProperty("user.dir")).toPath().toRealPath();

        // Setup the basic application "context" for this application at "/"
        // This is also known as the handler tree (in jetty speak)
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        context.setBaseResource(new PathResource(pwdPath));
        server.setHandler(context);

        // Fist, add special pathspec of "/home/" content mapped to the homePath
        ServletHolder holderHome = new ServletHolder("static-home", DefaultServlet.class);
        holderHome.setInitParameter("resourceBase",homePath.toUri().toASCIIString());
        holderHome.setInitParameter("dirAllowed","true");
        // Use request pathInfo, don't calculate from contextPath
        holderHome.setInitParameter("pathInfoOnly","true");
        context.addServlet(holderHome,"/foo/*"); // must end in "/*" for pathInfo to work

        // Lastly, the default servlet for root content
        // It is important that this is last.
        String defName = "default"; // the important "default" name
        ServletHolder holderDef = new ServletHolder(defName, DefaultServlet.class);
        holderDef.setInitParameter("dirAllowed","true");
        context.addServlet(holderDef,"/"); // the servlet spec "default url-pattern"

        server.start();
        server.join();
    }
}

这使用第二个 DefaultServlet ,为此使用独特的资源库 DefaultServlet仅,并映射到以 /* 结尾的 url 模式.

最后,这一秒的初始化参数DefaultServlet被告知使用请求 URI 的 pathInfo,而不是像通常那样在 contextPath 上拆分。

For more information on what this whole pathInfo, request URI, contextPath, and url-patterns ending in /* are all about, see the useful answer by @30thh

这个独立的DefaultServlet不参与申报ServletContext图书馆将无法查看或访问该 DefaultServlet 中的内容通过 ServletContext方法。但是,所有传入的 HTTP 客户端请求都可以通过该 url 模式轻松请求内容。

关于java - Jetty:默认的 servlet 上下文路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39011587/

相关文章:

java - servlet 上的 jhipster 注入(inject)

java - hibernate 搜索 : configure Facet for custom FieldBridge

java - Intellij IDEA : equivalent of Eclipse's "Complete Current Statement" (Ctrl+Shift+Enter)?

java - quartz : The Scheduler has been shutdown

web-services - 你能通过 HTTPS 运行soap吗?

java - 从jetty中运行的Web应用程序访问本地目录图像

java - jetty 嵌入式: Using CORS + Basic authentication (ConstraintSecurityHandler)

java - RedisTemplate getExpire() 在 Springcache 中返回意外值

MySQL 注册器数据使用 setString 数据,但不使用 getParameter

java - Spring mvc 将数据发送到 Controller