Spring Boot不能提供静态内容服务。

216

我无法让我的Spring-boot项目提供静态内容。

我已经在src/main/resources下放置了一个名为static的文件夹。 在它里面,我有一个名为images的文件夹。 当我打包应用并运行它时,它无法找到我放在那个文件夹中的图像。

我尝试将静态文件放置在publicresourcesMETA-INF / resources中,但没有任何作用。

如果我运行命令jar -tvf app.jar,我可以看到文件位于正确的文件夹中:/static/images/head.png,但是调用:http://localhost:8080/images/head.png,我得到一个 404错误。

为什么Spring-boot找不到这个东西呢?(顺便说一句,我正在使用1.1.4版本)


9
默认的资源处理映射到/。我建议检查它是否已启用。如果是的话,在您启动应用程序时,您会在输出中看到一行以“Mapped URL path [/] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]”结尾。另外一个可能性是您自己的控制器也被映射到/**并且优先于资源处理程序。发布应用程序启动的输出将使我们更容易地了解情况。 - Andy Wilkinson
18
我猜你的应用程序中有@EnableWebMvc(或其等效物)。 这将关闭默认的Boot MVC配置。 - Dave Syer
4
没有,我在任何地方都没有使用@EnableWebMvc。我不明白这是怎么回事。现在连模板也出问题了,我的所有模板(使用freemarker)都无法被spring boot的类加载器找到。 - Vinicius Carvalho
3
我遇到了类似的问题,但是尝试了推荐的解决方法都没有成功。如果有人能够帮忙看看并指出我做错了什么,我将不胜感激!!!链接为https://github.com/kylebober/kbss - Kyle S. Bober
4
我发现如果我有一个文件 src/main/resources/public/style.css,那么它的网址是 /style.css 而不是我预期的 /public/style.css。 - Dave
显示剩余9条评论
26个回答

210

超过一年后不再讨论死亡,但所有之前的回答都错过了一些关键点:

  1. 在您的类上使用@EnableWebMvc将禁用org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration。如果您想完全控制它,则没问题,否则它是一个问题。

  2. 无需编写任何代码即可添加静态资源的其他位置,除了已经提供的位置。观看v1.3.0.RELEASE的org.springframework.boot.autoconfigure.web.ResourceProperties,我看到可以在application.properties中配置staticLocations字段。这里是源代码的片段:

/**
 * Locations of static resources. Defaults to classpath:[/META-INF/resources/,
 * /resources/, /static/, /public/] plus context:/ (the root of the servlet context).
 */
