Reputation: 9335
I'm trying to to mix mvc and rest in a single spring boot project.
I want to set base path for all rest controllers (eg. example.com/api)
in a single place (I don't want annotate each controller with @RequestMapping('api/products')
, instead, just @RequestMapping('/products')
.
Mvc controllers should be accessible by example.com/whatever
Is it possible?
(I don't use spring data rest, just spring mvc)
Upvotes: 203
Views: 382568
Reputation: 966
I might be a bit late, BUT... I believe it is the best solution. Set it up in your application.yml (or similar config file):
spring:
data:
rest:
basePath: /api
As I can remember that's it - all of your repositories will be exposed beneath this URI.
Upvotes: 6
Reputation: 803
For Spring WebFlux the approach is similar to Harald's, but with the obvious WebFlux configuration set up:
@Configuration
public class WebFluxConfig implements WebFluxConfigurer {
@Override
public void configurePathMatching(PathMatchConfigurer configurer) {
configurer.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
}
}
And for Kotlin it's:
@Configuration
class WebFluxConfig : WebFluxConfigurer {
override fun configurePathMatching(configurer: PathMatchConfigurer) {
configurer.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController::class.java))
}
Upvotes: 1
Reputation: 311
I did some research on the differences of spring properties mentioned in this thread. Here are my findings if anybody is wondering.
spring.data.rest.basePath=/api
This property is specifically for Spring Data Rest projects. It won't work in a usual Spring MVC projects.
To change the context path in MVC projects, you can use those two properties mentioned below. Let me mention the differences too.
server.servlet.context-path=/api
This one sets the context path on your web servelet. This property perfectly works fine in both spring mvc and spring data rest projects. But, the differnce is the request url will be filter out before reaching spring interceptors. So it will respond with HTML on bad request. Not Spring's or your own custom JSON response (in @ResponseBodyAdvice annotated class) defined. To overcome that, you should use this property below.
spring.mvc.servlet.path=/api
This will filter the request URL in spring mvc interceptors and will respond default/your custom JSON response if you invoke a bad request.
So as the OP's question, I would suggest that he should use spring.mvc.servlet.path to change the context path.
Upvotes: 21
Reputation: 199
server.servlet.context-path=/api
would be the solution I guess. I had the same issue and this got me solved. I used server.context-path. However, that seemed to be deprecated and I found that server.servlet.context-path
solves the issue now. Another workaround I found was adding a base tag to my front end (H5) pages. I hope this helps someone out there.
Cheers
Upvotes: 1
Reputation: 5532
For those who use YAML configuration(application.yaml).
Note: this works only for Spring Boot 2.x.x
server:
servlet:
contextPath: /api
If you are still using Spring Boot 1.x
server:
contextPath: /api
Upvotes: 1
Reputation: 11
You can create a custom annotation for your controllers:
Use it instead of the usual @RestController on your controller classes and annotate methods with @RequestMapping.
Works fine in Spring 4.2!
Upvotes: 1
Reputation: 2265
With Spring Boot 1.2+ (<2.0) all it takes is a single property in application.properties:
spring.data.rest.basePath=/api
For 2.x, use
server.servlet.context-path=/api
Upvotes: 176
Reputation: 439
Try using a PathMatchConfigurer (Spring Boot 2.x):
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.addPathPrefix("api", HandlerTypePredicate.forAnnotation(RestController.class));
}
}
Upvotes: 43
Reputation: 4464
Per Spring Data REST docs, if using application.properties, use this property to set your base path:
spring.data.rest.basePath=/api
But note that Spring uses relaxed binding, so this variation can be used:
spring.data.rest.base-path=/api
... or this one if you prefer:
spring.data.rest.base_path=/api
If using application.yml, you would use colons for key separators:
spring:
data:
rest:
basePath: /api
(For reference, a related ticket was created in March 2018 to clarify the docs.)
Upvotes: -1
Reputation: 111
With spring-boot 2.x you can configure in application.properties:
spring.mvc.servlet.path=/api
Upvotes: 2
Reputation: 4313
For spring boot framework version 2.0.4.RELEASE+
. Add this line to application.properties
server.servlet.context-path=/api
Upvotes: 62
Reputation: 12751
This solution applies if:
RestController
but not Controller
.You are not using Spring Data Rest.
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Override
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
return new ApiAwareRequestMappingHandlerMapping();
}
private static class ApiAwareRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
private static final String API_PATH_PREFIX = "api";
@Override
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
Class<?> beanType = method.getDeclaringClass();
if (AnnotationUtils.findAnnotation(beanType, RestController.class) != null) {
PatternsRequestCondition apiPattern = new PatternsRequestCondition(API_PATH_PREFIX)
.combine(mapping.getPatternsCondition());
mapping = new RequestMappingInfo(mapping.getName(), apiPattern, mapping.getMethodsCondition(),
mapping.getParamsCondition(), mapping.getHeadersCondition(), mapping.getConsumesCondition(),
mapping.getProducesCondition(), mapping.getCustomCondition());
}
super.registerHandlerMethod(handler, method, mapping);
}
}
}
This is similar to the solution posted by mh-dev, but I think this is a little cleaner and this should be supported on any version of Spring Boot 1.4.0+, including 2.0.0+.
Upvotes: 0
Reputation: 193
For Boot 2.0.0+ this works for me: server.servlet.context-path = /api
Upvotes: 14
Reputation: 1789
I couldn't believe how complicate the answer to this seemingly simple question is. Here are some references:
There are many differnt things to consider:
server.context-path=/api
in application.properties
you can configure a prefix for everything.(Its server.context-path not server.contextPath !)spring.data.rest.base-path
in application.properties
. But plain @RestController
won't take this into account. According to the spring data rest documentation there is an annotation @BasePathAwareController
that you can use for that. But I do have problems in connection with Spring-security when I try to secure such a controller. It is not found anymore.Another workaround is a simple trick. You cannot prefix a static String in an annotation, but you can use expressions like this:
@RestController
public class PingController {
/**
* Simple is alive test
* @return <pre>{"Hello":"World"}</pre>
*/
@RequestMapping("${spring.data.rest.base-path}/_ping")
public String isAlive() {
return "{\"Hello\":\"World\"}";
}
}
Upvotes: 32
Reputation: 2508
You can create a base class with @RequestMapping("rest")
annotations and extend all you other classes with this base class.
@RequestMapping("rest")
public abstract class BaseController {}
Now all classes that extend this base class will be accessible at rest/**
.
Upvotes: 5
Reputation: 5533
Since this is the first google hit for the problem and I assume more people will search for this. There is a new option since Spring Boot '1.4.0'. It is now possible to define a custom RequestMappingHandlerMapping that allows to define a different path for classes annotated with @RestController
A different version with custom annotations that combines @RestController with @RequestMapping can be found at this blog post
@Configuration
public class WebConfig {
@Bean
public WebMvcRegistrationsAdapter webMvcRegistrationsHandlerMapping() {
return new WebMvcRegistrationsAdapter() {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new RequestMappingHandlerMapping() {
private final static String API_BASE_PATH = "api";
@Override
protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
Class<?> beanType = method.getDeclaringClass();
if (AnnotationUtils.findAnnotation(beanType, RestController.class) != null) {
PatternsRequestCondition apiPattern = new PatternsRequestCondition(API_BASE_PATH)
.combine(mapping.getPatternsCondition());
mapping = new RequestMappingInfo(mapping.getName(), apiPattern,
mapping.getMethodsCondition(), mapping.getParamsCondition(),
mapping.getHeadersCondition(), mapping.getConsumesCondition(),
mapping.getProducesCondition(), mapping.getCustomCondition());
}
super.registerHandlerMethod(handler, method, mapping);
}
};
}
};
}
}
Upvotes: 28
Reputation: 11026
I found a clean solution, which affects only rest controllers.
@SpringBootApplication
public class WebApp extends SpringBootServletInitializer {
@Autowired
private ApplicationContext context;
@Bean
public ServletRegistrationBean restApi() {
XmlWebApplicationContext applicationContext = new XmlWebApplicationContext();
applicationContext.setParent(context);
applicationContext.setConfigLocation("classpath:/META-INF/rest.xml");
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setApplicationContext(applicationContext);
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/rest/*");
servletRegistrationBean.setName("restApi");
return servletRegistrationBean;
}
static public void main(String[] args) throws Exception {
SpringApplication.run(WebApp.class,args);
}
}
Spring boot will register two dispatcher servlets - default dispatcherServlet
for controllers, and restApi
dispatcher for @RestControllers
defined in rest.xml
:
2016-06-07 09:06:16.205 INFO 17270 --- [ main] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'restApi' to [/rest/*]
2016-06-07 09:06:16.206 INFO 17270 --- [ main] o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
The example rest.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="org.example.web.rest"/>
<mvc:annotation-driven/>
<!-- Configure to plugin JSON as request and response in method handler -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonMessageConverter"/>
</list>
</property>
</bean>
<!-- Configure bean to convert JSON to POJO and vice versa -->
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</bean>
</beans>
But, you're not limited to:
XmlWebApplicationContext
, you may use any else context type available, ie. AnnotationConfigWebApplicationContext
, GenericWebApplicationContext
, GroovyWebApplicationContext
, ...jsonMessageConverter
, messageConverters
beans in rest context, they may be defined in parent contextUpvotes: 10
Reputation: 2037
A bit late but the same question brought me here before reaching the answer so I post it here. Create (if you still don't have it) an application.properties and add
server.contextPath=/api
So in the previous example if you have a RestController with @RequestMapping("/test")
you will access it like localhost:8080/api/test/{your_rest_method}
question source: how do i choose the url for my spring boot webapp
Upvotes: 105
Reputation: 1873
You can create a custom annotation for your controllers:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@RestController
@RequestMapping("/test")
public @interface MyRestController {
}
Use it instead of the usual @RestController on your controller classes and annotate methods with @RequestMapping.
Just tested - works in Spring 4.2!
Upvotes: 25