2014/8/4

Jetty - Part 2/2

接續上一次的說明,我們已經讓 Embedded Jetty Server 能夠支援 http 與 https 了,接下來就是要整合既有的 WebContent,使用 web.xml ,支援 JSP, Servlet 與 Filter 等等。最後,我們再處理要支援多個 WebAppContext 的問題。

WebAppContext

先前在提供網頁服務時,很單純地只有用 Handler 實作,但一個網站並不會這麼單純,一定包含了 servlet, jsp, event listener, filter, html, css, js, images 等等這些東西,換句話說,以往在 Eclipse 使用 Web Project 開發時,WebContent 裡面的資料都要能支援。

原本 setHandler 的地方,我們必須做個調整,改成使用 WebAppContext,然後把 context 指定給 server 的 handler。

// server.setHandler(new HelloHandler());

WebAppContext context = new WebAppContext();
context.setDescriptor("../WebContent/WEB-INF/web.xml");
context.setResourceBase("../WebContent");
context.setContextPath("/examples");
context.setParentLoaderPriority(true);

server.setHandler(context);

在這樣的方式調整下,我們就可以用 http://localhost:8080/examples/ 瀏覽網站。

更複雜的 web application

為了完整 web application 的功能,我們還必須做些調整。

  1. 支援 servlet 與 jsp 的 jar files
    在測試的過程中,我們發現只有 jetty-all 這個 jar 還是不夠的,必須額外增加一些 jar,我們可以在 jetty-distribution-9.2.2\lib 的目錄裡面找到。

     javax.el-3.0.0.jar
     javax.servlet.jsp.jstl-1.2.2.jar
     javax.servlet.jsp-2.3.2.jar
     javax.servlet.jsp-api-2.3.1.jar
     servlet-api-3.1.jar
  2. 讓 WebApplicationContext 支援 JSP
    我們必須在 web.xml 裡面增加以下這個 servlet 處理 JSP files

     <servlet id="jsp">
         <servlet-name>jsp</servlet-name>
         <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
         <init-param>
             <param-name>logVerbosityLevel</param-name>
             <param-value>DEBUG</param-value>
         </init-param>
         <init-param>
             <param-name>fork</param-name>
             <param-value>false</param-value>
         </init-param>
         <init-param>
             <param-name>keepgenerated</param-name>
             <param-value>true</param-value>
         </init-param>
         <load-on-startup>0</load-on-startup>
     </servlet>
    
     <servlet-mapping>
         <servlet-name>jsp</servlet-name>
         <url-pattern>*.jsp</url-pattern>
         <url-pattern>*.jspf</url-pattern>
         <url-pattern>*.jspx</url-pattern>
         <url-pattern>*.xsp</url-pattern>
         <url-pattern>*.JSP</url-pattern>
         <url-pattern>*.JSPF</url-pattern>
         <url-pattern>*.JSPX</url-pattern>
         <url-pattern>*.XSP</url-pattern>
     </servlet-mapping>
  3. jetty-web.xml
    在 WEB-INF 目錄中,增加一個 jetty-web.xml 檔案,讓 WebAppContext 支援 Http Session。

     <?xml version="1.0"  encoding="ISO-8859-1"?>
     <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
    
     <Configure class="org.eclipse.jetty.webapp.WebAppContext">
         <Get name="sessionHandler">
             <New class="org.eclipse.jetty.server.session.SessionHandler">
                 <Arg>
                     <New class="org.eclipse.jetty.server.session.HashSessionManager">
                         <Set name="storeDirectory">session</Set>
                     </New>
                 </Arg>
             </New>
         </Get>
     </Configure>
  4. 調整 filter-mapping
    測試過程中發現,如果將 filter-mapping 的 url-pattern 設定為 .jsp,瀏覽 jsp 網頁會一直無法先進入 filter 進行前置處理,因此要把 url-pattern 改成 /

     <filter-mapping>
         <filter-name>CookieLoginFilter</filter-name>
         <url-pattern>/*</url-pattern>
     </filter-mapping>
  5. ServletContextListener
    我們都是在 ServletContextListener 裡面處理 webapp 啟動時,必須要一併啟動的一些服務,例如 DB logback, spring, connection pool (dbcp) 還有一些 scheduler,很幸運的在 Jetty 都可以直接支援,不需要再修改程式。

  6. Dynamic Web Project 的路徑
    如果一開始是用 Eclipse 的 Dynamic Web Project 初始化專案,java 程式編譯後將會放在 project 的 /build/classes 目錄中。

    但如果程式中有使用到 ServletContext 的getResourceAsStream 的功能,再加上我們把 Jetty 的 WebAppContext 的 setResourceBase 指定到 WebContent 目錄,這時就會發生找不到檔案的問題。

    我們必須調整 project 設定,在 Java Build Path 中將 Default output folder 由 project/build/classes 改為 project/WebContent/WEB-INF/classes 。

就這樣修改到這邊,我們的 Embedded Jetty 已經可以支援一個 web application 了。

Multiple Contexts

通常我們會希望除了能支援一個 web context 之外,server 的 root context 也要能使用,因此我們參考 ManyContexts.java 的作法。

利用 ContextHandlerCollection 將多個 context handler 集合起來,然後再設定給 server 的 handler。

WebAppContext context = new WebAppContext();
context.setDescriptor("../WebContent/WEB-INF/web.xml");
context.setResourceBase("../WebContent");
context.setContextPath("/examples");
context.setParentLoaderPriority(true);

ContextHandler rootcontext = new ContextHandler("/");
rootcontext.setContextPath("/");
rootcontext.setHandler(new HelloHandler());

ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[] { rootcontext, context });

server.setHandler(contexts);