在 Jetty 9 中访问 {war}/WEB-INF/classes 中使用 @Path 注解的类时出现 404 错误

问题描述 投票:0回答:1

这是我在 Eclipse 中的设置:

有2个项目....clinixwip11Appl和clinixwip11Jtty

clinixwip11Jtty 的目的是启动 Jetty 的实例...如下...

public class JttyMain{

    public static void main(String[] args) throws Exception {
        
        int             iPort       =   0;
        ClassList       clssList    =   null;
        Server          jttySrvr    =   null;
        ServletHolder   srvtHldr    =   null;
        WebAppContext   wappCtxt    =   null;
        
        if (args.length != 1) {
            System.err.println("Usage: need a relative path to the war file to execute");
            System.exit(1);
        }
        System.setProperty("org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StrErrLog");
        System.setProperty("org.eclipse.jetty.LEVEL", "INFO");
        
        iPort           =   Integer.parseInt(System.getenv().getOrDefault("PORT", "8080"));
        jttySrvr        =   new Server(iPort);
        System.out.println("jttySrvr created and listening at 8080");
        jttySrvr.addLifeCycleListener(new CustomLifeCycleListener());
        wappCtxt        =   new WebAppContext();
        wappCtxt.setContextPath("/");
        wappCtxt.setWar(args[0]);
        wappCtxt.setConfigurations(new Configuration[]  {
            new AnnotationConfiguration(),
            new WebInfConfiguration(),
         });
        wappCtxt.setAttribute   ("org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern", ".*/target/classes/|.*/classes/.");
        System.out.println("wappCtxt created");
        srvtHldr        =   wappCtxt.addServlet(DefaultServlet.class, "/");
        srvtHldr.setInitParameter("jersey.config.server.provider.packages", "com.applix.cliniX.serverApp");
        srvtHldr.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters", "com.applix.cliniX.serverApp.filter.ResponseFilter");
        srvtHldr.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters", "com.applix.cliniX.serverApp.filter.RequestFilter");
        System.out.println("srvtHldr created and initialized");
        clssList        =   ClassList.setServerDefault(jttySrvr);
        clssList.addBefore  (
            "org.eclipse.jetty.webapp.WebXmlConfiguration",
            "org.eclipse.jetty.annotations.AnnotationConfiguration"
        );
        jttySrvr.setHandler(wappCtxt);
        System.out.println("before starting jttySrvr");
        jttySrvr.start();
        System.out.println("after starting jttySrvr");
        jttySrvr.join();
        System.out.println("after joining with main thread");
    }
    
    public static class CustomLifeCycleListener implements LifeCycle.Listener   {
        @Override
        public void lifeCycleStarting(LifeCycle event)  {
            System.out.println("JTTYMAIN Starting at " + new Date(System.currentTimeMillis()) + " : " + event);
        }

        @Override
        public void lifeCycleStarted(LifeCycle event)   {
            System.out.println("JTTYMAIN Started: at " + new Date(System.currentTimeMillis()) + " : " + event);
        }

        @Override
        public void lifeCycleFailure(LifeCycle event, Throwable cause)  {
            System.out.println("JTTYMAIN Failure: at " + new Date(System.currentTimeMillis()) + " : " + event);
            cause.printStackTrace(System.out);
        }

        @Override
        public void lifeCycleStopping(LifeCycle event)  {
            System.out.println("JTTYMAIN Stopping: at " + new Date(System.currentTimeMillis()) + " : " + event);
        }

        @Override
        public void lifeCycleStopped(LifeCycle event)   {
            System.out.println("JTTYMAIN Stopped: at " + new Date(System.currentTimeMillis()) + " : " + event);
        }
    }
}

因为这应该在 Google App Engine 上运行,所以

app.yaml
中有
clinixwip11Appl/src/main/appengine
文件:

runtime: java11
instance_class: F2
entrypoint: 'java -cp "*" com.applix.clinix.clinixwip11Jtty.JttyMain clinixwip11Appl.war'

当 maven 构建 2 个项目时,有两个输出部署到 Google App Engine:

(1)

clinixwip11Jtty.jar
(包含 JttyMain.class) (2)
clinixwip11Appl.war
(包含我的appl代码)....如下:

