Java Spring 4 - addResourceHandlers 不解析静态资源

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25061237/
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-08-10 23:32:18  来源:igfitidea点击:

Spring 4 - addResourceHandlers not resolving the static resources

javaspringspring-mvcspring-annotationsspring-4

提问by Vijay Veeraraghavan

My maven spring project directory structure is shown below. I am using Spring-4 annotation based configuration. I configure the resources like below. I tried many ways that are suggested in many Stackoverflow questions and other websites

我的maven spring项目目录结构如下图。我正在使用基于 Spring-4 注释的配置。我配置资源如下。我尝试了许多 Stackoverflow 问题和其他网站中建议的方法

Spring 4 loading static resources

Spring 4 加载静态资源

http://imwill.com/spring-mvc-4-add-static-resources-by-annotation/#.U5GZlXKs9i4

http://imwill.com/spring-mvc-4-add-static-resources-by-annotation/#.U5GZlXKs9i4

But the jsp files could not load the resources, all the static content requests returns 404 error. I tried these things in jsp,

但是jsp文件无法加载资源,所有静态内容请求都返回404错误。我在jsp中尝试过这些东西,

 <link href="resources/css/bootstrap.css" rel="stylesheet" media="screen">
 <link href="/resources/css/bootstrap.css" rel="stylesheet" media="screen">
 <link href="css/bootstrap.css" rel="stylesheet" media="screen">

EDIT: I am using servlet 2.5 because as of now I cannot upgrade my project from JBoss 5 to higher versions. JBoss5 do not support servlets 3, and do that matter?

编辑:我正在使用 servlet 2.5,因为到目前为止我无法将我的项目从 JBoss 5 升级到更高版本。JBoss5 不支持 servlets 3,这有关系吗?

@Configuration
@ComponentScan("com.mgage.mvoice")
public class MyAppWebConfig extends WebMvcConfigurerAdapter {
     public void addResourceHandlers(ResourceHandlerRegistry registry) {  
        // I tried these many combinations separately.

        ResourceHandlerRegistration resourceRegistration = registry
            .addResourceHandler("resources/**");
        resourceRegistration.addResourceLocations("/resources/**");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/**");
        registry.addResourceHandler("/img/**").addResourceLocations("/img/**");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/**");
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("classpath:/resources/"); 
              // do the classpath works with the directory under webapp?
     }

}

Project structure

项目结构

采纳答案by Vijay Veeraraghavan

this worked,

这有效,

   registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");

and in the jsp files I referred to the static resources like

在jsp文件中我提到了静态资源,比如

<link href="resources/css/bootstrap.css" rel="stylesheet" media="screen">

回答by Ivan Ketler

I guess it's a bit late, however I was facing with a similar problem just recently. After several days of wrestling, finally it turned out that my DispatcherServlet was not configured to handle the request, therefore the resources were never looked up. So I hope others will find this answer useful.

我想这有点晚了,但是我最近遇到了类似的问题。折腾了几天,终于发现我的DispatcherServlet没有配置处理请求,所以一直没有查到资源。所以我希望其他人会发现这个答案很有用。

If the dispatcher servlet to that you give your config class above is mapped not to the root ("/") but to a top word (e.g. "/data/"), then you might face with the same problem.

如果您在上面提供的配置类的调度程序 servlet 不是映射到根(“/”)而是映射到顶部单词(例如“/data/”),那么您可能会面临同样的问题。

Suppose I have a mapping as "/data/*" for my dispatcher servlet. So my calls look like

假设我的调度程序 servlet 有一个映射为“/data/*”。所以我的电话看起来像

http://localhost:8080/myWebAppContext/data/command

and I thought that if I have a resource mapping e.g. "/content/**/*", then I have access to it as

我认为如果我有一个资源映射,例如“/content/**/*”,那么我可以访问它

http://localhost:8080/myWebAppContent/content/resourcePath

but it's not true, I should use

但这不是真的,我应该使用

http://localhost:8080/myWebAppContent/data/content/resourcePath

instead. This was not clear for me, and since most of the samples use the root "/" for the dispatcher servlet's mapping, therefore it was not an issue there. Upon considering later I should have known it earlier - /data/ tells that the DispatcherServlet should evaluate the call, and the content/ tells to the servlet that a resource handler is the "controller".

反而。这对我来说并不清楚,而且由于大多数示例使用根“/”作为调度程序 servlet 的映射,因此这不是问题。稍后考虑时,我应该早点知道它 - /data/ 告诉 DispatcherServlet 应该评估调用,而 content/ 告诉 servlet 资源处理程序是“控制器”。

But I want to make it very clear in my frontend (angularJs) whether I look for data (via the REST services) or a content (returning plain texts). The data comes from a database, but the content comes from files (e.g. pdf docs). Therefore, I decided to add two mappings to the dispatcher servlet:

但我想在我的前端 (angularJs) 中非常清楚我是查找数据(通过 REST 服务)还是内容(返回纯文本)。数据来自数据库,但内容来自文件(例如 pdf 文档)。因此,我决定向调度程序 servlet 添加两个映射:

public class MidtierWebConfig implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {

    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(MidtierAppConfig.class);

    servletContext.addListener(new ContextLoaderListener(rootContext));

    AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
    dispatcherContext.register(MidtierDispatcherConfig.class);

    Dynamic netskolaDispatcher = servletContext.addServlet(
        "dispatcher",
        new DispatcherServlet(dispatcherContext)
    );
    netskolaDispatcher.setLoadOnStartup(1);
    netskolaDispatcher.addMapping("/data/*");
    netskolaDispatcher.addMapping("/content/*");
}

}

The MidtierAppConfig class is empty, but the MidtierDispatcherConfig defines the static resources:

MidtierAppConfig 类为空,但 M​​idtierDispatcherConfig 定义了静态资源:

@Configuration
@ComponentScan("my.root.package")
@EnableWebMvc
public class MidtierDispatcherConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry
            .addResourceHandler("/courses/**/*")
            .addResourceLocations("/WEB-INF/classes/content/")
        ;
    }
}

