We are using Spring MCV and i am trying to use spring auto wiring to decouple my code. however, autowiring is not happening at all. Can you please suggest any issue in following code/ dispatcher
dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd"
xmlns:context="http://www.springframework.org/schema/context">
<context:component-scan base-package="com.eos.accounts" />
</beans>
User.java
package com.eos.accounts.data;
#Service
public class User {
.......
#Autowired
public UserMilesHelper userMilesHelper ;
.....
public static setUserPoints(User user){
user.setPoints(user.userMilesHelper.getUserPoints(user.getUserId()));
}
IUserMilesHelper.java
package com.eos.accounts.data;
public interface IUserMilesHelper {
public int getUserPoints(int userId);
}
UserMilesHelper.java
package com.eos.accounts.data;
import org.springframework.stereotype.Component;
//I have used #Repository or Qualifier etc, no avail
#Component
public class UserMilesHelper implements IUserMilesHelper {
#Override
public int getUserPoints(int userId) {
return 10;
}
}
Web.xml
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>50</load-on-startup>
</servlet>
your User.java class have to be annotated with #Component too or any of its children for ex.
#Controller
#Service
#RestController
Spring initiliaze component in his context by scanning packages and looking for class annoted with stereotypes (#Controller, #Service, #Repository....) or by explicit instantiation with manually adding a bean. If you use a the new it won't call Spring initilization mecanism and won't inject the dependancy.
I suppose your User class is not a singleton class so you should add #Scope("prototype") and use applicationContext.getBean(User.class) to instantiate with dependancy.
But to be honest i would instead refactor the code to avoid public members and static method to set variable and have class like that:
#Service
public class UserService{
private IUserMilesHelper userHelper;
#Autowired
public UserService(IUserMilesHelper userHelper){
this.userHelper = userHelper:
}
public setUserPoints(User user){
user.setPoints(userHelper.getUserPoints(user.getUserId()));
}
}
By default, the name of the dispatcher servlet is xxx-servlet.xml where xxx is the servlet name. Which means that the spring is looking for dispatcher-servlet.xml, which is not the name of your XML config.
Thus the context itself is not loaded for you. Change it and test.
Apart from that, make sure that you follow best practises. Autowire on interfaces rather than on concrete class. Quick link for you - Spring: Why do we autowire the interface and not the implemented class?
pleae change <context:component-scan base-package="com.eos.accounts" /> to
<context:component-scan base-package="com.eos.accounts.*" />
give it a try and let me know the result.
hope it helps.
I am plugging in Spring to existing Java EE web Application. I have following lines in my web.xml:
<listener>
<listener-class>com.MyContextListener</listener-class>
</listener>
And Following MyContextListener class?
public class MyContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
//...
}
}
What should I do to make MyContextListener be managed by Spring?
Edited:
My assumption is: Spring should create all servlets and all web app infrastructure so everything happened in contextInitialized method of MyContextListener should be somehow handled by Spring. How can I achieve, by implementing some interface I suppose. Correct me if I am wrong. Thanks!
Well,
We had a similar scenario of configuring an exiting Jersey web services app to use Spring for dependency injection. Our Jersey webapp had extended ContextLoaderListener as follow
public class XServletContextListener extends ContextLoaderListener {
...
#Override
public void contextInitialized(ServletContextEvent arg0) {
super.contextInitialized(arg0);
....
}
#Override
public void contextDestroyed(ServletContextEvent arg0) {
super.contextDestroyed(arg0);
....
}
}
where ContextLoaderListener is
import org.springframework.web.context.ContextLoaderListener;
We included the jersey-spring bridge with all spring dependencies including applicationContext.xml as follow
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="com.xxx.*" />
....
....
</beans>
And obviously needed to make sure that XServletContextListener is included in the web.xml as follow
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>com.xxx.**.XServletContextListener</listener-class>
</listener>
Followed by servlet and its init-param values and servlet mapping. You can obviously adopt annotation config in place of xml confib in which case you would need to use WebListener annotation.
We use a variety of annotations such as
#Component for objects
#Service for services
#Repository for DAOs
#Controller for controllers/resources
#ContextConfiguration for tests
Everything is loaded and autowired by Spring framework.
What should I do to make MyContextListener be managed by Spring?
It depends on which configuration way you are using. Anyway, you should tell directly Spring to use the class you have declared. That could be done by the following way:
#WebListener
public class MyContextListener implements ServletContextListener { ... }
A class marked with this annotation (the Servlet 3.0 specification, 8.1.4) must implement one of these interfaces
HttpSessionAttributeListener
HttpSessionListener
ServletContextAttributeListener
ServletContextListener (+)
ServletRequestAttributeListener
ServletRequestListener
HttpSessionIdListener
that it actually does.
Personally, I prefer a meta-annotation based approach which makes my configuration shorter and more concise.
Spring should create all servlets and all web app infrastructure so everything happened in contextInitialized method of MyContextListener should be somehow handled by Spring.
Yes, Spring will do it for you if you provide some information which could help it to register / configure / create / manage an instance.
The information may be either meta-information (a template that tells how to create an instance, like BeanDefinitions) or a completed instance itself (usually, it gets passed programmatically that, in turn, leads to writing a huge amount of code).
How can I achieve, by implementing some interface I suppose.
You are implementing an interface to make your listener a listener (a class that describes specific methods which will be called at some points of time). Spring, itself, is responsible for guaranteeing such calls at those points of time, placing an object in the existing web infrastructure before.
Either annotate the class with #WebListener or the method with #Bean
Annotate where you create a new instance of MyContextListener with #Bean if using Java Configs with Spring Boot.
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)
With Spring Boot 1.2+ (<2.0) all it takes is a single property in application.properties:
spring.data.rest.basePath=/api
ref link : https://docs.spring.io/spring-data/rest/docs/current/reference/html/#getting-started.changing-base-uri
For 2.x, use
server.servlet.context-path=/api
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
For spring boot framework version 2.0.4.RELEASE+. Add this line to application.properties
server.servlet.context-path=/api
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));
}
}
I couldn't believe how complicate the answer to this seemingly simple question is. Here are some references:
Spring JIRA Ticket
Another SO question
Yet another SO question
Very nice GitRepository that showcases the problem
There are many differnt things to consider:
By settingserver.context-path=/api in application.properties you can configure a prefix for everything.(Its server.context-path not server.contextPath !)
Spring Data controllers annotated with #RepositoryRestController that expose a repository as rest endpoint will use the environment variable 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\"}";
}
}
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);
}
};
}
};
}
}
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!
For Boot 2.0.0+ this works for me: server.servlet.context-path = /api
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:
use XmlWebApplicationContext, you may use any else context type available, ie. AnnotationConfigWebApplicationContext, GenericWebApplicationContext, GroovyWebApplicationContext, ...
define jsonMessageConverter, messageConverters beans in rest context, they may be defined in parent context
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 Property
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 Property
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 Property
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.
Conclusion:
So as the OP's question, I would suggest that he should use spring.mvc.servlet.path to change the context path.
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.
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/**.
With spring-boot 2.x you can configure in application.properties:
spring.mvc.servlet.path=/api
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
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
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!
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))
}
This solution applies if:
You want to prefix 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+.
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.)
worked server.contextPath=/path
I a new to Java Spring MVC web development. I am kind of confused by the 3 config files below. They are auto created by the STS webmvc project template.
What's the intended use of them?
Why do we need 3 config files rather than a single one?
Is there any special reason for their different locations?
root-context.xml is the Spring Root Application Context Configuration. It's optional. It's for configuring your non-web beans. You need it for Spring Security or OpenEntityManagerInView Filter though. It would be better to place it in meta-inf/spring.
servlet-context.xml is the Spring Web Application Context Configuration. It's for configuring your Spring beans in a web application. If you use root-context.xml, you should put your non-web beans in root-context.xml, and web beans in servlet-context.xml.
web.xml is for configuring your servlet container, such as Tomcat. You need this one too. It's for configuring servlet filters and the servlet. web.xml is loaded first, then optionally loads your root context, then loads your web context.
You can avoid using xml by using JavaConfig.
Create a file name "javax.servlet.ServletContainerInitializer" (without quotes) the file content will be fully qualified name of the class implementing this interface, put the file here /META-INF/services
You may implement ServletContainerInitializer and override the method like this
public class CourtServletContainerInitializer implements ServletContainerInitializer {
#Override
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(CourtConfiguration.class);
DispatcherServlet dispatcherServlet = new DispatcherServlet(applicationContext);
ServletRegistration.Dynamic registration = ctx.addServlet("court", dispatcherServlet);
registration.setLoadOnStartup(1);
registration.addMapping("/");
}
}
After this you do not need web.xml
Do remember if you are using maven to build your application mention this in pom.xml
<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
Before that you have to write a configuration class using #Configuration and #Bean annotations
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#ComponentScan(basePackages = "com.practice.learnspringmvc.*")
public class CourtConfiguration {
#Bean
public InternalResourceViewResolver internalResourceViewResolver() {
InternalResourceViewResolver internalResourceViewResolver = new InternalResourceViewResolver();
internalResourceViewResolver.setPrefix("/WEB-INF/views/");
internalResourceViewResolver.setSuffix(".jsp");
return internalResourceViewResolver;
}
}
This configuration class replaces your <bean></bean> initializers from servlet-context.xml
I have created a new Spring MVC 3 project using NetBean. But there is no option of adding a new controller in the IDE.
Well adding a Controller is as simple as adding a class annotated with
#Controller
And specifying the package to be scanned from applicationContext.xml which in turn is specified in the web.xml. Something like this:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/appServlet/applicationContext.xml
</param-value>
</context-param>
in web.xml
Then in /WEB-INF/spring/appServlet/applicationContext.xml :
<context:component-scan base-package="your.package" />
Of course you need the actual schema in your applicationContext.xml
xmlns:context="http://www.springframework.org/schema/context"
And under schema location:
http://www.springframework.org/schema/context/spring-context-3.0.xsd
And then a class :
package your.package
.....
#Controller
MyController{
.....
If you are using an annotation driven implementation of Spring you don't need to do anything special. Create a standard Java class inside the package that Spring is configured to scan. Then annotate the class with #Controller then create your method(s) and mappings using #RequestMapping.
In its simplest form a controller would be something like:
#Controller
public class MyClass {
#RequestMapping("/myUrlMapping.do")
public ModelAndView myMethod() {
return new ModelAndView("myView");
}
}
This assumes you already have Spring configured correctly.