部署代码后,我可以看到 Jetty 实例启动,并且我能够成功访问位于

/index.html
根目录的
/main.html
clinixwip11Appl.war

但是,当访问

classes
clinixwip11Appl.war
文件夹中的任何类时,我会收到 404。

classes 文件夹包含许多已编译的类......我已经从下面的类之一复制了相关代码......

@Path("/estbStaffCard")
public  class   EstbStaffCardController {
    
@Context 
    private         HttpServletRequest  request             =   null;
    private static  Logger              logger              =   Logger.getLogger("EstbStaffCardController");
        
    @GET
    @Path("/getEstbForEstbStaffIden")
    @Consumes(MediaType.TEXT_PLAIN)
    @Produces(MediaType.TEXT_PLAIN)
    public  synchronized    Response    getEstbForEstbStaffIden (@QueryParam("queryString") String paramQueryString)    {

        logger.info("//////////////////////////////////////////////////////////////////////////////////////");
        logger.info("begin new method: " + new Object(){}.getClass().getEnclosingMethod().getName());
    .......
        }
    }

因此,当访问

{URL to app engine}/estbStaffCard/getEstbForEstbStaffIden...
时,我会得到 404。

我尝试了各种在 JttyMain 类中指定配置选项的选项,这些选项在网络上的众多线程中指定,特别是在 stackoverflow 上,但没有效果。

您知道需要在上面的 JttyMain 类中指定什么配置,以便

clinixwip11Appl.war
的类文件夹中的类得到尊重吗?过去三天我一直在做这个。请帮忙。

在战争中的这个地点...

web.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="4.0" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
   http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd">
<!--  

    <init-param>
        <param-name>org.glassfish.jersey.server.ServerProperties.DisableWADL</param-name>
        <param-value>true</param-value>
    </init-param>
    
    <httpProtocol>
        <customHeaders>
            <add name="X-Frame-Options" value="*" />
        </customHeaders>
    </httpProtocol>
    
--> 
    <servlet>
        <servlet-name>Jersey Web Application</servlet-name>
        <servlet-class>
            org.glassfish.jersey.servlet.ServletContainer
        </servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.applix.cliniX.serverApp</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
            <param-value>com.applix.cliniX.serverApp.filter.RequestFilter</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
            <param-value>com.applix.cliniX.serverApp.filter.ResponseFilter</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
        <servlet-name>_ah_sessioncleanup</servlet-name>
        <servlet-class>com.google.apphosting.utils.servlet.SessionCleanupServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>_ah_sessioncleanup</servlet-name>
        <url-pattern>/_ah/sessioncleanup</url-pattern>
    </servlet-mapping>
  
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>*</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
    <listener>
        <listener-class>com.applix.cliniX.serverApp.listener.SessionListener</listener-class>
    </listener>
</web-app>

我知道我没有做一些我需要做的关键事情,或者在

JttyMain
代码的这一部分中做得太过分:

wappCtxt.setConfigurations(new Configuration[]  {
            new AnnotationConfiguration(),
            new WebInfConfiguration(),
         });
        wappCtxt.setAttribute   ("org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern", ".*/target/classes/|.*/classes/.");
        System.out.println("wappCtxt created");
        srvtHldr        =   wappCtxt.addServlet(DefaultServlet.class, "/");
        srvtHldr.setInitParameter("jersey.config.server.provider.packages", "com.applix.cliniX.serverApp");
        srvtHldr.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters", "com.applix.cliniX.serverApp.filter.ResponseFilter");
        srvtHldr.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters", "com.applix.cliniX.serverApp.filter.RequestFilter");
        System.out.println("srvtHldr created and initialized");
        clssList        =   ClassList.setServerDefault(jttySrvr);
        clssList.addBefore  (
            "org.eclipse.jetty.webapp.WebXmlConfiguration",
            "org.eclipse.jetty.annotations.AnnotationConfiguration"
        );

任何帮助将不胜感激。

发现扫描哪些 Jar 文件以查找发现的注释 这里。所以现在我想知道我哪里出了问题?有什么提示、线索、帮助吗?

