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.
Related
I'm trying to implement a REST endpoint between two non-web applications with all configuration in XML files.
I've created a simple controller with a method that only returns "OK", so I can run some tests using Postman.
Unfortunately, the endpoint is not being created.
I did some research and I found out that I need to add the "context" tag with the component-scan pointing to the controller package for it to work.
But my current implementation is not enough for it to work:
<context:component-scan base-package="com.app.REST"/>
My controller class is:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class TestController {
#RequestMapping("/test")
#ResponseBody
public String test(){
return "OK";
}
}
My question is: is there any way to create a REST endpoint without annotating the main class with #SpringBootApplication? If yes, what am I missing? Is it something in my XML file or somewhere else?
For enabling the MVC functionality you need to instruct spring to scan for your controllers
this is done via the <mvc:annotation-driven /> tag.
Also as the DispatcherServlet is taking care of your requests you need to add the correct configuration for it in your web.xml
....
<servlet>
<servlet-name>my-dispatcher-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:web-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher-servlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
LE:
<mvc:annotation-driven> is similar to <context:component-scan> they register all beans annotated with #Controller, #Component, #Service, #Repository and #Bean...
The main difference with mvc:annotation-driven is that it also creates some extra beans which take care of the endpoint registration in the dispatcherServlet (the HandlerMapping, HandlerAdapters and some default conversionServices needed to represent your data received in your controllers for example)
Say I have a RestController:
#RestController
#RequestMapping("path")
public class MyRestController {
#GetMapping("path")
public void myMethod(final MyObject object) throws Exception {
...
}
}
By default Spring uses getters and setters to set fields values for the object variable.
How can I specify to use direct field access?
I've tried with a custom Configuration class, but it doesn't work.
#Configuration
public class CustomWebMvcConfigurationSupport extends WebMvcConfigurationSupport {
#Override
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
final ConfigurableWebBindingInitializer initializer = super.getConfigurableWebBindingInitializer();
initializer.setDirectFieldAccess(true);
return initializer;
}
}
When working on projects you don't know very well keep an eye on every XML file. When working with a mixture of XML and Java configurations something may not work as expected (especially if you haven't read the Spring documentation carefully).
Basically if you've defined an XML configuration like:
<?xml version="1.0" encoding="UTF-8"?>
<beans ... [skipped]>
<description>Spring XML configuration</description>
<mvc:annotation-driven />
<context:component-scan base-package="com.my.package" />
</beans>
And you try customizing the web configuration extending WebMvcConfigurationSupport:
#Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
#Override
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
final ConfigurableWebBindingInitializer initializer = super.getConfigurableWebBindingInitializer();
initializer.setDirectFieldAccess(true);
return initializer;
}
}
You're basically dealing with two different instances, one created by Spring using the XML description, and one created by WebMvcConfiguration.
I solved using only the Java configuration.
So, by coding your web.xml file this way, you can delete entirely the XML configuration. You can see I specified I want an Annotation configuration for the contextClass parameter, and my configuration class for the contextConfigLocation parameter
<servlet>
<servlet-name>SpringDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.my.package.WebMvcConfiguration</param-value>
</init-param>
</servlet>
Remember to add the #ComponentScan annotation to the Java class:
#ComponentScan("com.my.package")
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 could use some help testing the authentication (using spring authentication) of my spring REST endpoints.
I have defined some endpoints requiring authentication using the following annotation #PreAuthorize("isAuthenticated()").
This seems to be working, because when I start a webserver and go to the URL I'm asked to authenticate, after which I get the proper results.
I run into trouble with my tests.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestContext.class)
#WebAppConfiguration
public class ControllerTest {
#Autowired
private WebApplicationContext context;
private MockMvc mvc;
#Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
#Test
public void testGetMethod() throws Exception {
mvc
.perform(get("/a-valid-url")
.accept(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isUnauthorized());
}
}
The TestContext class contains some autowired classes in the controller which are mocked, like this:
#Configuration
public class TestContext {
#Bean
public ClassToMock autowiredClass() {
return Mockito.mock(ClassToMock.class);
}
}
When run like this I get the following error:
java.lang.IllegalStateException: springSecurityFilterChain cannot be null. Ensure a Bean with the name springSecurityFilterChain implementing Filter is present or inject the Filter to be used.
The only solution I have found thus far to get everything running is by adding a springSecurityFilterChain bean in the TestContext class, like this:
#Bean
public Filter springSecurityFilterChain() {
return Mockito.mock(Filter.class);
}
However then I always get a Status = 200, even when I use an URL that is not defined in the controller.
If anyone could point me in the right direction it would be much appreciated!
Edit: Some of the configuration of the project.
web.xml
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The project has another project as a dependency which contains the TokenContext and AuthenticationStatelessContext configuration XML files.
TokenContext.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd" >
<context:component-scan base-package="com.example.auth.service" resource-pattern="TokenServiceImpl.class"/>
<context:component-scan base-package="com.example.auth.service" resource-pattern="ActorRolServiceImpl.class"/>
</beans>
The AuthenticationStatelessContext.xml defines the following spring beans: DefaultMethodSecurityExpressionHandler, PreAuthenticatedAuthenticationProvider and UserDetailsByNameServiceWrapper.
Update:
Created a class named TestContext2:
#Configuration
#ImportResource({
"classpath:**/AuthenticationStatelessContext.xml",
"classpath:**/TokenContext.xml"})
public class TestContext2 {
}
And added that class to the test
#ContextConfiguration(classes = {TestContext.class, TestContext2.class})
This because spring doesn't allow loading of classes and xml files at the same time in the #ContextConfiguration annotation.
When I try to run the test I still get the following error:
java.lang.IllegalStateException: springSecurityFilterChain cannot be null.
PS: The used springframework version is 4.1.3 and the spring-security version is 4.0.4.
It is wrong to mock the Filter interface to inject a springSecurityFilterChain bean.
What you want is to inject a filter chain with atleast one authentication filter, e.g. UsernamePasswordAuthenticationFilter
CasAuthenticationFilter
BasicAuthenticationFilter.
Read this spring security filter chain guide to understand which filters to inject for your purpose.
Right now mockito is setting a filter on the springSecurityFilterChain that allows all urls and does not provide the intended filtering behaviour.
The fix could be as easy as including a referrence to the correct app context along with TestContext on the Test class, depends on how you have defined the context for the rest of the application. I suspect a filter chain bean may be available for auto wiring as well.
Update:
Tell spring to load the TokenContext and AuthenticationStatelessContext here:
#ContextConfiguration(classes = TestContext.class)
Remove any code to define security filter chain bean in TestContext
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.