Spring 4 - addResourceHandlers не разрешает статические ресурсы

Структура каталогов моего проекта maven spring показана ниже. Я использую конфигурацию на основе аннотаций Spring-4. Я настраиваю ресурсы, как показано ниже. Я пробовал много способов, которые предлагаются во многих вопросах Stackoverflow и на других веб-сайтах.

Spring 4 загружает статические ресурсы

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

Но файлы 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">

РЕДАКТИРОВАТЬ: я использую сервлет 2.5, потому что на данный момент я не могу обновить свой проект с JBoss 5 до более высоких версий. JBoss5 не поддерживает сервлеты 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?
     }

}

Структура проекта


person Vijay Veeraraghavan    schedule 31.07.2014    source источник
comment
Вам необходимо добавить путь контекста вашего веб-приложения.   -  person Sotirios Delimanolis    schedule 31.07.2014
comment
Но разве это не жестко закодирует контекст? Интересно, как это работает с той же конфигурацией, но в конфиге xml spring-3.2.6!   -  person Vijay Veeraraghavan    schedule 31.07.2014
comment
Вы ничего не кодируете жестко: stackoverflow.com/questions/12705193/   -  person Sotirios Delimanolis    schedule 31.07.2014


Ответы (5)


это сработало,

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

и в файлах jsp я ссылался на статические ресурсы, такие как

<link href="resources/css/bootstrap.css" rel="stylesheet" media="screen">
person Vijay Veeraraghavan    schedule 01.08.2014
comment
Моя ошибка. Это Ant-style path patterns. Проверьте здесь: docs.spring.io/spring/docs/current/spring-framework-reference/ - person smwikipedia; 06.12.2015
comment
Следите за тем, как Spring Boot 2.4.x по умолчанию отключает сервлет по умолчанию - github.com/ Spring-projects / Spring-boot / issues / 22915 - person Nigel Sheridan-Smith; 10.02.2021

Думаю, уже немного поздно, но совсем недавно я столкнулся с подобной проблемой. После нескольких дней борьбы наконец выяснилось, что мой DispatcherServlet не был настроен для обработки запроса, поэтому ресурсы никогда не просматривались. Так что я надеюсь, что другие сочтут этот ответ полезным.

Если сервлет диспетчера, которому вы передаете свой класс конфигурации выше, сопоставлен не с корнем ("/"), а с верхним словом (например, "/ data /"), вы можете столкнуться с той же проблемой.

Предположим, у меня есть отображение как «/ data / *» для моего сервлета диспетчера. Так что мои звонки выглядят так

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

и я подумал, что если у меня есть сопоставление ресурсов, например "/ content / ** / *", то у меня есть доступ к нему как

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

но это неправда, я должен использовать

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

вместо. Для меня это было непонятно, и, поскольку в большинстве примеров для отображения сервлета диспетчера используется корень «/», это не было проблемой. Рассмотрев позже, я должен был знать это раньше - / data / сообщает, что DispatcherServlet должен оценить вызов, а содержимое / сообщает сервлету, что обработчик ресурсов является «контроллером».

Но я хочу, чтобы в моем интерфейсе (angularJs) было очень ясно, ищу ли я данные (через службы REST) ​​или контент (возвращая простые тексты). Данные поступают из базы данных, а содержимое - из файлов (например, документов в формате pdf). Поэтому я решил добавить к сервлету диспетчера два сопоставления:

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 / course / whatEverPath), потому что диспетчер прослушивает как «data /», так и «content /», и анализирует только остальную часть URL-адреса («app / about "в обоих случаях), чтобы найти подходящий @Controller.

Тем не менее, текущее решение, которого я достиг, достаточно меня устраивает, поэтому я оставлю его как есть.

person Ivan Ketler    schedule 06.09.2014
comment
Спасибо! Я пытался настроить два сервлета в одном контексте: один для REST api, а другой - для документации Swagger. Ваш пост очень помог;) - person Marco Ferrari; 12.09.2014

Это сработало для меня. Файлы доступны по адресу /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/");
    }
}
person kundan    schedule 05.06.2015

Я использую Spring Boot 2.2.1 и с «spring-boot-starter-web» и «spring-boot-starter-tomcat». В моем случае Spring Boot может найти папку «/ resources /» только тогда, когда я использую пустой «classpath: /»

Моя структура папок:

введите описание изображения здесь

Мой код:

@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

person Rafael S. Fijalkowski    schedule 23.02.2020

Можно упростить 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, для определения фактического местоположения ресурса.

person beemaster    schedule 29.02.2016
comment
это полезно до тех пор, пока вы не захотите разделить файлы css (скажем, на темы). Этот метод предполагает, что файлы css всегда будут в одной структуре каталогов. вы не сможете отличить resources/theme1/css от resources/theme2/css - person coderatchet; 07.06.2017
comment
@coderatchet, это не должно быть проблемой и не имеет ничего общего со Spring. В первую очередь вы захотите поместить CSS ваших тем в структуру типа resources/css/theme1 и resources/css/theme2. Тогда вы должны использовать свой css как href="theme1/styles.css". Со структурой, которую вы описали, вы столкнетесь с проблемами независимо от структуры, потому что логически невозможно различить что-то подобное. - person eja; 08.09.2019