更新: 看来 Jetty 只使用一个类路径,命名为 war 文件的根目录,因为 index.html 和 main.html 以及位于其中的所有其他资源....css/、images/、html/ 等正在加载。只有 WEB-INF/类不被尊重。所以问题归结为让 Jetty 知道 WEB-INF/classes 和 WEB-INF/lib 也需要被视为类路径的一部分。

问题是......如何让 Jetty 知道这一点??

++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++在实验后于 2024 年 1 月 30 日星期二添加了以下内容 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++

我的目标: 按照 Google App Engine 的要求从 Java8 升级到 Java11

问题: 通过 Java8,Google App Engine 用于提供 RESTful 服务器的预构建实现

使用 Java11,Google App Engine 将不会提供这样的服务器,开发人员有责任构建提供这样的服务器

我的结论(关于maven和版本的东西)经过上述实验...... (1) 对于上述目标,我将能够使用 Java11 编译器,但我必须将目标设置为 Java8 (2) 我将不得不使用 2.25 版本的球衣服务器和 10.0.19 版本的其他工件

但是还有更多...... 我的应用程序有许多由前端使用 REST 访问的服务。我的应用程序也有很多静态资源。 因此,为了提供这两种资源,如果我使用以下设置,

HandlerCollection handlerCollection = new HandlerCollection();
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
handlerCollection.addHandler(context);
        
jettyServer.setHandler(handlerCollection);
        
ServletHolder jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, "/*");
jerseyServlet.setInitOrder(0);
        jerseyServlet.setInitParameter("jersey.config.server.provider.packages", "com.rest.test");
ServletHolder staticHolder = new ServletHolder(new DefaultServlet());
staticHolder.setInitParameter("pathInfoOnly", "true");
URL webAppDir = App.class.getClassLoader().getResource("META-INF/resources");
staticHolder.setInitParameter("resourceBase", webAppDir.toURI().toString());
context.addServlet(staticHolder, "/*");        

jettyServer.start();

我在服务器启动时收到此错误......

Exception in thread "main" java.lang.IllegalStateException: Multiple servlets map to path /*

    

但是如果我使用以下设置......

HandlerCollection handlerCollection = new HandlerCollection();
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
handlerCollection.addHandler(context);
jettyServer.setHandler(handlerCollection);
ServletHolder jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, "/");
jerseyServlet.setInitOrder(0);
jerseyServlet.setInitParameter("jersey.config.server.provider.packages", "com.rest.test");
ServletHolder staticHolder = new ServletHolder(new DefaultServlet());
staticHolder.setInitParameter("pathInfoOnly", "true");
URL webAppDir = App.class.getClassLoader().getResource("META-INF/resources");
staticHolder.setInitParameter("resourceBase", webAppDir.toURI().toString());
context.addServlet(staticHolder, "/*");       

I can only access static content but not the REST content

如果我使用以下设置......

HandlerCollection handlerCollection = new HandlerCollection();
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
handlerCollection.addHandler(context);
jettyServer.setHandler(handlerCollection);
ServletHolder jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, "/rest/*");
jerseyServlet.setInitOrder(0);
jerseyServlet.setInitParameter("jersey.config.server.provider.packages", "com.rest.test");
ServletHolder staticHolder = new ServletHolder(new DefaultServlet());
staticHolder.setInitParameter("pathInfoOnly", "true");
URL webAppDir = App.class.getClassLoader().getResource("META-INF/resources");
staticHolder.setInitParameter("resourceBase", webAppDir.toURI().toString());
context.addServlet(staticHolder, "/*");


**I can access static content and also the REST content**

经过上述实验后我的问题(关于提供静态和 REST 内容)...... 我现在是否必须去更改我的源代码(基本上每个 REST 资源都带有 /rest 前缀)才能使上述内容正常工作? 我知道,使用 Java8 和 GAE 提供的默认 REST 实现,我能够在 /

提供静态和 REST 资源
google-app-engine annotations jetty classloader embedded-jetty
1个回答
0
投票

您的

org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern
设置仅对开发/测试/IDE时间有效。摆脱它进行生产。

你的主类没有做任何特别的事情。为什么有它?

WAR 文件本身就包含了它所需要的一切

WEB-INF/web.xml

我会跳过自定义入口点、跳过主类、跳过入口点 jar,然后将该 WAR 文件部署到 GAE。

© www.soinside.com 2019 - 2024. All rights reserved.