2016-10-14 21 views
2

有沒有辦法在Servlet 3.x容器中運行Jersey servlet容器(2.x)描述符作爲javax.servlet.Filter?我要爲靜態資源旁邊我的服務,因此需要使用根據的Javadoc無描述符的澤西servlet容器作爲Servlet 3.x容器中的過濾器運行

財產只有當新澤西servlet容器被配置爲一個使用javax運行應用時,作爲一個過濾器運行jersey.config.servlet.filter.forwardOn404jersey.config.servlet.filter.staticContentRegex只工作.servlet.Filter,否則這個屬性將被忽略。

我想擺脫web.xml完全

<?xml version="1.0" encoding="UTF-8"?> 
<web-app 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" 
    version="3.1"> 
    <display-name>My-Webservice</display-name> 

    <filter> 
     <filter-name>Jersey Filter</filter-name> 
     <filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class> 
     <init-param> 
      <param-name>javax.ws.rs.Application</param-name> 
      <param-value>com.foo.webservices.MyApplication</param-value> 
     </init-param> 
    </filter> 
</web-app> 

,並擁有一切在我的自定義Application

@ApplicationPath(value = "/") 
public class MyApplication extends ResourceConfig 
{  
    public MyApplication() 
    { 
     packages("com.foo.webservices.services"); 
     property(ServletProperties.FILTER_FORWARD_ON_404, true); 
    } 
} 

的官方文檔(https://jersey.java.net/documentation/latest/deployment.html#deployment.servlet.3)沒有說明什麼關於過濾器不幸。

回答

2

這是可能,但不會像設置一些配置屬性一樣簡單。如果你瞭解它的實際工作方式,這將有所幫助。通過Servlet 3.x,引入了一個ServletContainerInitializer,我們可以實現動態加載servlet(這將在here進一步討論)。澤西島有一個它使用的實現。但是它遵循JAX-RS,它說應用程序應該作爲一個servlet加載。所以澤西島並沒有提供任何解決方法。

我們可以寫我們自己的ServletContainerInitializer或者我們可以直接進入澤西島。澤西島有我們可以實施的SerletContainerProvider。我們需要自己註冊servlet過濾器。實施將是這個樣子

@Override 
public void preInit(ServletContext context, Set<Class<?>> classes) throws ServletException { 
    final Class<? extends Application> applicationCls = getApplicationClass(classes); 
    if (applicationCls != null) { 
     final ApplicationPath appPath = applicationCls.getAnnotation(ApplicationPath.class); 
     if (appPath == null) { 
      LOGGER.warning("Application class is not annotated with ApplicationPath"); 
      return; 
     } 
     final String mapping = createMappingPath(appPath); 
     addFilter(context, applicationCls, classes, mapping); 
     // to stop Jersey servlet initializer from trying to register another servlet 
     classes.remove(applicationCls); 
    } 
} 

private static void addFilter(ServletContext context, Class<? extends Application> cls, 
           Set<Class<?>> classes, String mapping) { 
    final ResourceConfig resourceConfig = ResourceConfig.forApplicationClass(cls, classes); 
    final ServletContainer filter = new ServletContainer(resourceConfig); 
    final FilterRegistration.Dynamic registration = context.addFilter(cls.getName(), filter); 
    registration.addMappingForUrlPatterns(null, true, mapping); 
    registration.setAsyncSupported(true); 
} 

一旦我們有我們的實現,我們需要創建一個文件

META-INF/services/org.glassfish.jersey.servlet.internal.spi.ServletContainerProvider 

應在類路徑的根。該文件的內容應該是我們實現的完全限定名稱。

您可以在此看到一個完整的示例GitHub Repo

+0

很好的答案,謝謝。我只需要在getApplicationClass方法中添加另一個檢查,因爲它錯誤地將'org.glassfish.jersey.server.ResourceConfig $ RuntimeConfig'識別爲應用程序類。我在'break'語句周圍添加了'if(applicationCls!= null && applicationCls.getAnnotation(ApplicationPath.class)!= null)'。 – lazlev