从 Java 网络项目构建 WAR 和可自执行的 JAR

Build WAR and self-executable JAR from Java web project

我有一个 Java servlets 项目,我想构建一个 WAR 以部署到服务器和一个可执行 JAR,其中包含一个可以 运行 独立的嵌入式 Jetty 服务器。 该项目如下所示:

HelloWorldServlets
  common
    src/main
      java
        HelloServlet.java
      webapp
        index.jsp
    build.gradle
  jetty
    src/main
      java
        JettyServer.java
    build.gradle
  build.gradle

jetty 导入 common 作为编译依赖项。构建任务是:

jar {
  manifest { attributes "Main-Class": "JettyServer" }
  from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) })
}

jarcommon的任务如下:

jar {
  sourceSets.main.resources.srcDirs += ["src/main/webapp"]
}

包含网络资源 common.jar 并且 common.jarjetty.jar 内被展平,因此 jetty.jar 的根目录中有资源,但是将服务器设置为:

Server server = new Server(8080);
WebAppContext context = new WebAppContext();
server.setHandler(context);

context.setResourceBase("/");
context.setContextPath("/");
context.addServlet(Hello.class, "");

总是导致 HTTP ERROR 404 Problem accessing /index.jsp.

我不应该将 common.jar 扁平化为 jetty.jar 还是我遗漏了一些关于 ResourceBase 的信息?谢谢!

您的代码示例中的一些注意事项。

  • 由于您希望使用 JSP,因此您必须满足 JSP 的最低要求。
  • setResourceBase(String) 必须是绝对路径 and/or URI 引用(无相对路径)(JSP 要求)
  • 必须正确定义 DefaultServlet。 (JSP 要求)
  • 添加 Servlet(或过滤器)时,必须使用有效的 url 模式。 (Servlet 要求)
  • 在您的处理程序树中添加 DefaultHandler 最后,因为当您有上下文 and/or 处理程序错误需要排除故障时,它会有所帮助。

出现问题的最常见原因是使用 WebAppContext 会导致强制执行标准 Servlet 类加载器隔离,这很可能会导致您出现问题。

要么破坏类加载器...

Server server = new Server(8080);

// Figure out what path to serve content from
ClassLoader cl = DemoProject.class.getClassLoader();
// We look for a file, as ClassLoader.getResource() is not
// designed to look for directories (we resolve the directory later)
URL f = cl.getResource("jsp-root/index.jsp");
if (f == null)
{
    throw new RuntimeException("Unable to find resource directory");
}

// Resolve file to directory
URI webRootUri = f.toURI().resolve("./").normalize();
System.err.println("WebRoot is " + webRootUri);

WebAppContext context = new WebAppContext();
context.setBaseResource(Resource.newResource(webRootUri));
context.setContextPath("/");
context.addServlet(Hello.class, "/hello");
context.setParentLoaderPriority(true); // use server classloader first

HandlerList handlers = new HandlerList();
handlers.addHandler(context);
handlers.addHandler(new DefaultHandler()); // for errors when request doesn't match above handlers
server.setHandler(handlers);

...或者只是不使用 WebAppContext ...

Server server = new Server(8080);

// Figure out what path to serve content from
ClassLoader cl = DemoProject.class.getClassLoader();
// We look for a file, as ClassLoader.getResource() is not
// designed to look for directories (we resolve the directory later)
URL f = cl.getResource("jsp-root/index.jsp");
if (f == null)
{
    throw new RuntimeException("Unable to find resource directory");
}

// Resolve file to directory
URI webRootUri = f.toURI().resolve("./").normalize();
System.err.println("WebRoot is " + webRootUri);

ServletContextHandler context = new ServletContextHandler();
context.setBaseResource(Resource.newResource(webRootUri));
context.setContextPath("/");
context.addServlet(Hello.class, "/hello");

// Must be added last, must be named "default" (JSP and Servlet requirement)
ServletHolder holderDef = new ServletHolder("default", DefaultServlet.class);
holderDef.setInitParameter("dirAllowed","false");
context.addServlet(holderDef,"/"); // Using "default" url-pattern (JSP and Servlet requirement)

HandlerList handlers = new HandlerList();
handlers.addHandler(context);
handlers.addHandler(new DefaultHandler()); // for errors when request doesn't match above handlers
server.setHandler(handlers);

但请注意,要在 ServletContextHandler 上启用 JSP,您还有更多工作要做。

详情见:https://github.com/jetty-project/embedded-jetty-jsp