Spring Boot不提供静态内容


180

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

我已经放在一个命名的文件夹staticsrc/main/resources。在其中,我有一个名为的文件夹images。当我打包应用程序并运行它时,它找不到我放在该文件夹中的图像。

我试图把静态文件中publicresourcesMETA-INF/resources但没有任何工程。

如果我jar -tvf app.jar我可以看到文件在正确文件夹的jar中: /static/images/head.png例如,但是调用:http://localhost:8080/images/head.png,我得到的只是一个404

有什么想法为什么spring-boot没有找到这个?(我正在使用1.1.4 BTW)


6
默认资源处理映射到/ **。我会仔细检查它是否已启用。如果是这样,在启动应用程序时,在输出中将看到一行以“将URL路径[/ **]映射到类型为[class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]类型的处理程序”结尾的行。另一种可能性是您自己的控制器,该控制器也已映射到/ **,并且优先于资源处理程序。发布应用程序启动的输出将使我们更容易看到正在发生的事情。
安迪·威尔金森

13
我猜您@EnableWebMvc的应用程式中有(或同等功能)。这将关闭默认的启动MVC配置。
戴夫·塞尔

1
不,我在任何地方都没有@EnableWebMvc。我不明白 现在它也在模板中发生。Spring Boot的类加载器可以找到我的任何模板(freemarker)。
Vinicius Carvalho 2014年

2
我遇到了类似的问题,并且没有提供任何建议的解决方案。如果有人这么友好地看看并指出我到底在做什么错,那将不胜感激!github.com/kylebober/kbss
Kyle S. Bober

3
我发现,如果我有一个文件src / main / resources / public / style.css,则该URL为/style.css,而不是我期望的/public/style.css。
戴夫

Answers:


183

