【问题标题】:How to put HttpServlet and WebSocketServlet in same WAR file for Jetty 9?如何将 HttpServlet 和 WebSocketServlet 放在 Jetty 9 的同一个 WAR 文件中?
【发布时间】:2017-04-11 22:46:14
【问题描述】:

这是我自定义的HttpServlet 实现:

public class AdminServlet extends HttpServlet
{
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        response.setContentType("text/html");
        response.setStatus(HttpServletResponse.SC_OK);
        response.getWriter().println("<h1>Hello Servlet</h1>");
    }
}

这是我自定义的WebSocketServlet 实现:

public class WsServlet extends WebSocketServlet {
    @Override
    public void configure(WebSocketServletFactory factory) {
        factory.register(MyListener.class);
    }
}

这是WEB-INF/web.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<web-app metadata-complete="false" version="3.1" 
         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_3_1.xsd">

    <servlet>
        <servlet-name>WsServlet</servlet-name>
        <servlet-class>de.afarber.websockets.WsServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>WsServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>AdminServlet</servlet-name>
        <servlet-class>de.afarber.websockets.AdminServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>AdminServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

这里是$JETTY_BASE/webapps/admin.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" 
    "http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">

    <Set name="contextPath">/admin</Set>
    <Set name="war"><SystemProperty name="jetty.base"/>/webapps/ws-servlet-0.1-SNAPSHOT.war</Set>

</Configure>

最后,这是$JETTY_BASE/webapps/ws.xml文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" 
        "http://www.eclipse.org/jetty/configure_9_0.dtd">
    <Configure class="org.eclipse.jetty.webapp.WebAppContext">

        <Set name="contextPath">/ws</Set>
        <Set name="war"><SystemProperty name="jetty.base"/>/webapps/ws-servlet-0.1-SNAPSHOT.war</Set>

    </Configure>

当我启动独立的 Jetty 9(deploy 和其他模块处于活动状态)时,我收到错误消息:

2016-11-28 09:59:40.994:INFO:oejs.Server:main: jetty-9.3.12.v20160915
2016-11-28 09:59:41.023:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///C:/Users/U299FAV/slova/jetty.base/webapps/] at interval 1
2016-11-28 09:59:41.152:INFO:oejsh.ContextHandler:main: Started o.e.j.s.h.ContextHandler@783e6358{/words,null,AVAILABLE}
2016-11-28 09:59:41.165:INFO:oejsh.ContextHandler:main: Started o.e.j.s.h.ContextHandler@7dc7cbad{/twentythirteen-child,null,AVAILABLE}
2016-11-28 09:59:41.950:INFO:oeja.AnnotationConfiguration:main: Scanning elapsed time=307ms
2016-11-28 09:59:41.970:INFO:oejw.StandardDescriptorProcessor:main: NO JSP Support for /ws, did not find org.eclipse.jetty.jsp.JettyJspServlet
2016-11-28 09:59:41.992:WARN:oejw.WebAppContext:main: Failed startup of context o.e.j.w.WebAppContext@5f2108b5{/ws,file:///C:/Users/U299FAV/AppData/Local/Temp/jetty-0.0.0.0-8080-ws-servlet-0.1-SNAPSHOT.war-_ws-any-239390
3927144372923.dir/webapp/,UNAVAILABLE}{/ws-servlet-0.1-SNAPSHOT.war}
java.lang.IllegalStateException: Multiple servlets map to path: /: AdminServlet,WsServlet
        at org.eclipse.jetty.servlet.ServletHandler.updateMappings(ServletHandler.java:1504)
        at org.eclipse.jetty.servlet.ServletHandler.doStart(ServletHandler.java:156)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:105)
        at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
        at org.eclipse.jetty.security.SecurityHandler.doStart(SecurityHandler.java:361)
        at org.eclipse.jetty.security.ConstraintSecurityHandler.doStart(ConstraintSecurityHandler.java:448)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:105)
        at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
        at org.eclipse.jetty.server.handler.ScopedHandler.doStart(ScopedHandler.java:120)
        at org.eclipse.jetty.server.session.SessionHandler.doStart(SessionHandler.java:116)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:105)
        at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
        at org.eclipse.jetty.server.handler.ScopedHandler.doStart(ScopedHandler.java:120)
        at org.eclipse.jetty.server.handler.ContextHandler.startContext(ContextHandler.java:809)
        at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:345)
        at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1404)
        at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1366)
        at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:778)
        at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:262)
        at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:520)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
        at org.eclipse.jetty.deploy.bindings.StandardStarter.processBinding(StandardStarter.java:41)
        at org.eclipse.jetty.deploy.AppLifeCycle.runBindings(AppLifeCycle.java:188)
        at org.eclipse.jetty.deploy.DeploymentManager.requestAppGoal(DeploymentManager.java:499)
        at org.eclipse.jetty.deploy.DeploymentManager.addApp(DeploymentManager.java:147)
        at org.eclipse.jetty.deploy.providers.ScanningAppProvider.fileAdded(ScanningAppProvider.java:180)
        at org.eclipse.jetty.deploy.providers.WebAppProvider.fileAdded(WebAppProvider.java:458)
        at org.eclipse.jetty.deploy.providers.ScanningAppProvider$1.fileAdded(ScanningAppProvider.java:64)
        at org.eclipse.jetty.util.Scanner.reportAddition(Scanner.java:610)
        at org.eclipse.jetty.util.Scanner.reportDifferences(Scanner.java:529)
        at org.eclipse.jetty.util.Scanner.scan(Scanner.java:392)
        at org.eclipse.jetty.util.Scanner.doStart(Scanner.java:313)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
        at org.eclipse.jetty.deploy.providers.ScanningAppProvider.doStart(ScanningAppProvider.java:150)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
        at org.eclipse.jetty.deploy.DeploymentManager.startAppProvider(DeploymentManager.java:561)
        at org.eclipse.jetty.deploy.DeploymentManager.doStart(DeploymentManager.java:236)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131)
        at org.eclipse.jetty.server.Server.start(Server.java:411)
        at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:113)
        at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61)
        at org.eclipse.jetty.server.Server.doStart(Server.java:378)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
        at org.eclipse.jetty.xml.XmlConfiguration$1.run(XmlConfiguration.java:1516)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.eclipse.jetty.xml.XmlConfiguration.main(XmlConfiguration.java:1441)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.eclipse.jetty.start.Main.invokeMain(Main.java:214)
        at org.eclipse.jetty.start.Main.start(Main.java:457)
        at org.eclipse.jetty.start.Main.main(Main.java:75)

