带有静态内容的 Spring Boot 项目在运行 jar 时生成 404

Posted

技术标签:

【中文标题】带有静态内容的 Spring Boot 项目在运行 jar 时生成 404【英文标题】:Spring Boot project with static content generates 404 when running jar 【发布时间】:2014-02-16 23:11:03 【问题描述】:

Spring 最近发布的关于在 Spring Boot 项目中使用静态 Web 内容的博文 (https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot) 表明可能会使用多个资源目录:

/META-INF/resources/ /资源/ /静态/ /公共/

这要归功于 WebMvcAutoConfiguration 类,它自动将这些目录添加到类路径中。这一切似乎都很好,并且在使用 spring-boot-maven-plugin spring-boot:run 目标时似乎可以工作,所有你的静态内容正在运行(例如:/index.html)。

当您打包 Spring Boot 项目并允许 spring-boot-maven-plugin 创建增强的 JAR 然后尝试使用 java -jar my-spring-boot-project.jar 运行您的项目时,您会发现您的静态内容现在返回404 错误。

【问题讨论】:

【参考方案1】:

我不得不向 pom.xml 添加 thymeleaf 依赖项。 没有这个依赖,Spring boot 找不到静态资源。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

【讨论】:

谢谢。我试图托管来自 Javadoc 和 JaCoCo 的静态内容。我让它在本地工作,但是一旦我部署,链接就会给出 404 响应。我不知道为什么,但添加此依赖项使其工作。【参考方案2】:

当我尝试从我现有的工作解决方案中创建一个沙箱示例作为模板 (https://github.com/fluentcodes/sandbox/tree/java-spring-boot) 时,我偶然发现了这个 404 主题:没有提供静态内容 index.html。

由于示例相当简单且现有解决方案有效,因此我不会深入探讨提到的深挖弹簧解决方案。

我查看了创建的目标类,没有预期的 static/index.html。

原因很简单:我创建的resources不是在src/main/下,而是在src/下。需要一些时间来寻找,因为提到了很多复杂的解决方案。对我来说,它有一个相当微不足道的原因。

另一方面,在启动 Spring Boot 时:为什么我没有得到任何提示,即找不到来自 location1、location2 .... locationx 的静态内容。认为它是一个主题。

【讨论】:

【参考方案3】:

我在静态目录中有一个资产文件夹,并允许在 SpringConfig 中扩展 WebSecurityConfigurerAdapter

http.authorizeRequests().antMatchers("/", "/login", "/assets/**")
            .permitAll()

【讨论】:

【参考方案4】:

Spring Boot 将使用WebMvcAutoConfiguration 配置静态内容,该类仅在您没有自定义WebMvcConfigurationSupport bean 时生效,而在我的情况下,我有一个。

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass( Servlet.class, DispatcherServlet.class,
        WebMvcConfigurerAdapter.class )
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter( DispatcherServletAutoConfiguration.class,
        ValidationAutoConfiguration.class )
    public class WebMvcAutoConfiguration 


所以我只需要自己配置它,这是我的解决方案:

@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) 
    registry.addResourceHandler("/static-file/**").addResourceLocations("classpath:/static/");

【讨论】:

【参考方案5】:

事实证明,虽然 Spring Boot 很聪明地将各种资源目录添加到类路径中,但 Maven 却不是,这取决于你来处理这部分。默认情况下,只有src/main/resources 将包含在您的 JAR 中。如果您在项目的根目录中创建一个名为 /static 的文件夹(正如博客文章所暗示的那样),那么在使用 spring-boot:run 时它会正常工作Maven 目标,但不是在您创建 JAR 后。

最简单的解决方案是在/src/main/resources 中创建/static 文件夹,然后Maven 会将其包含在JAR 中。或者,您可以向 Maven 项目添加其他资源位置:

<resources>
    <resource>
        <directory>src/main/resources</directory>
    </resource>
    <resource>
        <directory>static</directory>
        <targetPath>static</targetPath>
    </resource>
</resources>

我希望这对某人有用,当您退后一步看看 Maven 的工作原理时,这很明显,但它可能会难倒一些使用 Spring Boot 的人,因为它的设计几乎不需要配置。

【讨论】:

仅作记录:我认为您误读了该博客,因为它根本没有提到 Maven,并且没有使用 jar 存档。如果你完全按照 Roy 在博客中所做的那样做,那就可以了。 你有一个示例项目吗,所以我可以看到...我仍然无法让它工作 您能否编辑答案以删除目录路径前的“/”?它应该是 src/main/resourcesstatic 这对我不起作用,在 pom.xml 中添加资源是不够的。相反,我必须使用&lt;addResources&gt;true&lt;/addResources&gt; 配置 Spring Boot 插件。看到这个答案***.com/questions/24762657/…【参考方案6】:

有两件事需要考虑(Spring Boot v1.5.2.RELEASE)-

1) 检查所有 Controller 类的 @EnableWebMvc 注解,删除 如果有的话

2) 检查使用注解的控制器类 - @RestController 或@Controller。

不要在一个类中混合使用 Rest API 和 MVC 行为。对于 MVC,使用 @Controller,对于 REST API,使用 @RestController

