无法使用Spring Boot和Jersey 2提供静态内容服务

3
有没有办法让Spring Boot与Jersey一起提供静态内容?我已经查看了一系列关于将Swagger集成到Spring Boot应用程序中的教程和代码示例。我可以使其传递基本的swagger.json,但我无法使Swagger UI工作。
我甚至不能传递一个简单的hello.txt静态文件。
我的pom.xml的相关部分为:
<!--Spring Boot-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!-- Jersey -->
<dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-client</artifactId>
    <version>${jersey.version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.ext</groupId>
    <artifactId>jersey-spring3</artifactId>
    <version>${jersey.version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.ext</groupId>
    <artifactId>jersey-bean-validation</artifactId>
    <version>${jersey.version}</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>${jersey.version}</version>
</dependency>

<!-- Swagger -->
<dependency>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-jersey2-jaxrs</artifactId>
    <version>1.5.7</version>
</dependency>

我的代码:

@Configuration
@EnableAutoConfiguration
@ComponentScan({"com.xxxx"})
public class AdminApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(AdminApplication.class)
                .run(args);
    }

    @Bean
    public ServletRegistrationBean jerseyServlet() {
        ServletRegistrationBean registration = new ServletRegistrationBean(new ServletContainer(), "/*");
        registration.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS, JerseyConfig.class.getName());
        return registration;
    }
}




package com.xxxxxx.admin.config;
import com.xxxxxx.admin.resource.Status;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.server.spring.scope.RequestContextFilter;    
import io.swagger.jaxrs.config.BeanConfig;

public class JerseyConfig extends ResourceConfig {

    public JerseyConfig() {
        register(RequestContextFilter.class);
        packages("com"); // TODO needs more detailed level
        register(LoggingFilter.class);
        // Validation
        this.property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
        this.property(ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, true);
        configureSwagger();
    }

    private void configureSwagger() {
        register(io.swagger.jaxrs.listing.ApiListingResource.class);
        register(io.swagger.jaxrs.listing.SwaggerSerializers.class);
        BeanConfig beanConfig = new BeanConfig();
        beanConfig.setVersion("1.0.0");
        beanConfig.setSchemes(new String[]{"http"});
        beanConfig.setHost("localhost:8080");
        beanConfig.setBasePath("/"); // tried other things like "/api", but doesn't change anything
        beanConfig.setResourcePackage("com.xxxxxx.admin");
        beanConfig.setPrettyPrint(true);
        beanConfig.setScan(true);
    }

}



//other imports
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

@Service
@Path("/status")
@Api(value = "status", description = "Check status")
public class Status {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @ApiOperation("Return status")
    public Response status() {
        return Response.ok("Up").build();
    }
}

我还尝试将Jersey作为过滤器运行(使用spring.jersey.type=filter),并按this answer中所述更改Jersey的servlet模式,但似乎没有影响任何内容。
@ApplicationPath("/rootPath")
public class JerseyConfig extends ResourceConfig {

我有一个hello.txt文件在/src/main/resources/public下,Swagger UI的静态文件在/src/main/resources/public/swagger下。
正如我所说,我的应用程序运行良好,GET http://localhost:8080/swagger.json 显示了纯json文档,但http://localhost:8080/hello.txthttp://localhost:8080/swagger/index.html 都返回404。
我正在使用Jersey 2.8和Spring Boot 1.3.0。
2个回答

2

I also tried changing Jersey's servlet pattern

@ApplicationPath("/rootPath")
public class JerseyConfig extends ResourceConfig {
您配置应用程序的方式,@ApplicationPath并不重要。 您链接到的这个答案之所以有效,是因为Spring Boot自动配置在从资源配置中提取@ApplicationPath值时设置了servlet映射。
您目前没有使用Spring Boot提供的ServletRegistrationBean来实现此目的。如果您使用自己的ServletRegistrationBean的目的是注册ResourceConfig,则可以通过以下任一方式轻松实现相同目的:
  1. Annotating your ResourceConfig with @Component to make it a Spring bean, or
  2. Make it a Spring bean in your configuration class

    @Bean
    public ResourceConfig config() {
        return new JerseyConfig();
    }
    
Spring Boot会将您的ResourceConfig注入到JerseyAutoConfiguration中,在那里它将获取ResourceConfig上的@ApplicationPath值(如果存在),并使用它来注册自己的ServletRegistrationBean。您可以查看JerseyAutoConfiguration,以了解在让Spring Boot处理配置时可以免费获得的所有内容。
如果您想保留当前的SpringRegistrationBean,只需更改您正在使用的路径即可。您正在使用/*,这在链接的答案中被提到是问题所在。因此,如果您需要,只需更改为/rooPath/*即可。

1
这是一个很好的答案,谢谢!但有一些奇怪的地方。我设置了 spring.jersey.type=filterspring.jersey.application-path=rootPath,一切都很好:静态内容被服务并且应用程序端点被移动到 rootPath/ 并正确响应。但是,如果我只设置 spring.jersey.type=filter 而没有设置 spring.jersey.application-path,那么静态内容将无法访问。根据您链接的答案中的选项1,将jersey设置为运行过滤器就足够了。我错过了什么? - user384729
好的,这意味着我不可能将静态内容和jersey资源放在同一路径下,对吗? - user384729
不,你可以这样做,但是你需要告诉Jersey(过滤器)在找不到你的静态内容时转发请求。这就是上面的属性所做的。但是对于一个servlet来说,不行。它必须是一个过滤器。 - Paul Samsotha
如果您想要组建一个极简的 (github) 项目,以便我可以测试并进行检查。但是我无法在我的端上复现这个问题。 - Paul Samsotha
找到了:我需要在我的ExceptionMapper<NotFoundException>.toResponse中删除return Response.status(Response.Status.NOT_FOUND).entity(exception.getMessage()).build()entity()部分。再次感谢。 - user384729
显示剩余4条评论

2

使用Spring MVC时,遇到的问题与常见问题相同。根据servlet规范,每个servlet容器都需要实现一个默认服务器,该服务器具有最低优先级,能够提供位于WEB-INF文件夹外部的静态内容。

不幸的是,您将Jersey servlet映射到"/*",这意味着每个URL都将提交给Jersey,而Jersey不知道如何处理静态URL。

那么可以(轻松)做什么呢?

  • map the Jersey servlet to a subpath (say /api) and move all you controllers there:

    ServletRegistrationBean registration =
        new ServletRegistrationBean(new ServletContainer(), "/api/*");
    ...
    beanConfig.setBasePath("/api/");
    

    and ask GET http://localhost:8080/api/swagger.json

  • only map the servlet to *.json URLs:

    ServletRegistrationBean registration =
        new ServletRegistrationBean(new ServletContainer(), "*.json");
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接