我的问题是:

如何使AdminServletWsServlet 共存于同一个WAR 文件中?

当我评论两者之一时,一切都按预期工作。

【问题讨论】:

    标签: servlets jetty war jetty-9


    【解决方案1】:

    只需在你的扩展WebSocketServlet中实现doGet方法,毕竟它只是一个普通的HttpServlet,有WebSocket升级知识。

    这是一个工作示例...

    package jetty.websocket;
    
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.eclipse.jetty.server.Server;
    import org.eclipse.jetty.servlet.ServletContextHandler;
    import org.eclipse.jetty.websocket.api.Session;
    import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
    import org.eclipse.jetty.websocket.api.annotations.WebSocket;
    import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
    import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
    
    public class MultiPurposeServletExample
    {
        public static void main(String[] args)
        {
            try
            {
                Server server = new Server(8080);
    
                ServletContextHandler context = new ServletContextHandler();
                context.setContextPath("/");
                context.addServlet(MultiPurposeServlet.class, "/multi");
    
                server.setHandler(context);
    
                server.start();
                server.join();
            }
            catch (Throwable t)
            {
                t.printStackTrace();
            }
        }
    
        @WebSocket
        public static class MultiPurposeSocket
        {
            @OnWebSocketMessage
            public void onMessage(Session session, String msg)
            {
                session.getRemote().sendStringByFuture("'" + msg + "' echo from " + this.getClass().getName());
            }
        }
    
        public static class MultiPurposeServlet extends WebSocketServlet
        {
            @Override
            public void configure(WebSocketServletFactory factory)
            {
                factory.register(MultiPurposeSocket.class);
            }
    
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
            {
                resp.setContentType("text/plain");
                resp.getWriter().println("Hello from " + this.getClass().getName());
            }
        }
    }
    

    如果你用 HTTP 请求点击它,你会得到......

    $ curl http://localhost:8080/multi
    Hello from jetty.websocket.MultiPurposeServletExample$MultiPurposeServlet
    

    如果您从 websocket 客户端连接到它并发送一条消息,您会得到...

    'Rock it with HTML5 WebSocket' echo from jetty.websocket.MultiPurposeServletExample$MultiPurposeSocket
    

    提示:使用http://websocket.org/echo.html 并使用ws://localhost:8080/multi 的“位置”来测试websocket 连接。

    【讨论】:

      【解决方案2】:

      如果您查看servlet-mapping 部分,您的两个servlet 都映射到同一个URL。如果是这样,容器不知道它应该将您的请求路由到给定 URL 的哪个 servlet(在您的情况下是 / - root)。

      &lt;url-pattern&gt;/&lt;/url-pattern&gt; 的 URL 更改为至少一个 servlet 的另一个 URL,例如,如果您要将后者更改为

      <servlet-mapping>
          <servlet-name>AdminServlet</servlet-name>
          <url-pattern>/AdminServlet</url-pattern>
      </servlet-mapping>
      

      例如,您的应用程序应该启动并且两个 servlet 都可用,但在不同的 URL 上。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-30
        • 1970-01-01
        • 2015-07-17
        • 1970-01-01
        • 1970-01-01
        • 2019-02-04
        • 2013-01-05
        • 1970-01-01
        相关资源
        最近更新 更多