This is something that I think should be very easy, but so far I have not been able to get it to work.
What I want to do is map my root path to a Spring MVC Controller. With a normal Servlet, I would just add a mapping for "/" in my web.xml, and it would pick it up quite well. But with Spring MVC, not so much.
I have tried many combinations, but none seem to work. I think the following one should work.
In web.xml:
<servlet-mapping>
<servlet-name>myDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
In my contextConfigLocation file:
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true"/>
<property name="mappings">
<util:map>
<entry key="/" value-ref="rootController"/>
</util:map>
</property>
</bean>
<bean id="rootController" class="my.package.RootController">
Then obviously, there is the case of the controller itself. I have no clue how to map the method to the actual root path. My attempt is something like this:
public class RootController extends MultiActionController {
#RequestMapping("/")
public ModelAndView display(HttpServletRequest request, HttpServletResponse response) throws Exception {
final Map<String, Object> model = new HashMap<String, Object>();
model.put("someVariable", "Hello, MVC world.");
return new ModelAndView("rootPage", model);
}
}
So let's say my application runs on http://localhost:8080/app/, I want that exact URL to execute the method display. I do not want to type anything after /app/. In fact, some things after /app/ are mapped to other controllers, and that all works fine (and they have to keep working).
What am I missing here? Why is this not simply working? If I use the same url-pattern to map to a plain Servlet instance, it works fine and I reach the doGet method, but with Spring MVC I seem to missing some particular black magic to get this to work.
Instead of mapping to / you can declare a welcome page in your web.xml file:
<welcome-file-list>
<welcome-file>welcome.htm</welcome-file>
</welcome-file-list>
so your / path will be processed as /welcome.htm and then if your controller is correctly mapped to /welcome.htm it will process / as if it was a /welcome.htm request, without making changes to other configuration.
I'd recommend getting rid of the SimpleUrlHandlerMapping and just doing the following:
#Controller
#RequestMapping("/")
public class RootController
{
#RequestMapping(method=RequestMethod.GET)
public ModelAndView display(...)
{
...
}
}
This should get the result you want. Also, add <mvc:annotation-driven/> to your servlet context with a <context:component-scan base-package="some.package.path.to.controller" /> to have Spring wire up that controller.
Otherwise, you can probably map the URL with the SimpleUrlHandlerMapping as so:
<property name="mappings">
<value>
/*=rootController
</value>
<property>
If done this way, you can keep the bean defined for rootController.
For Spring Webflow, the suggestion from Boris Treukhov to use web-file-list led to my discovering a hack that worked for weblogic. For example, if welcome is a flow.xml file, do the following: Change the url-pattern from \ to *.html in web.xml. Place a dummy(empty) file welcome.htm into the folder src\main\webapp\WEB-INF. In SimpleUrlHandlerMapping map the value /welcome.htm=flowController. Finally, complete the registry, flow-location path="welcome.xml". Refer to link: http://forum.spring.io/forum/spring-projects/web/50547-welcome-file-list-with-spring.
Related
I'm porting a large Spring 3.0 application to Spring 3.2 (yes, I know). The application combines XML and annotation configuration to define routes, for example:
servlet.xml:
<context:annotation-config/>
<context:component-scan base-package="foo.bar" />
...
<mvc:annotation-driven />
...
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
...
<property name="mappings">
<props>
<prop key="/booking/default.htm">booking.default</prop>
...
</props>
</property>
...
</bean>
<bean id="booking.default" class="foo.bar.BookingController">
...
</bean>
BookingController.java
#Controller
public class BookingController {
...
#RequestMapping(method = RequestMethod.GET)
public String handleRequest(...)
...
}
In Spring 3.0, the effect is to map GET /booking/default.htm to the handleRequest method of BookingController, however I have been unable to recreate this behaviour in Spring 3.2.
Spring 3.2, it seems, ignores the XML and views every method annotated with #RequestMapping(method = RequestMethod.GET) as the same, aborting on startup with java.lang.IllegalStateException: Ambiguous mapping found.
There are a large number of methods configured this way. Some of them have the #RequestMapping in a base library class that I can't change.
I can work around it by moving the url path from the XML configuration to the annotation, but I'd like to avoid that (for various reasons) and replicate the Spring 3.0 behaviour.
Is that possible? Searching for an answer has not been successful.
UPDATE:
TL;DR: This is not possible from Spring 3.1 onwards
Reading a SO "related questions" link:
SpringMVC 3.0 to 3.1 migration of ControllerClassNameHandlerMapping
Led me to:
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html
Which contains the excerpt:
New Support Classes for #RequestMapping methods in Spring MVC 3.1
...
There are also several things no longer possible:
Select a controller first with a SimpleUrlHandlerMapping or
BeanNameUrlHandlerMapping and then narrow the method based on
#RequestMapping annotations.
Which explains my problem.
I was trying to get spring form to work, I am using spring mvc only, When ever I try to add the spring form tag with a modelAttribute it fails and says that no ContextLoaderListener was found.
this is my JSP code for creating the form:
<sf:form method="POST" cssClass="form-horizontal" modelAttribute="companySearch">
and here is how i find my beans and my mvc is annotation-driven
<context:component-scan base-package="com.mubasherjson.controllers" />
<context:annotation-config />
<bean id="companySearch" class="com.mubasherjson.models.CompanySearch" />
<mvc:annotation-driven />
and this is my code of the post method
#RequestMapping(method = RequestMethod.POST)
public String showResultPage(Model model){
model.addAttribute(new CompanySearch());
return "result";
}
I also tried it with #ModelAttribute annotation but still nothing works, I also added the action attribute to the form but still no luck, my root path of this method is "/"
why must I create a ContextLoaderListener here ? basicly the CompanySearch is a Model and its a simple POJO, If I remove the form or comment it everything works fine. what seems to be the problem here, I've checked various questions here but still don't get it in my case
Bootstrap listener to start up Spring's root WebApplicationContext.
Simply delegates to ContextLoader.
Doc
It is a servlet listener called by container. Which creates application context and loads the XML bean definition files. It means everything starts with it and have to have it.
You can define it by
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
ContextLoaderListener Vs DispatcherServlet
In Spring MVC, there are two context. One is the application context or global context which is booted up by ContextLoaderListener. It takes all the configuration file mentioned in contextConfigLocation parameter.
Now if you are are using Spring MVC also than Dispatcher servlet is required, which boots up another container which is also known as web application container. This container takes the global container as a parent.
If you are using Spring in the backend only, then the global context is good enough. However if you are using Spring MVC also for front end than you need Dispatcher Servlet also.
(Copied from http://www.coderanch.com/t/516563/Spring/DispatcherServlet-ContextLoaderListener, I am too lazy and there is already lots of stuff out there)
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{
}
I am integrating Spring MVC into an existing project I have been working on. By integrating, I mean I am rewriting the project using Spring, and using much of my old code. I have already setup the environment and have began working on it. I will refer to this project as ProjectX.
I have already setup and configured my ProjectX-servlet.xml that holds the view-resolver bean, and the controller beans, etc. I want to set up an applicationContext.xml file that I can place all my DAO beans in such as ...
<bean id="MemberDAO" class="com.xxx.xxx.MemberDAO"/>
<bean id="ProductDAO" class="com.xxx.xxx.ProductDAO"/>
I want these values to be in the applicationContext.xml so that in my controllers I can do the following.
public SomeController extends SimpleFormController{
private MemberDAO memberDao;
private ProductDAO productDao;
...getter/setter methods for memberDao;
...getter/setter methods for productDao;
and the values will be available(injecting them into the controllers)
I have configured the controllers in the ProjectX-servlet.xml like the following definition.
<bean name="/SomeController.thm" class="com.xxx.xxx.controllers.SomeController">
<property name="memberDao" ref="MemberDAO"/>
<property name="productDao" ref="ProductDAO"/>
</bean>
I believe I need to configure something such as the following in my web.xml so that it knows to load the application context.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
My question is, what do I have to do following creating an applicationContext.xml file, to be able to do what I showed above and inject beans such as the ProductDAO and MemberDAO into my controlellers which are configured in the ProjectX-servlet.xml
I have been using Spring MVC for a contract for a couple months and am comfortable with how to use it, but I am new to configuring it on my own, for my own use, so I would appreciate if any advice or answers were explained a little easier for me.
Thank you
By convention, the name you give to your instance of DispatcherServlet will be associated with {name}-servlet.xml. This context will be a child to applicationContext.xml as you described, meaning it will have access to beans in applicationContext.xml.
Try the following in your web.xml:
<servlet>
<servlet-name>ProjectX</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ProjectX</servlet-name>
<url-pattern>/projectx/*</url-pattern>
</servlet-mapping>
You don't have to do anything special. You can continue injecting beans defined in applicationcontext.xml into the beans defined in xx-servlet.xml as if all of them are declared in same file. Do remember to use the attribute ref instead of ref-local as below.
<bean id="mycontroller" class="x.y.z.CustomerController>
<property name="service" ref="myservice"/><!--myservice defined in applicationcontext-->
</bean>
Unless I'm misunderstanding, the solution you're looking for is to use an import statement in your applicationContext.xml. This effectively combines the two XML files into a single context, allowing you to reference beans in either.
Ex:
<import resource="classpath:foo/bar/ProjectX-servlet.xml" />
You may or may not want to use "classpath." See section 3.2.2.1 in the Spring docs for more details.
Is it possible to have one controller to handle multiple forms in spring?
For example, i have 3 steps registration that map with "/register" url. Is it possible to have only one RegisterController that can handle all registration's steps form submit?
That depends on the style of controllers you're using. If you use Spring 2.0-style form controllers (e.g. a subclass of SimpleFormController or AbstractFormController), then you might have some difficulty. If, however, you're using Spring 2.5-style annotated #Controllers, then these are very flexible, and you should be able to handle pretty much any cmplexity you desire in one controller class.
Like skaffman said you can use #Controller that are very flexible. But if you're writting a Wizard, you should take a look at AbstractWizardFormController. It handles all steps and validation of a wizard. It also keeps the same backing object for each form submission. When your wizard is on the final action, you can take this object and update it at the database.
You can find an exemple at :
http://www.cs.bham.ac.uk/~aps/syllabi/2004_2005/issws/h04/spring.html#AbstractWizardFormController
you can use multi action controller .In Spring Single Controller Handel Multipal Method by method name resolver
<bean id="id" class="controller class"> <property name="name"><ref bean="service Name"/></property > <property
name="methodNameResolver"><ref bean="name of Resolver"/></property>
</bean>
------------------------------------------------------------------------ <bean id="name of Resolver"
class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
<property name="mappings"> <props> <prop
key="/url.com">MethodName</prop> </props> </property> </bean> This can
be Help you use single controller
------------------------------------------------------------------------
https://jira.springsource.org/browse/SPR-5534
Question
For example, i have 3 steps registration that map with "/register" url. Is it possible to have only one RegisterController that can handle all registration's steps form submit?
Proposed Solution:
Spring 3 - Spring-mvc controller using servlet mapping to your controller. Using the mapping in your url request you will always go to the same controller.
You can create a servlet & servlet mapping that maps to your controller through the spring DispatcherServlet.
Create a servlet & servlet mapping to handle your requests.
Web.XML
<servlet>
<description>
</description>
<display-name>TestServ</display-name>
<servlet-name>main</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>/test/*</url-pattern>
</servlet-mapping>
Create a spring config file associated to the servlet.
In this case since the name of my servlet is test, it will be test-servlet.xml file that goes into your WEB-INF folder at the root.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean name="/registration/*" class="register.ResgisterController"/>
Create your controller class to map your requests.
package registration;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import registration.User;
#Controller
public final class RegistrationController {
public RosterController() {
}
//Spring lets you You can access your spring mvc model from the controller automatically
#RequestMapping
public void list(Model model) {
//do something
}
//Extract a registration id from the request and you can use in your model
#RequestMapping
public void member(#RequestParam("registrationId") Integer id, Model model) {
//do something
}
}
you will have to use 'MultiActionController', but there are some complication in validation porting if you will use this controller.
Solution of similar problem is given # http://www.scribd.com/doc/20156448/Multi-Action-Controller-With-Validation
you can use Spring webFlow and annotate your controller as #controller