超过一年后不复活,但先前的所有答案都遗漏了一些关键点:

  1. @EnableWebMvc在您的课程上将被禁用org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration。如果您想要完全控制,那很好,但是否则,这是一个问题。
  2. 除了已经提供的内容外,无需编写任何代码即可为静态资源添加其他位置。看着org.springframework.boot.autoconfigure.web.ResourceProperties从v1.3.0.RELEASE,我看到一个字段staticLocations,可以在配置application.properties。这是源代码片段:

    /**
     * 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;
    
  3. 如前所述,请求URL将对于这些位置进行解析。因此,src/main/resources/static/index.html当请求网址为时将投放/index.html。从Spring 4.1开始,负责解析路径的类为org.springframework.web.servlet.resource.PathResourceResolver

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

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

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


3
这个答案的确是经过大量研究的。
值得

3
如果我是关键人物,我会回答这个问题并将其放在Spring Boot文档中
aliopi

2
@Abhijit Sarkar我的意思是Pivotal公司,对任何不好的想法感到抱歉,但这不是故意的。如果我正确的话,Pivotal是Spring的所有者。我可以记录下来,但是他们有为此薪水的人,所以他们应该这样做:P
aliopi

1
@aliopi Spring是一个开源项目。
Abhijit Sarkar

3
在您的代码中减少错误的唯一方法就是不要像这样编写代码
Clijsters

81

与spring-boot声明的状态不同,要让spring-boot jar服务于内容:我必须通过此config类专门注册我的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);
    }
}

3
我有相同的问题,相同版本的Spring Boot,但这对我也
不起作用

修复了我在1.2.5版本中的问题!非常感谢你..投票给这个!!
mrclrchtr

此hack有效...很奇怪,自动配置失败
Allan Vital

遗憾的是,这种技巧对我不起作用,由于优雅,这实在令人遗憾。我不确定根本原因是否是资源的路径。也许,由于我是在Windows中运行的,因此它们需要采用不同的格式吗?
acarlstein

50

我有一个类似的问题,事实证明,简单的解决方案是使我的配置类扩展WebMvcAutoConfiguration

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

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


通过这种方式,静态资源无法在其他配置文件中工作。例如,我有一个使用另一个IP地址发布的配置文件。我所有的资源都收到404错误。
马赫迪

26

查找映射到“ /”或没有映射路径的控制器。

我遇到这样的问题,出现405个错误,并用力地摔了几天。原来问题出在@RestController我已忘记使用注释进行@RequestMapping注释的注释控制器。我想这个映射路径默认为“ /”,并阻止了静态内容资源映射。


1
为我解决了!我有一个用@RestController(“ / blubb”)注释的控制器,这显然是错误的,但是有时您看不到树木的木头。将其更改为@RestController @RequestMapping(“ / blubb”)即可解决
krinklesaurus

我很高兴它为您带来帮助,并为“瑞典的瑞典语和瑞典语中都存在“看不见所有树木的树林”这一表达而感到高兴:)
Johannes

2
如果目的是同时提供静态内容并为根请求提供动态处理程序,则还可以显式添加@RequestMapping(“ /”)。
mjj1409 '16

1
哇...。花了2天浪费了这一天。我的spring boot mvc应用程序使用spring安全性,但是没有看到styles.css文件。我认为安全性不允许.jsp来访问styles.css文件。我的控制器中有一个@RequestMapping({“”,“ /”,“ / home”})。拿出“”和“ /”后,我的MVC开始完美运行...非常奇怪。
skmansfield,2013年

3
@Shafiul否同时添加EnableAutoConfiguration和SpringBootApplication是多余的!“ @SpringBootApplication”包含“ @EnableAutoConfiguration”
Dehan de Croos

20

可以进行如下配置:

@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上启动,并且应用程序已部署到根上下文中)。


评论一下也许很重要,尽管您可以/ can /覆盖addResourceHandlers,但实际上并不需要为了解决OP的问题。
软件工程师

@EngineerDollery感谢您的评论,这是我的意图,但我明确添加了解释
Francisco Spaeth 2014年

我将css / js移到src / main / resources / static文件夹中,错误不再存在,但仍然无法使css显示在页面中。
Hatem Jaber

杜德,我走遍了互联网的深处,找到了这个可行的解决方案。看来问题的关键是组合@EnableWebMvcWebMvcAutoConfigurationAdapter。谢谢您的宝贵时间!
伊恩·纽兰德

对于我来说,它也不是开箱即用的。我也必须添加它。我在这里添加评论,因为我有两个问题。我也有一个控制器,它映射了@Johannes提到的“ /”。这样做并删除我的“ /”控制器就解决了我的问题。
loyalBrown '17

11

您是否检查了Spring Boot参考文档

默认情况下,Spring Boot将从类路径中名为/static/public/resources/META-INF/resources)的文件夹或ServletContext的根目录中提供静态内容。

您还可以将项目与使用Spring MVC服务Web内容指南进行比较,或查看spring-boot-sample-web-ui项目的源代码。


2
是的,我确实做到了,就像文档指示的那样,这是我尝试过的地方。但是没有任何效果。我不明白为什么根本找不到资源。我试图研究样本,奇怪的是没有样本使用文档提出的结构。您刚刚粘贴的模板模板文件夹,我假设是百里香的配置或速度。
Vinicius Carvalho 2014年


我同意@ViniciusCarvalho的观点,我已经尝试了所有可能的组合来将css / js放在正确的位置,但似乎无法做到这一点。即使我访问localhost:8089 / css / styles.css,我也看不到任何东西。我只有一条规则可以更改车身颜色。
Hatem Jaber

10

我遇到了这个确切的问题,然后意识到自己已经在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提供。

以上都不对我有用,因为没有人提到这个可以轻易从网上复制以达到不同目的的小财产;)

希望能帮助到你!认为这对于有此问题的人来说很长的答案很合适。


我正在使用Spring Boot 2.0.5.RELEASE并将其spring.resources.static-locations=file:/var/www/static,classpath:static放入我的application.properties中,但是它对我不起作用。我@EnableWebMvc在配置类上使用。
N. Ngo,

这是解决我的问题的那个。随着security.ignoredsecurity.publicPaths
JoSSte

5

此解决方案适用于我:

首先,将资源文件夹放在webapp / WEB-INF下,如下所示

-- 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


谢谢,终于可以了!
NobodySomewhere

5

我认为前面的答案很好地解决了这个问题。但是,我要补充一点,在一种情况下,如果您在应用程序中启用了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
    }
.....
}

5

只是为旧问题添加了另一个答案...人们已经提到过@EnableWebMvcwill会阻止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


从Spring Boot 5.0开始不推荐使用WebMvcConfigurerAdapter。在Javadocs中对该类进行谷歌搜索:“从5.0开始,WebMvcConfigurer具有默认方法(由Java 8基准实现),可以直接实现而无需此适配器。” 因此,我认为现在可以实现WebMvcConfigurer。
Marvo

@Marvo完全正确。在5.x中执行此操作的正确方法是实施WebMvcConfigurer
Bal

3

有两件事需要考虑(Spring Boot v1.5.2.RELEASE)-1)检查所有Controller类的@EnableWebMvc注释,如果有的话将其删除2)检查使用注释的Controller类-@RestController或@Controller 。不要将Rest API和MVC行为混为一谈。对于MVC使用@Controller,对于REST API使用@RestController

做以上两件事解决了我的问题。现在,我的春季启动正在加载静态资源,而不会出现任何问题。@Controller =>加载index.html =>加载静态文件。

@Controller
public class WelcomeController {

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

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

}

index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>index</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>

删除@EnableWebMvc对我有用!谢谢
turboemu


2

如果问题是从IDE内启动应用程序(即从Eclipse或IntelliJ Idea开始)并使用Maven时出现的,则解决方案的关键在Spring-boot入门文档中:

如果您使用的是Maven,请执行:

mvn package && java -jar target/gs-spring-boot-0.1.0.jar

其中的重要部分是添加在package实际启动应用程序之前要运行的目标。(理念:Run菜单Edit Configrations...Add以及有选择Run Maven Goal,并指定package在该领域的目标)


1

我正在使用1.3.5并通过Jersey实施托管一堆REST服务。在我决定添加几个HTMLs + js文件之前,这种方法一直很好。这个论坛上给出的答案都没有帮助我。但是,当我在pom.xml中添加以下依赖项时,src / main / resources / static中的所有内容最终都通过浏览器显示:

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

似乎spring-web / spring-webmvc是使Spring Boot自动配置打开的重要传递依赖项。


1

仅供参考:我还注意到,如果我像这样添加一个坏的休息控制器,我可以弄乱一个可以正常工作的spring boot应用程序,并阻止它从静态文件夹中提供内容。

 @RestController
public class BadController {
    @RequestMapping(method= RequestMethod.POST)
    public String someMethod(@RequestParam(value="date", required=false)String dateString, Model model){
        return "foo";
    }
}

在此示例中,将错误的控制器添加到项目后,当浏览器要求静态文件夹中的文件可用时,错误响应为“ 405 Method Not Allowed ”。

注意,在错误的控制器示例中未映射路径。


1

我在Spring Boot 2.1.3中遇到了同样的问题,说找不到资源404。我从applicatiion.properties中删除了以下内容。

#spring.resources.add-mappings=true
#spring.resources.static-locations=classpath:static
#spring.mvc.static-path-pattern=/**,

删除了 @enableWebMVC并删除了所有WebMvcConfigurer覆盖

// @ EnableWebMvc

还要确保您的配置中有@EnableAutoConfiguration

并将所有静态资源放入src / main / resources / static中,它终于像魔术一样工作了。


在2.2.6和我的春天版本我有@EnableAutoConfiguration和在src /主/资源/静态文件,但它不工作,并抛出500
shivani塔库尔

1

使用Spring Boot 2. *,我有一个映射到路由的控制器,GetMapping({"/{var}", "/{var1}/{var2}", "/{var1}/{var2}/{var3}"})并且我的应用停止提供资源。

我知道不建议使用这样的路线,但这完全取决于您正在构建的应用程序(就我而言,我别无选择,只能使用这样的路线)

所以这是我的技巧,以确保我的应用再次提供资源。我只是有一个映射到我的资源的控制器。因为spring会先匹配一条直接路线,然后再匹配任何变量,所以我决定添加一个控制器方法,该方法映射到/imgaes/{name}其他资源并重复其他资源

@GetMapping(value = "/images/{image}", produces = {MediaType.IMAGE_GIF_VALUE, MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE})
    public @ResponseBody
    byte[] getImage(@PathVariable String image) {
        ClassPathResource file = new ClassPathResource("static/images/" + image);
        byte[] bytes;
        try {
            bytes = StreamUtils.copyToByteArray(file.getInputStream());
        } catch (IOException e) {
            throw new ResourceNotFoundException("file not found: " + image);
        }
        return bytes;
    }

这解决了我的问题


0

遇到了同样的问题,使用gradle和eclipse并花费了数小时试图找出答案。

无需编码,诀窍在于必须使用菜单选项“新建”->“源文件夹”(“不新建”->“文件夹”)在src / main / resources下创建静态文件夹。不知道为什么这样做,但是新建了->源文件夹,然后将其命名为静态文件夹(然后,源文件夹对话框给出了必须检查的错误:更新其他源文件夹中的排除过滤器以解决嵌套问题)。我添加了index.html这个新的静态文件夹,现在可以使用了。


0

好了,有时候值得检查一下是否由某些rest控制器覆盖了全局映射。简单示例错误(kotlin):

@RestController("/foo")
class TrainingController {

    @PostMapping
    fun bazz(@RequestBody newBody: CommandDto): CommandDto = return commandDto

}

在上述情况下,您将在请求静态资源时得到:

{
    title: "Method Not Allowed",
    status: 405,
    detail: "Request method 'GET' not supported",
    path: "/index.html"
}

造成这种情况的原因可能是您想映射@PostMapping到该级别,/foo但忘记了@RequestMapping@RestController级别上的注释。在这种情况下,所有请求都被映射到该情况下POST,您将不会收到静态内容。


0

给定资源src / main / resources / static下,如果添加此代码,则来自src / main / resources / static的所有静态内容将在“ /”下提供:

@Configuration
public class StaticResourcesConfigurer implements WebMvcConfigurer {
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/resources/static/");
    }
}

0

就我而言,没有提供某些静态文件,例如.woff字体和某些图像。但是css和js很好用。

更新:使Spring Boot正确提供woff字体的更好的解决方案是配置答案中提到的资源过滤,例如(请注意,您需要同时包含和排除):

<resources>
    <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
        <excludes>
            <exclude>static/aui/fonts/**</exclude>
        </excludes>
    </resource>
    <resource>
        <directory>src/main/resources</directory>
        <filtering>false</filtering>
        <includes>
            <include>static/aui/fonts/**</include>
        </includes>
    </resource>
</resources>

-----旧的解决方案(可以工作,但会损坏某些字体)-----

另一种解决方案是使用以下命令禁用后缀模式匹配 setUseSuffixPatternMatch(false)

@Configuration
public class StaticResourceConfig implements WebMvcConfigurer {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        // disable suffix matching to serve .woff, images, etc.
        configurer.setUseSuffixPatternMatch(false);
    }
}

鸣谢:@Abhiji确实向我指出了正确的方向4。


0

对/ **的请求将评估到resourceProperties中配置的静态位置

在application.properties上添加以下内容,可能是您唯一需要做的...

spring.resources.static-locations=classpath:/myresources/

这将覆盖默认的静态位置,其中包括:

ResourceProperties.CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
        "classpath:/resources/", "classpath:/static/", "classpath:/public/" };

您可能不想这样做,只是确保您的资源位于这些默认文件夹之一中。

执行请求:如果将example.html存储在/public/example.html上,则可以按以下方式进行访问:

<host>/<context-path?if you have one>/example.html

如果我想要另一个URI,例如<host>/<context-path>/magico/*classpath:/ magicofiles / *中的文件,则需要更多配置

@Configuration
class MyConfigClass implements WebMvcConfigurer

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/magico/**").addResourceLocations("/magicofiles/");
}

0

就我而言,我有一个Spring Boot应用程序,它是混合spring和jaxrs的一种。所以我有一个从该类继承的Java类org.glassfish.jersey.server.ResourceConfig。我必须将此行添加到该类的构造函数中,这样弹簧端点仍称为:property(ServletProperties.FILTER_FORWARD_ON_404, true)


-1

如上所述,该文件应位于$ClassPath/static/images/name.png,(/ static或/ public或/ resources或/ META-INF / resources)中。$ ClassPath的意思是main/resourcesmain/javadir。

如果文件不在标准目录中,则可以添加以下配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/lib/**"); // like this
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // ... etc.
}
...

}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.