Question
I am trying to set a Spring Boot applications context root programmatically.
The reason for the context root is we want the app to be accessed from
localhost:port/{app_name}
and have all the controller paths append to it.
Here is the application configuration file for the web-app.
@Configuration
public class ApplicationConfiguration {
Logger logger = LoggerFactory.getLogger(ApplicationConfiguration.class);
@Value("${mainstay.web.port:12378}")
private String port;
@Value("${mainstay.web.context:/mainstay}")
private String context;
private Set<ErrorPage> pageHandlers;
@PostConstruct
private void init(){
pageHandlers = new HashSet<ErrorPage>();
pageHandlers.add(new ErrorPage(HttpStatus.NOT_FOUND,"/notfound.html"));
pageHandlers.add(new ErrorPage(HttpStatus.FORBIDDEN,"/forbidden.html"));
}
@Bean
public EmbeddedServletContainerFactory servletContainer(){
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
logger.info("Setting custom configuration for Mainstay:");
logger.info("Setting port to {}",port);
logger.info("Setting context to {}",context);
factory.setPort(Integer.valueOf(port));
factory.setContextPath(context);
factory.setErrorPages(pageHandlers);
return factory;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
}
Here is the index controller for the main page.
@Controller
public class IndexController {
Logger logger = LoggerFactory.getLogger(IndexController.class);
@RequestMapping("/")
public String index(Model model){
logger.info("Setting index page title to Mainstay - Web");
model.addAttribute("title","Mainstay - Web");
return "index";
}
}
The new root of the application should be at localhost:12378/mainstay
, but
it is still located at localhost:12378
.
What am I missing that is causing Spring Boot to not append the context root before the request mapping?
Answer
Why are you trying to roll your own solution. Spring-boot already supports that.
If you don't already have one, add an application.properties
file to
src\main\resources
. In that properties file, add 2 properties:
server.contextPath=/mainstay
server.port=12378
UPDATE (Spring Boot 2.0)
As of Spring Boot 2.0 (due to the support of both Spring MVC and Spring
WebFlux) the contextPath
has been changed to the following:
server.servlet.context-path=/mainstay
You can then remove your configuration for the custom servlet container. If
you need to do some post processing on the container you can add a
EmbeddedServletContainerCustomizer
implementation to your configuration (for
instance to add the error pages).
Basically the properties inside the application.properties
serve as a
default you can always override them by using another application.properties
next to the artifact you deliver or by adding JVM parameters
(-Dserver.port=6666
).
See also [The Reference Guide](http://docs.spring.io/spring- boot/docs/current/reference/html) especially the [properties](https://docs.spring.io/spring- boot/docs/current/reference/htmlsingle/#common-application-properties) section.
The class [ServerProperties
](https://github.com/spring-projects/spring-
boot/blob/master/spring-boot-
autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java)
implements the EmbeddedServletContainerCustomizer
. The default for
contextPath
is ""
. In your code sample you are setting the contextPath
directly on the TomcatEmbeddedServletContainerFactory
. Next the
ServerProperties
instance will process this instance and reset it from your
path to ""
. ([This line](https://github.com/spring-projects/spring-
boot/blob/master/spring-boot-
autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java#L110)
does a null
check but as the default is ""
it always fail and set the
context to ""
and thus overriding yours).