无描述符 Jersey Servlet 容器在 Servlet 3.x 容器中作为过滤器运行

laz*_*lev 2 java jersey

有没有办法像javax.servlet.Filter在 Servlet 3.x 容器中一样运行 Jersey servlet 容器 (2.x) 无描述符?我需要与我的服务一起提供静态资源,因此需要使用jersey.config.servlet.filter.forwardOn404orjersey.config.servlet.filter.staticContentRegex仅在根据 Javadoc 作为过滤器运行时才起作用

该属性仅当 Jersey servlet 容器配置为作为 javax.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>
Run Code Online (Sandbox Code Playgroud)

并在我的定制Application课程中拥有一切

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

不幸的是,官方文档(https://jersey.java.net/documentation/latest/deployment.html#deployment.servlet.3)没有说明有关过滤器的任何内容。

Pau*_*tha 5

这是可能的,但不会像设置一些配置属性那么简单。如果您了解一点它的实际工作原理,将会有所帮助。在 Servlet 3.x 中,引入了一个ServletContainerInitializer我们可以实现动态加载 servlet 的方法(这将在此处进一步讨论)。Jersey 有一个它使用的实现。但它遵循 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);
}
Run Code Online (Sandbox Code Playgroud)

一旦我们实现了,我们需要创建一个文件

META-INF/services/org.glassfish.jersey.servlet.internal.spi.ServletContainerProvider
Run Code Online (Sandbox Code Playgroud)

它应该位于类路径的根部。该文件的内容应该是我们实现的完全限定名称。

您可以在此GitHub Repo中查看完整的示例