I am developing a web app using the Spring MVC framework (v3).
Currently I have several controller classes defined - I have created them by extending the MultiActionController and then in my web mvc XML config defined the beans and the URL mappings:
QuestionController.java:
public class QuestionController extends MultiActionController implements InitializingBean
{
webmvc-config.XML
<bean id="questionController" class="com.tmm.enterprise.microblog.controller.QuestionController"></bean>
...
<bean id="fullHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true" />
<property name="mappings">
<props>
<prop key="/question/**">questionController</prop>
</props>
</property>
</bean>
This works fine, I define methods in my controller matching the URLs being called and everything works correctly (for example, I have a list(..) method, that gets correctly executed when I browse to /question/list).
However, for this particular controller I want to make use of the #PathVariable option in Spring to allow for variable URLs (e.g. i want a details(..) method, that when I call /question/detail/9999 - where 9999 is a question ID the method is executed). I have tried to use this as follows:
QuestionController.java:
#RequestMapping("/detail/{questionId}")
public ModelAndView detail(#PathVariable("questionId") long questionId, HttpServletRequest request, HttpServletResponse response) throws Exception{
However, I get an error when I run the above and get:
Could not find #PathVariable [questionId] in #RequestMapping
Has anyone come across this before? Is it ok to mix RequestMapping annotations with the existing XML configured URL mapping?
This is the comment from DefaultAnnotationHandlerMapping class, If i am reading the comment right, If you add #RequestMapping at the top of your QuestionController.java, It might resolve your problem
Annotated controllers are usually marked with the {#link Controller} stereotype
at the type level. This is not strictly necessary when {#link RequestMapping} is
applied at the type level (since such a handler usually implements the
{#link org.springframework.web.servlet.mvc.Controller} interface). However,
{#link Controller} is required for detecting {#link RequestMapping} annotations
at the method level if {#link RequestMapping} is not present at the type level.
EDIT
You can do some thing like this, move the /question part of the uri to the top and leave the
detail part at the method level
#RequestMapping("/question")
public class QuestionController
{
#RequestMapping("/detail/{questionId}")
public ModelAndView detail(#PathVariable("questionId") long questionId, HttpServletRequest request, HttpServletResponse response) throws Exception{
}
Related
I am unable to configure HttpServletRequest in application context in my spring environment.
below is the code I tried:
<bean id="request" class="javax.servlet.http.HttpServletRequest">
</bean>
<bean id="rwEloquaControllerService" class="com.rightwave.eloqua.RWEloquaControllerService">
<property name="request" ref="request" />
</bean>
RWEloquaControllerService class code for getter setter:
HttpServletRequest request;
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
But when I start my server, exceptions occurred due to application context error. can any one tell me how to configure HttpServletRequest object in application context.
Let's talk about some basic concepts first.
In my Knowledge, it's not possible to instantiate an interface in application context. How do you new an interface without give it real implementation? It's impossible.
You write bean in application context so that Spring can instantiate them. However, the request you want is generated by servlet container. It's not created by Spring.
If you want to inject request in your controller, just add the following code in your controller. Spring doesn't create the request, Spring just get it from servlet container then inject it into the controller.
private #Autowired HttpServletRequest request;
Based on your comment:
Can I not instantiate an interface in application context. Basically, I need request object to get context, then springContext and then get a bean. So at first point I need request
Simply make you controller implement org.springframework.context.ApplicationContextAware. You will have to add the public void setApplicationContext(ApplicationContext applicationContext) throws BeansException method, which you can use to set the provided applicationContext to a member variable.
You can then use it to query the context for spring-managed beans.
Note: the setApplicationContext method will be invoked by Spring after your controller has been created but before afterPropertiesSet is invoked (if you implement InitializingBean).
I have some ServerResources in my application which are identified by the #Service(name) annotation. The methods are annotated with the #Get and #Post restlet annotations.
Everything worked fine until recently I wanted to add another ServerResource which has to serve a URL pattern with different parameters and request methods, thus I tried to use #RequestMapping annotation on the methods like:
#Service
public class MyResource extends ServerResource {
#RequestMapping(value="/pathToMyResource/{parameter1}", method=RequestMethod.GET)
public Representation getResponseForGetRequest(Representation entity) {
...
}
//and for the other method:
#RequestMapping(value="/pathToMyResource/{parameter1}/{parameter2}", method=RequestMethod.POST)
public Representation getResponseForPostRequest(Representation entity) {
...
}
...
}
However my resource is not properly registered with org.restlet.ext.spring.SpringBeanRouter as it is not found when this URL is requested.
The only way I figured out multiple paths working for one resource is via XML configuration:
<bean name="/pathToMyResource/{parameter1}"
id="myGetResource"
class="com.mycompany.resource.MyResource"
autowire="byName" scope="prototype">
</bean>
<bean name="/pathToMyResource/{parameter1}/{parameter2}"
id="myPostResource"
class="com.mycompany.resource.MyResource"
autowire="byName" scope="prototype">
</bean>
and using Restlet annotation for methods:
public class MyResource extends ServerResource {
#Get
public Representation getResponseForGetRequest(Representation entity) {
...
}
//and for the other method:
#Post
public Representation getResponseForPostRequest(Representation entity) {
...
}
...
}
Do you know how the #RequestMapping annotation works with Restlet? I would like to avoid XML configuration completely and trying to find a way to get it working with annotations...
As I mentioned I have no problem with resources mapped only to one path like:
#Service("/pathToMyResource/{parameter1}")
public class MyResource extends ServerResource {
...
}
This is working fine... only multiple paths mapping causes problems.
Thanks for any help!
from what I see, we don't support annotations taken from Spring framework.
If you want to remove any xml configuration, you can follow two ways:
use classic Restlet code: define an Application, implement the createInboundRoot methods in order to define the routing aspects, use annotated ServerResource. (see this page for a simple example http://restlet.com/learn/guide/2.2/editions/jse/, or this one for a complete code http://restlet.com/learn/guide/2.2/introduction/first-steps/first-application,
use the JaxRs extension in order to rely on JaxRs annotations (see http://restlet.com/learn/guide/2.2/extensions/jaxrs)
I have annotated the controller with a requestmapping. I also annotated the method with another requestmapping, however it doesn't seemed to get mapped. I am using Spring 2.5.
#RequestMapping("/animals")
#Controller
public class AnimalController {
#RequestMapping(value="/tiger")
public void doSomething(...) {..}
}
Shouldn't this give me the path /animals/tiger? I have these in the context config:
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
I only get a exception saying that it isn't mapped.
You will need the #Controller annotation above the class definition. But in addition to that you need to specify the type of Request. e.g. is is POST or GET. An example is shown below:
#RequestMapping(value = "tiger", method = RequestMethod.GET)
Also, note that a forward slash is not needed before the String 'tiger'. This is automatic.
I just started working with spring and set up a simple spring project in NetBeans. By default it doesn't seem to use annotations.
In one of my controllers I'd like to handle different clicks on the form. I have looked at some solutions and it seems like adding a parameter check could work:
#RequestMapping(params = "someAction")
public ModelAndView doSomeAction() {
However it looks like all of the requests are going to:
public class SetupController implements Controller {
#Override
public org.springframework.web.servlet.ModelAndView handleRequest(
HttpServletRequest hsr, HttpServletResponse hsr1) throws Exception {
Is there a way I can achieve the same effect without RequestMapping annotation?
It seams that you mixed the old (implements Controller) style with the new one annotation based style.
You can't (or at least should not) mix them, at least not for one class.
If you use Spring 3.x then I strongly recommend to use the Annotation based style.
#Controller
#RequestMapping("/whatever")
public class DemoController() {
#RequestMapping(params="x");
public ModelAndView doX() {
}
#RequestMapping(params="y");
public ModelAndView doY() {
}
}
To enable the Annotation Based style, you need at least this configuration settings:
<!-- Turns on support for mapping requests to Spring MVC #Controller methods
Also registers default Formatters and Validators for use across all
#Controllers -->
<mvc:annotation-driven conversion-service="applicationConversionService" />
Typically, when you declare different "<authentication-provider>" for your application (webapp in my case), Spring Security takes care of invoking providers one after another, incase of failure. So, say I have DatabaseAuthenticationProvider and LDAPAuthenticationProvider with DatabaseAuthenticationProvider declared first in the config file, at runtime, DatabaseAuthenticationProvider is invoked first and if authentication fails, LDAPAuthentication is tried. This is cool - However, what I need is a runtime switch.
I would like to have an option of chosing between these two approaches (database based authentication / ldap based authentication) and somehow swith the implementation based on thsi global setting.
How do I do it? Is it even possible with Spring-Security?
I will leave how to inject your own custom authentication provider to the other myriad of examples from Googleland and here on StackOverflow. It looks like it has to do with marking a particular bean with the xml. But hopefully I can fill in some of the other details for you.
So you've defined the class somewhat like above and I'll add more of the details that you'll need for Spring (i.e. merge the stuff from above as well.
public class SwitchingAuthenticationProvider implements AuthenticationProvider
{
....
public List<AuthenticationProvider> getProviders() { return delegateList; }
public void setProviders(List<AuthenticationProvider> providers) {
this.delegateList = providers;
}
....
}
This will allow you to inject a host of providers using spring:
<bean id="customAuthProvider1" class=".....CustomProvider1"> ... </bean>
<bean id="customAuthProvider2" class=".....CustomProvider2"> ... </bean>
...
<bean id="customAuthProviderX" class=".....CustomProviderX"> ... </bean>
<bean id="authenticationProvider" class="....SwitchingAuthenticationProvider">
<security:custom-authentication-provider/>
<!-- using property injection (get/setProviders) in the bean class -->
<property name="providers">
<list>
<ref local="customAuthProvider1"/> <!-- Ref of 1st authenticator -->
<ref local="customAuthProvider2"/> <!-- Ref of 2nd authenticator -->
...
<ref local="customAuthProviderX"/> <!-- and so on for more -->
</list>
</property>
</bean>
In the end how you populate the providers could be any means of getting the delegator a collection of providers. How they map up to which one to use is up to you. The collection could be a named mapped, based on the current state of the delegator. It could be a list of more than one to try. It could be two properties, "get/setPrimary" and "get/setSecondary" for fail-over like functionality. Once you have the delegator injected the possibilities are up to you.
Let me know if this isn't answering your question.
How about writing a delegating AuthenticationProvider that knows how to access your runtime switch and the actual instances of Database/LDAP AuthenticationProvider.
I'm thinking of something like:
public class SwitchingAuthenticationProvider implements AuthenticationProvider
{
private List<AuthenticationProvider> delegateList;
private int selectedProvider;
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException
{
AuthenticationProvider delegateTo = delegateList.get(selectedProvider);
return delegateTo.authenticate(authentication);
}
....
}