private String[] staticLocations = RESOURCE_LOCATIONS;
  • 如前所述,请求URL将相对于这些位置进行解析。因此,当请求URL为/index.html时,将提供src/main/resources/static/index.html。负责解析路径的类是Spring 4.1的org.springframework.web.servlet.resource.PathResourceResolver

  • 后缀模式匹配默认启用,这意味着对于请求URL/index.html,Spring将查找与/index.html对应的处理程序。如果意图是提供静态内容,则这是一个问题。要禁用它,请扩展WebMvcConfigurerAdapter(但不要使用@EnableWebMvc),并按以下示例覆盖configurePathMatch

  • @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        super.configurePathMatch(configurer);
    
        configurer.setUseSuffixPatternMatch(false);
    }
    

    我认为,减少代码中错误的唯一方法是尽可能少地编写代码。即使需要进行一些研究,也要使用已经提供的内容,因为回报是值得的。

    2021年7月编辑:

    1. WebMvcConfigurerAdapter自Spring 5以来已被弃用。实现WebMvcConfigurer并注释上@Configuration

    4
    这个答案确实经过了很多研究。非常推荐阅读。 - Ekansh Rastogi
    4
    如果我是关键人物,我会将这个答案放入Spring Boot文档中。 - aliopi
    2
    @Abhijit Sarkar 我的意思是公司_Pivotal_,对于任何不好的感觉我很抱歉,但这并不是我的本意。如果我没记错的话,Pivotal 是 Spring 的所有者。我可以记录下来,但他们有专门的人员负责此事,所以他们应该会做的 :P - aliopi
    3
    减少代码中错误的唯一方法是不写代码[...] 我非常喜欢这句话。 - Clijsters
    1
    嗯...我尝试过应用这个,但是它仍然不起作用。 (https://stackoverflow.com/questions/48934844/index-html-is-not-showing-up-after-refactoring-the-project) - Stefan Falk
    显示剩余9条评论

    103

    与spring-boot所述的不同,要让我的spring-boot jar提供内容:

    我必须通过这个配置类明确地注册我的src/main/resources/static内容:

    @Configuration
    public class StaticResourceConfiguration implements WebMvcConfigurer {
    
        private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
                "classpath:/META-INF/resources/", "classpath:/resources/",
                "classpath:/static/", "classpath:/public/" };
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/**")
                .addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);
        }
    }
    

    4
    我遇到了同样的问题,使用了相同版本的Spring Boot,但这对我也没用。 - greyfox
    在1.2.5版本中解决了我的问题!非常感谢...点个赞吧!! - mrclrchtr
    这个黑科技能用... 奇怪的是自动配置失败了。 - Allan Vital
    遗憾的是,这个 hack 对我不起作用,这很遗憾,因为它很优雅。 我不确定根本原因是否是资源路径。也许,由于我在 Windows 上运行它,它们需要以不同的格式进行格式化? - acarlstein
    请注意,WebMvcConfigurer现在已被弃用。 - FishingIsLife
    org.springframework.web.servlet.config.annotation.WebMvcConfigurer没有被弃用(Spring-webmvc-5.3.3.jar)。这个解决方案仍然有效,只是我用它来添加了一个额外的处理程序/路径组合"/reports/**","file:/mnt/somedir/reports/"。必须在Linux上保留斜杠。 - robododge

    52

    我曾经遇到过类似的问题,后来发现简单的解决方案是让我的配置类扩展WebMvcAutoConfiguration

    我也有类似的问题,后来发现简单的解决方法是让我的配置类继承WebMvcAutoConfiguration

    @Configuration
    @EnableWebMvc
    @ComponentScan
    public class ServerConfiguration extends WebMvcAutoConfiguration{
    }
    

    我不需要任何其他代码来提供静态内容服务,但我确实在src/main/webapp下放置了一个名为public的目录,并配置了Maven指向src/main/webapp作为资源目录。这意味着public将被复制到target/classes中,因此在运行时,spring-boot/tomcat可以找到该目录。


    使用这种方式静态资源在其他配置文件中无法正常工作。例如,我有一个为发布而创建的配置文件,它使用另一个IP地址。我会收到所有资源的404错误。 - Mahdi

    29

    寻找映射到"/"或没有映射路径的控制器。

    我曾遇到过类似的问题,出现405错误,苦思冥想了好几天。最终问题原因是我忘记在一个用@RestController注解的控制器上加上@RequestMapping注解。我猜测这个控制器映射的路径默认为"/",阻塞了静态内容资源映射。


    2
    解决了我的问题!我有一个带有@ RestController(“/ blubb”)注释的控制器,显然是错误的,但有时你看不到树木。将其更改为@RestController @RequestMapping(“/ blubb”)即可解决问题。 - krinklesaurus
    我很高兴它有所帮助,并对“无法看到树林中的所有树木”这个表达在德语和瑞典语中也存在这一概念感到有趣 :) - Johannes
    2
    如果希望同时提供静态内容并为根请求提供动态处理程序,也可以显式添加 @RequestMapping("/")。 - mjj1409
    我有一个映射到“/”的控制器方法。但解决我的问题的是在主类中添加自动配置。EnableAutoConfiguration SpringBootApplication - Shafiul
    1
    哇....在这个问题上浪费了2天时间。我的Spring Boot MVC应用程序使用Spring Security,但未看到styles.css文件。我认为安全性未允许.jsp文件访问styles.css文件。我在控制器中有一个@RequestMapping({"","/", "/home"})。去掉""和"/"后,我的MVC开始完美地工作了...非常奇怪。 - skmansfield
    4
    添加@EnableAutoConfiguration和@SpringBootApplication是多余的!@SpringBootApplication已经包含了@EnableAutoConfiguration。 - Dehan

    22

    可以按照以下方式进行配置:

    @Configuration
    @EnableWebMvc
    public class WebMvcConfig extends WebMvcAutoConfigurationAdapter {
    
    // specific project configuration
    
    }
    

    重要的是,您的WebMvcConfig 可以 覆盖addResourceHandlers方法,因此您需要显式调用super.addResourceHandlers(registry)(如果您满意默认资源位置,则无需覆盖任何方法)。

    还有一件需要在这里评论的事情是,只有在没有已映射到/**的资源处理程序时,才会注册这些默认资源位置(/static/public/resources/META-INF/resources)。

    从此刻开始,如果您在src/main/resources/static/images中有一个名为image.jpg的图像,例如,您可以使用以下URL访问它:http://localhost:8080/images/image.jpg(服务器在端口8080上启动,并将应用程序部署到根目录)。


    1
    或许需要说明的是,虽然你可以重写addResourceHandlers方法,但实际上并不需要这样做来解决OP的问题。 - Software Engineer
    @EngineerDollery 感谢您的评论,这正是我的意图,但我还特别添加了解释。 - Francisco Spaeth
    我将我的CSS/JS移动到src/main/resources/static文件夹中,错误不再存在,但我仍然无法在页面中显示CSS。 - Hatem Jaber
    1
    兄弟,我深入互联网的深处找到了这个可行的解决方案。看起来关键是@EnableWebMvcWebMvcAutoConfigurationAdapter的组合。非常感谢! - Ian Newland
    对我来说,它也没有直接奏效。我不得不添加这个。我在这里加上我的评论,因为我有两个问题。我还有一个控制器将“/”映射为@Johannes提到的。这样做并删除我的“/”控制器解决了我的问题。 - loyalBrown

    13

    我遇到了完全相同的问题,后来意识到我在我的application.properties文件中定义了:

    spring.resources.static-locations=file:/var/www/static
    

    这一属性覆盖了我尝试过的所有其他属性。在我的情况下,我想同时保留两者,因此我只保留了这个属性并添加了:

    spring.resources.static-locations=file:/var/www/static,classpath:static
    

    它将src/main/resources/static下的文件作为localhost:{port}/file.html提供文件服务。

    以上所有方法对我都没有用,因为没有人提到这个小属性,它本来可以很容易地从网上复制过来以实现不同的目的;)

    希望能对你有所帮助!我觉得它适合在这篇回答长贴中为那些有这个问题的人提供帮助。


    1
    我正在使用Spring Boot 2.0.5.RELEASE,并将 spring.resources.static-locations=file:/var/www/static,classpath:static 放入我的 application.properties 文件中,但它对我没有起作用。我在我的配置类上使用了 @EnableWebMvc - N. Ngo
    1
    这是解决我的问题的那个。还有 security.ignoredsecurity.publicPaths - JoSSte

    11

    3
    是的,我试过了,那些都是我按照文档指示尝试的地方。但是什么都不起作用。我不明白为什么根本找不到资源。我试图查看示例,奇怪的是没有一个示例使用文档提出的结构。你刚刚粘贴的那个使用了一个模板文件夹,我假设那是为了thymeleaf配置或velocity。 - Vinicius Carvalho
    Web UI示例(https://github.com/spring-projects/spring-boot/tree/v1.1.3.RELEASE/spring-boot-samples/spring-boot-sample-web-ui)提供静态内容服务。 - Andy Wilkinson
    2
    我同意@ViniciusCarvalho的观点,我已经尝试了所有可能的组合来使css/js放置在正确的位置,但似乎无法做到。即使我访问localhost:8089/css/styles.css,我也看不到任何东西。我只有一个规则来改变body颜色。 - Hatem Jaber

    7

    我认为之前的回答已经很好地解决了这个问题。然而,我想补充一点,在你的应用中启用Spring Security时,有一种情况可能需要明确告诉Spring允许请求其他静态资源目录,例如"/static/fonts"

    在我的情况下,"/static/css""/static/js""/static/images"是默认允许的,但/static/fonts/**被我的Spring Security实现阻止了。

    下面是我如何解决这个问题的示例。

    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    .....
        @Override
        protected void configure(final HttpSecurity http) throws Exception {
            http.authorizeRequests().antMatchers("/", "/fonts/**").permitAll().
            //other security configuration rules
        }
    .....
    }
    

    6

    仅仅是为了给一个老问题添加另一个答案... 人们已经提到@EnableWebMvc将会阻止WebMvcAutoConfiguration的加载,这段代码负责创建静态资源处理程序。还有其他条件也会阻止WebMvcAutoConfiguration的加载。最清晰的方法是查看源代码:

    https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java#L139-L141

    在我的情况下,我正在包含一个扩展自WebMvcConfigurationSupport的类的库,这是一个条件,会阻止自动配置:
    @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
    

    重要提示:绝不能从WebMvcConfigurationSupport扩展。而应该从WebMvcConfigurerAdapter进行扩展。
    更新:在5.x中正确的方法是实现WebMvcConfigurer。

    WebMvcConfigurerAdapter 在 Spring Boot 5.0 中已被弃用。在 Javadocs 中可以找到以下信息:“从5.0开始,WebMvcConfigurer具有默认方法(由Java 8基线实现),可以直接实现,无需使用此适配器。” 因此,现在应该实现 WebMvcConfigurer。 - Marvo
    @Marvo,你说得非常正确。在5.x中实现WebMvcConfigurer是正确的方法。 - Bal

    6
    这是我的解决方案:
    首先,在webapp/WEB-INF下创建一个resources文件夹,文件夹结构如下:
    -- src
      -- main
        -- webapp
          -- WEB-INF
            -- resources
              -- css
              -- image
              -- js
              -- ...
    

    第二步,在Spring配置文件中。
    @Configuration
    @EnableWebMvc
    public class MvcConfig extends WebMvcConfigurerAdapter{
    
        @Bean
        public ViewResolver getViewResolver() {
            InternalResourceViewResolver resolver = new InternalResourceViewResolver();
            resolver.setPrefix("/WEB-INF/views/");
            resolver.setSuffix(".html");
            return resolver;
        }
    
        @Override
        public void configureDefaultServletHandling(
                DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/resource/**").addResourceLocations("WEB-INF/resources/");
        }
    }
    

    接下来,您可以访问您的资源内容,例如http://localhost:8080/resource/image/yourimage.jpg


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