Spring 4 - addResourceHandlers não resolve os recursos estáticos
-
22-12-2019 - |
Pergunta
Minha estrutura de diretórios do projeto maven spring é mostrada abaixo.Estou usando a configuração baseada em anotação Spring-4.Eu configuro os recursos como abaixo.Eu tentei muitas maneiras sugeridas em muitas perguntas do Stackoverflow e outros sites
Spring 4 carregando recursos estáticos
http://imwill.com/spring-mvc-4-add-static-resources-by-annotation/#.U5GZlXKs9i4
Mas os arquivos jsp não conseguiram carregar os recursos, todas as solicitações de conteúdo estático retornam erro 404.Eu tentei essas coisas em 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">
EDITAR:Estou usando o servlet 2.5 porque no momento não consigo atualizar meu projeto do JBoss 5 para versões superiores.O JBoss5 não suporta servlets 3, e isso importa?
@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?
}
}
Solução
isso funcionou,
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
e nos arquivos jsp me referi aos recursos estáticos como
<link href="resources/css/bootstrap.css" rel="stylesheet" media="screen">
Outras dicas
Acho que é um pouco tarde, mas recentemente enfrentei um problema semelhante.Depois de vários dias de luta, finalmente descobri que meu DispatcherServlet não estava configurado para lidar com a solicitação e, portanto, os recursos nunca foram consultados.Portanto, espero que outros considerem esta resposta útil.
Se o servlet do despachante para o qual você fornece sua classe de configuração acima estiver mapeado não para a raiz ("/"), mas para uma palavra superior (por exemplo,"/data/"), então você poderá enfrentar o mesmo problema.
Suponha que eu tenha um mapeamento como "/data/*" para meu servlet despachante.Então minhas ligações parecem
http://localhost:8080/myWebAppContext/data/command
e pensei que se eu tivesse um mapeamento de recursos, por ex."/content/**/*", então tenho acesso a ele como
http://localhost:8080/myWebAppContent/content/resourcePath
mas não é verdade, eu deveria usar
http://localhost:8080/myWebAppContent/data/content/resourcePath
em vez de.Isso não ficou claro para mim e, como a maioria dos exemplos usa a raiz "/" para o mapeamento do servlet do despachante, isso não foi um problema.Ao considerar mais tarde, eu deveria ter sabido disso antes - /data/ informa que o DispatcherServlet deve avaliar a chamada, e o content/ informa ao servlet que um manipulador de recursos é o "controlador".
Mas quero deixar bem claro no meu frontend (angularJs) se procuro dados (através dos serviços REST) ou um conteúdo (retornando textos simples).Os dados vêm de um banco de dados, mas o conteúdo vem de arquivos (por exemplo,documentos em pdf).Portanto, decidi adicionar dois mapeamentos ao servlet do despachante:
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/*");
}
}
A classe MidtierAppConfig está vazia, mas MidtierDispatcherConfig define os recursos estáticos:
@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/")
;
}
}
Agora, quando quero ter acesso ao meu @Controller, uso o prefixo /data/, e quando quero acessar meus recursos, uso o prefixo /content/.A advertência é que se eu tiver uma classe @RequestMapping("/app") que tenha um método @RequestMapping("/about"), então tanto o data/app/about quanto o content/app/about chamarão apenas esse método ( e sem realmente tentar, acho que posso acessar os recursos como /app/courses/whatEverPath também), porque o despachante escuta "dados/" e "conteúdo/" e analisa apenas o resto da URL ("app/about " em ambos os casos) para encontrar o @Controller adequado.
Independentemente disso, a solução atual que alcancei é satisfatória o suficiente para mim, então deixarei como está.
Isso funcionou para mim.Arquivos disponíveis em /resources/js/select.js
.Cuidado que você não está faltando @EnableWebMvc
anotação....
@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/");
}
}
É possível simplificar o URI da página web apenas para conter o nome do arquivo de um recurso:
<link href="bootstrap.css" rel="stylesheet" media="screen">
Uma configuração apropriada pode ser a seguinte:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("*.css").addResourceLocations("/resources/css/");
}
Spring concatena a string '/resources/css/' com qualquer nome de arquivo extraído do URI para identificar a localização real de um recurso.