Spring 4 - addResourceHandlers无法解析静态资源

36

我的Maven Spring项目目录结构如下所示。我正在使用基于Spring-4注释的配置。我像下面这样配置资源。我尝试了许多在Stackoverflow和其他网站上建议的方法,但jsp文件无法加载资源,所有静态内容请求都返回404错误。我在jsp中尝试了这些事情,

Spring 4 loading static resources

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

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

编辑:目前我无法将我的项目从JBoss 5升级到更高版本,因此我正在使用servlet 2.5。 JBoss5不支持servlet 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?
     }

}

项目结构


您需要在您的Web应用程序上添加前缀上下文路径。 - Sotirios Delimanolis
但是,这样不会硬编码上下文吗?我想知道在xml配置中使用相同配置时它是如何工作的,比如spring-3.2.6! - vvra
你不需要硬编码任何东西:https://dev59.com/QWnWa4cB1Zd3GeqPxSS4 - Sotirios Delimanolis
5个回答

24

这个方法有效。

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

而在jsp文件中,我像下面这样引用了静态资源:

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

4
我错了,这是“蚂蚁风格路径模式”。在这里查看:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-patterns - smwikipedia
注意了,Spring Boot 2.4.x 现在默认禁用了默认的 servlet - https://github.com/spring-projects/spring-boot/issues/22915 - Nigel Sheridan-Smith

13

我想可能已经有点晚了,但是最近我也遇到了类似的问题。经过几天的搏斗,最终发现我的DispatcherServlet没有配置处理请求,因此资源从未被查找。所以我希望其他人能够从这个答案中获益。

如果你给上面提供的配置类的调度程序servlet不是映射到根目录("/"),而是映射到顶级单词(例如"/data/"),那么你可能会遇到同样的问题。

假设我为我的调度程序servlet设置了一个映射为“/data/*”。那么我的调用看起来像:

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

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

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

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

http://localhost:8080/myWebAppContent/data/content/resourcePath
相反。对我来说不明显,因为大多数示例使用根“/”作为调度程序servlet的映射,所以这里没有问题。后来考虑到我早该知道 - /data/表示DispatcherServlet应该评估调用,而content/告诉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/*");
}

}

MidtierAppConfig类为空,但MidtierDispatcherConfig定义了静态资源:

@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/")
        ;
    }
}
现在当我想要访问我的@Controller时,我使用/data/前缀,而当我想要访问我的资源时,我使用/content/前缀。需要注意的是,如果我有一个@RequestMapping("/app")类,其中有一个@RequestMapping("/about")方法,则data/app/about和content/app/about将都调用同一个方法(我猜即使我尝试访问资源也可能会使用/app/courses/whatEverPath路径)。这是因为调度程序同时监听"data/"和"content/",并仅分析URL的其余部分(在这两种情况下均为"app/about")以找到正确的@Controller。 无论如何,我已经达到了满意的解决方案,所以我会保留它不变。

谢谢!我正在尝试在同一上下文中配置两个servlet:一个用于REST API,另一个用于Swagger文档。你的帖子帮了很大的忙 ;) - Marco Ferrari

8
这对我很有帮助。文件可在/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/");
    }
}

4

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

我的文件夹结构如下:

enter image description here

我的代码:

@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("/**");
    }
}

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

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

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


0

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

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

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

这是有用的,直到您想要将CSS文件分开(比如按主题)。该方法假定CSS文件始终位于一个目录结构中。您将无法区分resources/theme1/cssresources/theme2/css - coderatchet
@coderatchet 这不应该是问题,也与Spring无关。你需要将主题的CSS放在类似于resources/css/theme1resources/css/theme2的结构中。然后,你可以使用href="theme1/styles.css"来引用你的CSS。根据你所描述的结构,无论使用哪个框架都会遇到问题,因为逻辑上不可能区分这样的东西。 - eja
registry.addResourceHandler("**/*.css").addResourceLocations("/")请将上述程序相关内容翻译成中文。仅返回翻译后的文本。 - Alex78191

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