Doing above 2 things resolved my issue. Now my spring boot is loading static resources with out any issues.
@Controller => load index.html => loads static files.

@Controller
public class WelcomeController 

    // inject via application.properties
    @Value("$welcome.message:Hello")
    private String message = "Hello World";

    @RequestMapping("/welcome")
    public String welcome(Map<String, Object> model) 
        model.put("message", this.message);
        return "welcome";
    

    @RequestMapping("/")
    public String home(Map<String, Object> model) 
        model.put("message", this.message);
        return "index";
    



<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Hello</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />


    <link rel="stylesheet/less" th:href="@/webapp/assets/theme.siberia.less"/>

    <!-- The app's logic -->
    <script type="text/javascript" data-main="/webapp/app" th:src="@/webapp/libs/require.js"></script>
    <script type="text/javascript">
        require.config(
            paths:  text:"/webapp/libs/text" 
        );
    </script>

     <!-- Development only -->
     <script type="text/javascript" th:src="@/webapp/libs/less.min.js"></script>


</head>
<body>

</body>
</html>

【讨论】:

我认为您的问题可能是由于使用了@RestController - 此注释与@Controlller 相同,但也会在每个方法中添加@ResponseBody,这意味着您从控制器方法返回的任何内容都结束了在响应正文中,可能由转换器转换。在您的情况下,这可能意味着您在浏览器中看到“welcome”或“index”作为字符串返回,而不是加载“welcome.html”或“index.html”视图。 太棒了!!!!我无法让我的 index.html 工作。我删除了一个@EnableWebMvc,它起作用了!!!非常感谢!【参考方案7】:

我翻了几页来了解如何在 Spring 引导环境中提供静态内容。大多数建议都是围绕将静态文件放在 /static /resources/ src/main/webapp 等中。考虑以下方法共享。

    允许 spring boot 自动配置 Dispatcher Servlet - 确保 DispatcherServletAutoConfiguration 不在 AutoConfiguration 的排除范围内。

    @EnableAutoConfiguration(排除 = //DispatcherServletAutoConfiguration.class, )

    为静态内容路由注入您的外部目录

    @Value("$static-content.locations:file:C:/myprj/static/") 私有字符串[] 静态内容位置;

3.Override WebMvcAutoConfiguration 使用 WebMvcConfigurerAdapter 建议 spring 不要使用默认资源位置,而是使用我们指示它的内容。如下所示

@Bean
    public WebMvcConfigurerAdapter webMvcConfigurerAdapter()
    
        return new WebMvcConfigurerAdapter()
        
            @Override
            public void addResourceHandlers(ResourceHandlerRegistry registry)
            
                if (!registry.hasMappingForPattern("/**"))
                
                    // if this is executed spring won't add default resource
                    // locations - add them to the staticContentLocations if
                    // you want to keep them
                    // default locations:
                    // WebMvcAutoConfiguration.RESOURCE_LOCATIONS
                    registry.addResourceHandler("/**").addResourceLocations(
                            staticContentLocations);
                
            
        ;
    

如果 C:/myprj/static 有 index.html ,那么 http://localhost:portno/index.html 应该可以工作。希望对您有所帮助。

【讨论】:

有一种更简单的方法可以做到这一点,您可以简单地将您的位置指定为application.properties / application.yml 文件中spring.resources.static-locations 属性的值,甚至可以将其作为命令行传递论据。【参考方案8】:

我正用头撞墙,试图弄清楚如何用 gradle 做到这一点。有什么建议吗?

编辑:我通过将它添加到我的 build.gradle 来让它工作:

// Copy resources into the jar as static content, where Spring expects it.
jar.into('static') 
    from('src/main/webapp')

【讨论】:

Gradle 默认也使用“src/main/resources”。使用它有什么问题? 确实如此,直接将其放入资源中会将您的文件复制到jar中。但是,为了让 Spring 识别并将您的文件作为静态内容提供服务,您需要将其打包到 jar 中名为“static”、“public”、“resources”或“/META-INF/resources/”的目录下文件。如果您只是将文件放在资源目录中,它们都会被复制到 jar 的根目录中,当您尝试访问它们时,Spring 会提供 404 服务。 对,所以最简单(最少配置,最多功能)的解决方案就是把你的静态资源放在“src/main/resourecs/static”中。这就是我的意思。 如果你让 npm/frontend 构建任务依赖于 jar 但是它已经将 /resources/static 收集到 /build/lib blabla 中,所以你需要让它依赖于 compileJava ,以便您的静态内容已经构建(对于未来的访问者,只是遇到了同样的问题)

以上是关于带有静态内容的 Spring Boot 项目在运行 jar 时生成 404的主要内容,如果未能解决你的问题,请参考以下文章

ApplicationInsights 破坏了静态内容的默认 Spring Boot 配置

在 spring-boot 项目中将 CSS 等静态文件放在哪里?

Eclipse软件运行spring boot项目修改静态文件(htmlcssjs)需要重启项目才生效---解决方法(亲测可用)

Eclipse软件运行spring boot项目修改静态文件(htmlcssjs)需要重启项目才生效---解决方法(亲测可用)

Spring-Boot Jersey:允许 Jersey 提供静态内容

spring boot项目进行war部署,对于静态资源无法访问的问题