How to serve static resources in Spring boot with #EnableWebMvc - spring-boot

Cracking head over this. The documentation says:
By default Spring Boot will serve static content from a directory called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext.
Minimal example:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
#SpringBootApplication
#EnableWebMvc
public class Main {
public static void main(final String[] args) {
SpringApplication.run(Main.class, args);
}
}
And create one directory /src/main/resources/public placing static resources there. When I run the application I only get 404. When I remove #EnableWebMvc resources are served as expected.
Attempted (and failed) remedies
/**
* #see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#addResourceHandlers(org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry)
*/
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/public/**").addResourceLocations("/public/");
}
In the application.properties added:
spring.mvc.static-path-pattern=/**
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
The question
So my question: What do I need to configure to serve static resource when I want to use the #EnableWebMvc annotation?

In the documentation you mentionned, it says :
If you want to take complete control of Spring MVC, you can add your
own #Configuration annotated with #EnableWebMvc.
You should try to use #EnableWebMvc with your configuration instead of your Spring boot application.
There's an example of this in this documentation.
Enabling the MVC Java Config or the MVC XML Namespace
To enable MVC Java config add the annotation #EnableWebMvc to one of
your #Configuration classes:
#Configuration
#EnableWebMvc
public class WebConfig {
}
Also in these examples :
Customizing the Provided Configuration
Conversion and Formatting
I hope this will help you.

You should configure a ViewResolver something like below along with your ResourceHandlers. Check this
#Bean
public InternalResourceViewResolver defaultViewResolver() {
return new InternalResourceViewResolver();
}

Related

Spring Boot: Adding static resources from file system breaks existing mappings

I have a Spring Boot MVC application in which I am trying to load resources from an external folder on the file system. I have used the following to configure this:
#Configuration
#EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/where/**")
.addResourceLocations("file:///C:/some/where/");
}
...
}
Once I configure this, I can access my static files by going to http://serverurl/where/somefile
BUT, I am no longer able to access the home page at http://serverurl/
Any idea what I did wrong here?

trigger component scan from a application for an included spring boot jar using extra annotations

I need to publish a Spring boot based jar which should be consumed in other Spring/Spring boot based applications.
In my reuse jar I have a class(BusinessConfig) annotated with #Configuration and it gives out two beans. This class is in the base package of the reuse jar.
#Configuration
public class BusinessConfig {
#Bean(name = "BusinessRepoManager")
public BusinessRepoManager businessRepoManager(){
return BusinessRepoManager.getInstance();
}
#Autowired
#Bean(name = "CustomerManager")
#Scope("request")
public CustomerManager customerManager(BusinessRepoManager busrepoManager){
return CustomerManager.getInstance();
}
}
In the second application, I have added the dependency and in the application class I have the statement
#ComponentScan(basePackageClasses = {BusinessConfig.class})
to inform Spring context to look for beans provided in BusinessConfig class as well.
This works well, as I could see the beans getting created.
Is there any possibility to simplify this, should all consuming applications know the class name in which my configuration exists/package name.
I tried creating a custom annotation in the jar project and used that in the consuming application.
#ComponentScan(basePackageClasses = {BusinessConfig.class})
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#Component
public #interface EnableDemoBusiness {
}
Then in my consuming application I just added
#EnableDemoBusiness
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Is there any way to get this work ?
Thanks in advance !
You have a couple of options:
Option 1
You can turn your class into "auto-configuration", by creating a META-INF/spring.factories file in your jar with the following content:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.your.package.BusinessConfig
Now in applications using your jar if #EnableAutoConfiguration or #SpringBootApplication annotations are used, your configuration will be processed and the beans created.
You might want to annotate your configuration with some #ConditionalXXX annotations if required to give applications that use your jar more control.
Refer to the documentation for more information.
Options 2
You can create a custom #EnableXXX annotation like you attempted.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#Import(com.your.package.BusinessConfig.class)
public #interface EnableDemoBusiness {
}

How to display "welcome.jsp" in spring boot?

Facing issues while displaying customized welcome.jsp in spring boot application.
It always displays "index.html" while I want to display customized jsp file "welcome.jsp"..
Request help.
1) make sure springmvc options in application.properties
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
2) add src/main/webapp/WEB-INF/jsp/welcome.jsp
3) modify Application like this:
package com.lenicliu.spring.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("welcome");
}
}
Please refer to http://docs.spring.io/spring/docs/4.2.6.RELEASE/spring-framework-reference/htmlsingle/#mvc-config-view-controller
Then, run application, and you can find the log:
Root mapping to handler of type [class org.springframework.web.servlet.mvc.ParameterizableViewController]

Changing default welcome-page for spring-boot application deployed as a war

I was trying to find a way to change the default welcome-page for a spring-boot application that is being deployed as a war in production but I can't find a way to do it without a web.xml file.
According to the documentation we can do it using the EmbeddedServletContainerFactory with this code:
#Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
TomcatContextCustomizer contextCustomizer = new TomcatContextCustomizer() {
#Override
public void customize(Context context) {
context.addWelcomeFile("/<new welcome file>");
}
};
factory.addContextCustomizers(contextCustomizer);
return factory;
}
Although, as we're creating a war file and deploying it to tomcat and not using the Embedded Tomcat, this isn't doing anything.
Any idea? If we really need to add a web.xml file, how can we do it and still using spring boot? Should we specify the Application bean(with the main method) as the application context for DispatcherServlet? The documentation isn't very clear about that.
Older Servlet containers don’t have support for the ServletContextInitializer bootstrap process used in Servlet 3.0. You can still use Spring and Spring Boot in these containers but you are going to need to add a web.xml to your application and configure it to load an ApplicationContext via a DispatcherServlet.
Thanks in advance!
Pedro
It's not too hard to do... you just need to forward the default mapping...
#Configuration
public class DefaultView extends WebMvcConfigurerAdapter{
#Override
public void addViewControllers( ViewControllerRegistry registry ) {
registry.addViewController( "/" ).setViewName( "forward:/yourpage.html" );
registry.setOrder( Ordered.HIGHEST_PRECEDENCE );
super.addViewControllers( registry );
}
}
Well, a few years passed since the last answer - and code evolves..
This won't work on Spring 5 / Java 8+, you should implement the interface and override the default method.
import org.springframework.core.Ordered;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class DefaultViewConfig implements WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("/homepage.html");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
}
Following Michael's tutorial, I was able to just map / to my index.gsp file.
#Controller
class Routes {
#RequestMapping({
"/",
"/bikes",
"/milages",
"/gallery",
"/tracks",
"/tracks/{id:\\w+}",
"/location",
"/about"
})
public String index() {
return "forward:/index.gsp";
}
}
I am doing it as follows.
package org.gwtproject.tutorial.configuration;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* Configure the welcome page
*
*/
#Configuration
public class SpringBootWelcomePageConfiguration extends WebMvcConfigurerAdapter implements WebMvcConfigurer {
/**
* redirect a user to the welcome page when he visits tha app without a
* destination url.
*/
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/ForExampleAGwtEntrypoint.html");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
super.addViewControllers(registry);
}
}