Now when I want to have access to my @Controller's, I use the /data/ prefix, and when I want to access to my resources, I use the /content/ prefix. Caveat is that if I have a @RequestMapping("/app") class which has a @RequestMapping("/about") method, then both the data/app/about and the content/app/about will call just that method (and without actually trying I guess I might access the resources as /app/courses/whatEverPath too), because the dispatcher listends to both "data/" and "content/", and analyzes only the rest of the url ("app/about" in both cases) to find the proper @Controller.

现在,当我想访问我的@Controller 时,我使用 /data/ 前缀,而当我想访问我的资源时,我使用 /content/ 前缀。警告是,如果我有一个 @RequestMapping("/app") 类,它有一个 @RequestMapping("/about") 方法,那么 data/app/about 和 content/app/about 都将只调用该方法(并且没有实际尝试,我想我也可能以 /app/courses/whatEverPath 的形式访问资源),因为调度程序会同时侦听“data/”和“content/”,并且仅分析 url 的其余部分(“app/about " 在这两种情况下)找到合适的@Controller。

Regardless, the current solution I've reached is satisfactory enough for me, so I will leave it as it is.

无论如何,我所达到的当前解决方案对我来说已经足够令人满意了,所以我将保持原样。

回答by kundan

This worked for me. Files available at /resources/js/select.js. Watch out that you are not missing @EnableWebMvcannotation....

这对我有用。文件可在 /resources/js/select.js. 请注意您没有丢失@EnableWebMvc注释....

@EnableWebMvc
@EnableTransactionManagement
public class ApplicationContextConfig extends WebMvcConfigurerAdapter {

    @Bean(name = "viewResolver")
    public InternalResourceViewResolver getViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
        return viewResolver;
    }

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

回答by beemaster

It is possible to simplify the web page's URI just to contain the filename of a resource:
<link href="bootstrap.css" rel="stylesheet" media="screen">
An appropriate configuration might be as the following:

可以简化网页的 URI 以包含资源的文件名:
<link href="bootstrap.css" rel="stylesheet" media="screen">
适当的配置可能如下所示:

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

Spring concatenates '/resources/css/' string with whatever filename extracted from URI to identify the actual location of a resource.

Spring 将 '/resources/css/' 字符串与从 URI 中提取的任何文件名连接起来,以标识资源的实际位置。

回答by Rafael S. Fijalkowski

I am using Spring Boot 2.2.1 and with "spring-boot-starter-web" and "spring-boot-starter-tomcat". In my case the Spring Boot only could find the "/resources/" folder when I use empty "classpath:/"

我正在使用 Spring Boot 2.2.1 和“spring-boot-starter-web”和“spring-boot-starter-tomcat”。在我的情况下,当我使用空的“类路径:/”时,Spring Boot 只能找到“ /resources/”文件夹

My folder structure:

我的文件夹结构:

enter image description here

在此处输入图片说明

My code:

我的代码:

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

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }
}

And using the browser I can find any file like:

使用浏览器我可以找到任何文件,如:

http://localhost:8080/resources/test.txt

http://localhost:8080/resources/test.txt

http://localhost:8080/resources/images/background-1.png

http://localhost:8080/resources/images/background-1.png