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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21358403/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 06:30:02  来源:igfitidea点击:

Spring Boot project with static content generates 404 when running jar

springmavenjettyspring-bootstatic-content

提问by Robert Hunt

The recent blog post (https://spring.io/blog/2013/12/19/serving-static-web-content-with-spring-boot) by Spring regarding the use of static web content in Spring Boot projects indicates that several resource directories may be used:

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

  • /META-INF/resources/
  • /resources/
  • /static/
  • /public/
  • /元信息/资源/
  • /资源/
  • /静止的/
  • /民众/

This is thanks to the WebMvcAutoConfiguration class which automatically adds these directories to the classpath. This all seems fine and appears to work when using the spring-boot-maven-pluginspring-boot:rungoal, all of your static content is working (eg: /index.html).

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

When you package your Spring Boot project and allow the spring-boot-maven-pluginto create the enhanced JAR then attempt to run your project using java -jar my-spring-boot-project.jaryou find that your static content now returns a 404 error.

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

回答by Robert Hunt

It turns out that whilst Spring Boot is being clever at adding the various resource directories to the classpath, Maven is not and it's up to you to deal with that part. By default, only src/main/resourceswill be included in your JAR. If you create a folder called /staticin the root of your project (as implied by the blog post) then it will work fine whilst using the spring-boot:runMaven goal but not once you create a JAR.

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

The easiest solution is to create your /staticfolder inside /src/main/resourcesand then Maven will include it in the JAR. Alternative you can add additional resource locations to your Maven project:

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

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

I hope this is useful to someone, it's kind of obvious when you step back and look at how Maven works but it might stump a few people using Spring Boot as it's designed to be pretty much configuration free.

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

回答by kgreenek

I am banging my head against the wall trying to figure out how to do this with gradle. Any tips?

我正在用头撞墙,试图弄清楚如何用 gradle 做到这一点。有小费吗?

EDIT: I got it to work by adding this to my build.gradle:

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

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

回答by Sriram

I was going around few pages to understand how to serve static content in Spring boot environment. Mostly all advises was around placing the static files with in /static /resources/ src/main/webapp etc. Thought of sharing below approach.

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

  1. Allow spring boot to auto configure Dispatcher Servlet - Make sure DispatcherServletAutoConfiguration is not in the exclude for AutoConfiguration.

    @EnableAutoConfiguration(exclude = { //DispatcherServletAutoConfiguration.class, })

  2. Inject your external directory for static content routing

    @Value("${static-content.locations:file:C:/myprj/static/") private String[] staticContentLocations;

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

    @EnableAutoConfiguration(exclude = { //DispatcherServletAutoConfiguration.class, })

  2. 为静态内容路由注入外部目录

    @Value("${static-content.locations:file:C:/myprj/static/") private String[] staticContentLocations;

3.Override WebMvcAutoConfiguration using WebMvcConfigurerAdapter to advice spring not to use default resource Location but use what we instruct it.Like below

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);
                }
            }
        };
    }

If C:/myprj/static has index.html , then http://localhost:portno/index.htmlshould work. Hope that helps.

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

回答by gjp

There are 2 things to consider (Spring Boot v1.5.2.RELEASE)-

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

1) Check all Controller classes for @EnableWebMvc annotation, remove it if there is any

1)检查所有Controller类是否有@EnableWebMvc注解,如果有就去掉

2) Check the Controller classes for which annotation is used - @RestController or @Controller.

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

Do not mix Rest API and MVC behaviour in one class. For MVC use @Controller and for REST API use @RestController

不要在一个类中混合 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>

回答by acoder2013

Spring Boot will use WebMvcAutoConfigurationto config static contents, this class will only take effects when you don't have a custom WebMvcConfigurationSupportbean ,and in my cases , i do have one.

Spring Boot 将用于WebMvcAutoConfiguration配置静态内容,这个类只有在你没有自定义WebMvcConfigurationSupportbean时才会生效,在我的情况下,我有一个。

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

}

so i'll just have to config it by myself, here is my solution:

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

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

回答by Venkat

I've a assets folder in static dir and permitting in SpringConfig which extended WebSecurityConfigurerAdapter.

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

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