META-INF/resources not works properly with #EnableWebMVC in Spring Boot

1.
I'm working with Spring Boot. My Main class very simple
#ComponentScan
#EnableAutoConfiguration
#Configuration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#2. Now I would like to make my static content externalised into a jar file. So, below is the jar project
/pom.xml
/src/main/resources/META-INF/resources/hello.json // here is my resource
I do maven install and put the dependency into the main app, run the app normally. Now I can invoke http://localhost:8080/hello.json to get my hello.json file
#3. Then, the next step is using the Apache Tiles for my main web project, so I create a #EnableWebMvc class to configure the tilesViewResolver
#Configuration
#EnableWebMvc
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
public #Bean TilesViewResolver tilesViewResolver() {
return new TilesViewResolver();
}
public #Bean TilesConfigurer tilesConfigurer() {
TilesConfigurer ret = new TilesConfigurer();
ret.setDefinitions(new String[] { "classpath:tiles.xml" });
return ret;
}
}
Then I started again the application and try the hello.json to ensure everything still works properly. But, the 404 page appear. Delete the WebMvcConfiguration give back my hello.json.
What configuration I should do to resolve this issue?
Thanks a lot.
In Spring MVC, using XML configuration, you have to have a tag like the following to service static content:
<mvc:resources mapping="/js/**" location="/js/"/>
This insinuates that Spring Boot is doing something to automatically guess that you have static content and properly setup the above example in META-INF/resources. It's not really "magic", but rather that they have a default Java Configuration using #EnableWebMvc that has some pretty reliable default values.
When you provide your own #EnableWebMvc, my guess is you are over-writting their "default" one. In order to add back a resource handler, you would do something like this:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
}
This is equivalent to the XML above.

Resources