Spring IDE Basics
Spring IDE is an eclipse plug-in that helps in developing Spring Application. First we will see how to install the Spring IDE and later we will create our first Spring project using it. I am using Eclipse 3.4.1 version to demonstrate this.
To install Spring IDE, Go to Help -> Software Updates.
Click the "Add Site" button and enter "http://springide.org/updatesite" in the Add Site popup.
Select all the Spring IDE features and click Install.
Once the installation is complete you are done. Now let's see how to create the hello world example using the Spring IDE.
First create a Spring project, go to File -> New -> Project.
Select Spring Project and click Next.
Enter the project name and click Finish.
The "S" in the upper right corner indictes it is a Spring Project.
Right click the src package and create a new package "opensourzesupport". Create the following HelloWorld class
package com.opensourzesupport; public class HelloWorld { private String message; public void setMessage(String message) { this.message = message; } public void display() { System.out.println(message); } }The HelloWorld class has a message property and its value is set using the setMessage() method. This is called setter injection. Instead of directly hard coding the message, we inject it through an external configuration file. The design pattern used here is called Dependency Injection design pattern and it is explained in detail in the next example. (Spring Dependency Injection)The HelloWorld class also has a display() method to display the message.
Now we have created the HelloWorld bean class, the next step is to add an entry for this in the bean configuration file. The bean configuration file is used to configure the beans in the Spring IoC container. To create a new bean configuration file right click the src folder and select New -> Spring Bean Configuration File.
Enter the bean name and click Next.
Select the beans option and click Finish.
Now the Spring configuration file is created. Add the following code to created an entry for the HelloWorld bean class.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" 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.xsd"> <bean id="helloWorld" class="com.opensourzesupport.HelloWorld"> <property name="message" value="Hello World!"></property> </bean> </beans>The id attribute of the bean element is used to give a logical name to the bean and the class attribute specifies the fully qualified class name of the bean. The property element within the bean element is used to set the property value. Here we set the message property to "Hello World!".
If you want to display a differnt message, the only change you need to is to change the value of the message in the bean configuration file. This is one of the main benefits of using the Dependency Injection design pattern, this makes the code loosely coupled.
To dispaly the message, create the following HelloWorldApp class.
package com.opensourzesupport; import org.springframework.context.ApplicationContext; import org.springframework.context.support. ClassPathXmlApplicationContext; public class HelloWorldApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld"); helloWorld.display(); } }First we instantiate the Spring IoC container with the bean configuration file beans.xml. We use the getBean() method to retrive the helloWorld bean from the application context and call the display() method to display the message in the console.
Add the following jar files to the classpath.
antlr-runtime-3.0 commons-logging-1.0.4 org.springframework.asm-3.0.0.M3 org.springframework.beans-3.0.0.M3 org.springframework.context-3.0.0.M3 org.springframework.context.support-3.0.0.M3 org.springframework.core-3.0.0.M3 org.springframework.expression-3.0.0.M3To execute the example run the HelloWorldApp file. The "Hello World!" message gets printed on the console.
Spring IoC
In Spring, the Inversion of Control (IoC) principle is implemented using the Dependency Injection (DI) design pattern. Let's understand dependency injection with the help of an example. First we will see a java version of the example and later we will add spring functionalities to it. As far as the example go, its pretty simple. The QuizMater interface exposes the popQuestion() method. To keep things simple, our QuizMaster will generate only one question.QuizMaster.java
----------------------
package
com.opensourzesupport;
public
interface
QuizMaster {
public
String popQuestion();
}
The StrutsQuizMaster and the SpringQuizMaster class implements QuizMaster interface and they generate questions related to struts and spring respectively.
StrutsQuizMaster.java
----------------------
package
com.
opensourzesupport
;
public
class
StrutsQuizMaster
implements
QuizMaster {
@Override
public
String popQuestion() {
return
"Are you new to Struts?"
;
}
}
SpringQuizMaster.java
.
----------------------
package
com.opensourzesupport;
public
class
SpringQuizMaster
implements
QuizMaster {
@Override
public
String popQuestion() {
return
"Are you new to Spring?"
;
}
}
We have a QuizMasterService class that displays the question to the user. The QuizMasterService class holds reference to the QuizMaster.
QuizMasterService.java
-----------------------
package
com.opensourzesupport;
public
class
QuizMasterService {
private
QuizMaster quizMaster =
new
SpringQuizMaster();
public
void
askQuestion()
{
System.out.println(quizMaster.popQuestion());
}
}
Finally we create the QuizProgram class to conduct quiz.
QuizProgram.java
----------------
package
com.
opensourzesupport
;
public
class
QuizProgram {
public
static
void
main(String[] args) {
QuizMasterService quizMasterService =
new
QuizMasterService();
quizMasterService.askQuestion();
}
}
As you can see it is pretty simple, here we create an instance of the QuizMasterService class and call the askQuestion() method. When you run the program as expected "Are you new to Spring?" gets printed in the console.
Let's have a look at the class diagram of this example. The green arrows indicate generalization and the blue arrows indicates association.
As you can see this architecture is tightly coupled. We create an instance of the QuizMaster in the QuizMasterService class in the following way.
To make our quiz master Struts genius we need to make modifications to the QuizMasterService class like this.
So it is tightly coupled. Now lets see how we can avoid this by using the Dependency Injection design pattern. The Spring framework provides prowerful container to manage the components. The container is based on the Inversion of Control (IoC) principle and can be implemented by using the Dependency Injection (DI) design pattern. Here the component only needs to choose a way to accept the resources and the container will deliver the resource to the components.
In this example instead of we, directly creating an object of the QuizMaster bean in the QuizMasterService class, we make use of the container to do this job for us. Instead of hard coding any values we will allow the container to inject the required dependancies.
We can inject the dependancies using the setter or constructor injection. Here we will see how we can do this using the setter injection.
The value for the QuizMaster will be set using the setQuizMaster() method. The QuizMaster object is never instantiated in the QuizMasterService class, but still we access it. Usually this will throw a NullPointerException, but here the container will instantiate the object for us, so it works fine.
After making all the changes, the class diagram of the example look like this.
The container comes into picture and it helps in injecting the dependancies.
The bean configuration is done in the beans.xml file.
We define each bean using the bean tag. The id attribute of the bean tag gives a logical name to the bean and the class attribute represents the actual bean class. The property tag is used to refer the property of the bean. To inject a bean using the setter injection you need to use the ref tag.
Here a reference of SpringQuizMaster is injected to the QuizMaster bean. When we execute this example, "Are you new to Spring?" gets printed in the console.
To make our QuizMaster ask questions related to Struts, the only change we need to do is, to change the bean reference in the ref tag.
In this way the Dependency Injection helps in reducing the coupling between the components.
To execute this example add the following jar files to the classpath.
The User bean class has three attributes viz. name, age and country. All the three attributes are set using the setter injection. The toString() method of the User bean class is overridden to display the user object.
Here the beans.xml file is used to do spring bean configuration. The following code shows how to set a property value thru setter injection.
The id attribute of the bean element is used to specify the bean name and the class attribute is used to specify the fully qualified class name of the bean. The property element with in the bean element is used to inject property value via setter injection. The name attribute of the property element represents the bean attribute and the value attribute specifies the corresponding property value.
Here we set "Prasobh", "26" and "India" for the User bean properties name, age and country respectively. The following Main class is used to get the User bean from the Spring IoC container and dispaly its value it to the user.
On executing the Main class the following message gets displayed on the console.
The User bean class has three attributes viz. name, age and country. All the three attributes are set thru constructor injection. The toString() method of the User bean class is overridden to display the user object.
Here the beans.xml file is used to do spring bean configuration. The following code shows how to set a property value thru constructor injection.
The constructor-arg element within the bean element is used to set the property value thru constructor injection. Since there is only one constructor in the User bean class, this code will work fine. When there is more than one constructor with the same number of arguments, then the following ambiguities will occur. Conside the following code.
The bean configuration file.
Now which constructor do you think will be invoked? The first one with the int and the String argument, right? But for your surprise it will call the second constructor with both String arguments. Though we know the first argument is of type int and the second argument is of type String, spring interprets both as String arguments. To avoid this confusion you need to specify the type attribute of the constructor-arg element. Now with the following bean configuration, the first constructor will be invoked.
Now consider this case. We have the following constructors in the User bean class.
The bean configuration file.
Now which constructor do you think will be called? The second constructor, right? But again for your surprise the first constructor will be called, this is because the order in which the arguments appear in the bean configuration file will not be considered while invoking the constructor. To solve this problem you can use the index attribute to specify the constructor argument index.
Here is the bean configuration file after adding the index attribute.
Now as expected, the second constructor will be invoked.
The figure below shows the flow of request in the Spring MVC Framework.
When a request is sent to the Spring MVC Framework the following sequence of events happen.
Go to File -> New -> Dynamic Web Project, to create a web project.
Enter the project name and click the Finish button.
Right click the project folder, and select Spring Tools -> Add Spring Project Nature, to add Spring capabilities to the web project. This feature will be available once you install the Spring IDE.
Create a new package com.opensourzesupport inside the src directory. The Spring controller class extends org.springframework.web.servlet.mvc.AbstractController class. To create a new controller class right click the src directory and create a new java class, enter the controller class name and super class name and the Finish button.
Copy the following code inside the HelloWorldController class.
The HelloWorldController class has a message property that is set thru the setter injection. The HelloWorldController class should override the handleRequestInternal() method to process the request. After processing the request the handleRequestInternal() method returns a ModelAndView object back to the DispatcherServlet.
The DispatcherSevlet, as the name indicates, is a single servlet that manages the entire request-handling process. When a request is sent to the DispatcherServlet it delegates the job by invoking the appropriate controllers to process the request. Like any other servlet the DispatcherServlet need to be configured in the web deployment descriptor as shown.
Here the servlet name is dispatcher. By default the DispatcherServlet will look for a file name dispatcher-servlet.xml to load the Spring MVC configuration. This file name is formed by concatenating the servlet name ("dispatcher") with "-servlet.xml". Here we user the the url-pattern as ".htm" inorder to hide the implementations technology to the users.
The redirect.jsp will be invoked first when we execute the Spring web application. This is the only jsp file outside the WEB-INF directory and it is here to provide a redirect to the DispatcherServlet. All the other views should be stored under the WEB-INF directory so that they can be invoked only through the controller process.
To create a bean configuration file right click the WebContent folder and select New -> Other. The following dialog box appears.
Select the Spring Bean Configuration file and click Next.
Enter the file name as "dispatcher-servlet.xml" and click the Finish button.
Now the Spring bean configuration file is created, we need to configure the Controller and the ViewResolver classes. The following code shows how to do this.
First let's understand how to configure the controller.
Here the name attribute of the bean element indicates the URL pattern to map the request. Since the id attribute can't contain special characters like "/" , we specify the URL pattern using the name attribute of the bean element. By default the DispatcherServlet uses the BeanNameUrlHandlerMapping to map the incoming request. The BeanNameUrlHandlerMapping uses the bean name as the URL pattern. Since BeanNameUrlHandlerMapping is used by default, you need not do any seperate configuration for this.
We set the message attribute of the HelloWorldController class thru setter injection. The HelloWorldController class is configured just like an another JavaBean class in the Spring application context, so like any other JavaBean we can set values to it through Dependency Injection(DI).
The redirect.jsp will redirect the request to the DispatcherServlet, which inturn consults with the BeanNameUrlHandlerMapping and invokes the HelloWorldController. The handleRequestInternal() method in the HelloWorldController class will be invoked. Here we return the message property under the name welcomeMessage and the view name welcomePage to the DispatcherServlet. As of now we only know the view name, and to find the actual view to invoke we need a ViewResolver.
The ViewResolver is configured using the following code.
Here the InternalResourceViewResolver is used to resolve the view name to the actual view. The prefix value + view name + suffix value will give the actual view location. Here the actual view location is /WEB-INF/jsp/welcomePage.jsp
The following library files are needed to run the example.
To execute the example run the redirect.jsp file.
I am using Spring 3.0 so you see the SuppressWarnings annotation there. Here we extend the UserController from SimpleFormController, this makes the controller class capable of handling forms. Usually a form will be associated with a particular domain object, in our case it is the User class. In Spring this domain object is called command object by default. To refer the command object in the jsp page you need to set the command class using the setCommandClass() method in the constructor. Let say the User class has a name property, and to refer this in the jsp page you will use "command.name". You can also change this name by using the setCommandName() method. Here we set the name to user, so to access the user name in the jsp page we use "user.name".
You need to have a method to handle the form when the form is submitted, here the onSubmit() method is used for this purpose. The onSubmit() method has access to the command object, we first typecast the command object to User (our domain object) and then to register the user we call the add() method of the service class and finally return the ModelandView object.
All the forms field values will be submitted as Strings to the form controller. Spring has several pre registered property editors to convert the String values to common data types. Incase you have a custom data type you need to create custom property editors to handle them.
The User domain object has the following attributes.
Our User Service interface.
Our User Service Implementation class.
Let's now create the user registration form using the Spring form tags. To use the form tags you need to first import the Spring's form tag library.
Here the path attribute is used to bind the form fields to the domain object. Here we use the HTTP POST method to submit the form. Inorder to bind the form fields to the domain object successfully the command object should be set to the same name in the jsp page and the controller class. To set the command object name in the jsp page, use the commandName attribute of the form tag.
The web.xml file.
Next create the Spring Bean Configuration file.
As you can see, we use "p" namespace here. The "p" namespace is simple and easy to use. Using "p" namespace the properties can be supplied using attributes, rather than elements.
For injecting the simple types we use property name in the "p" namespace and for injecting references we add "-ref" suffix to it. For example we use p:formView for injecting the form view property and p:userService-ref for injecting the user service.
During the HTTP GET request the formView will be rendered. When the form is submitted (during the HTTP POST request) the onSubmit() method of the UserController class will be called, on successful execution of the method the successView will be rendered. Incase of any type conversion errors or validation errors the formView will be automatically displayed the user.
Run the example by executing the redirect.jsp file. The redirect.jsp file, redirect the request to "userRegistration.htm".
The following user registration page will be displayed.
Fill the form and submit it.
The onSubmit() method of the UserController class will be called and the control will be transfered to the view "userSuccess". We use InternalResourceViewResolver here, so the userSuccess.jsp page will be dispalyed. In the userSuccess.jsp page we dispaly all the user details using the jstl tags.
The userSuccess.jsp page.
web.xml
Let's have a look at the class diagram of this example. The green arrows indicate generalization and the blue arrows indicates association.
As you can see this architecture is tightly coupled. We create an instance of the QuizMaster in the QuizMasterService class in the following way.
1.
private
QuizMaster quizMaster =
new
SpringQuizMaster();
1.
private
QuizMaster quizMaster =
new
StrutsQuizMaster();
In this example instead of we, directly creating an object of the QuizMaster bean in the QuizMasterService class, we make use of the container to do this job for us. Instead of hard coding any values we will allow the container to inject the required dependancies.
We can inject the dependancies using the setter or constructor injection. Here we will see how we can do this using the setter injection.
QuizMasterService.java
.
-----------------------
package
com.opensourzesupport;
public
class
QuizMasterService {
QuizMaster quizMaster;
public
void
setQuizMaster(QuizMaster quizMaster) {
this
.quizMaster = quizMaster;
}
public
void
askQuestion()
{
System.out.println(quizMaster.popQuestion());
}
}
After making all the changes, the class diagram of the example look like this.
The container comes into picture and it helps in injecting the dependancies.
The bean configuration is done in the beans.xml file.
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
beans
xmlns
=
"http://www.springframework.org/schema/beans"
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.xsd"
>
<
bean
id
=
"springQuizMaster"
class
=
"com.opensourzesupport.SpringQuizMaster"
></
bean
>
<
bean
id
=
"strutsQuizMaster"
class
=
"com.opensourzesupport.StrutsQuizMaster"
></
bean
>
<
bean
id
=
"quizMasterService"
class
=
"com.opensourzesupport.QuizMasterService"
>
<
property
name
=
"quizMaster"
>
<
ref
local
=
"springQuizMaster"
/>
</
property
>
</
bean
>
</
beans
>
Here a reference of SpringQuizMaster is injected to the QuizMaster bean. When we execute this example, "Are you new to Spring?" gets printed in the console.
To make our QuizMaster ask questions related to Struts, the only change we need to do is, to change the bean reference in the ref tag.
<
bean
id
=
"quizMasterService"
class
=
"com.opensourzesupport.QuizMasterService"
>
<
property
name
=
"quizMaster"
>
<
ref
local
=
"strutsQuizMaster"
/>
</
property
>
</
bean
>
To execute this example add the following jar files to the classpath.
1.
antlr-runtime-3.0
2.
commons-logging-1.0.4
3.
org.springframework.asm-3.0.0.M3
4.
org.springframework.beans-3.0.0.M3
5.
org.springframework.context-3.0.0.M3
6.
org.springframework.context.support-3.0.0.M3
7.
org.springframework.core-3.0.0.M3
8.
org.springframework.expression-3.0.0.M3
Spring Setter Injection
In this example you will learn how to set a bean property via setter injection. Consider the following User bean class.
package
com.opensourzesupport;
public
class
User {
private
String name;
private
int
age;
private
String country;
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
public
int
getAge() {
return
age;
}
public
void
setAge(
int
age) {
this
.age = age;
}
public
String getCountry() {
return
country;
}
public
void
setCountry(String country) {
this
.country = country;
}
public
String toString() {
return
name +
" is "
+ age +
" years old, living in "
+ country;
}
}
Here the beans.xml file is used to do spring bean configuration. The following code shows how to set a property value thru setter injection.
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
beans
xmlns
=
"http://www.springframework.org/schema/beans"
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.xsd"
>
<
bean
id
=
"user"
class
=
"com.opensourzesupport.User"
>
<
property
name
=
"name"
value
=
"Prasobh"
/>
<
property
name
=
"age"
value
=
"26"
/>
<
property
name
=
"country"
value
=
"India"
/>
</
bean
>
</
beans
>
Here we set "Prasobh", "26" and "India" for the User bean properties name, age and country respectively. The following Main class is used to get the User bean from the Spring IoC container and dispaly its value it to the user.
package
com.opensourzesupport;
import
org.springframework.context.ApplicationContext;
import
org.springframework.context.support. ClassPathXmlApplicationContext;
public
class
Main {
public
static
void
main(String[] args) {
ApplicationContext context =
new
ClassPathXmlApplicationContext(
"beans.xml"
);
User user = (User)context.getBean(
"user"
);
System.out.println(user);
}
}
1.Prasobh
is 26 years old, living in India
Spring Constructor Injection
In this example you will learn how to set a bean property via constructor injection. Consider the following User bean class.
package
com.opensourzesupport;
public
class
User {
private
String name;
private
int
age;
private
String country;
User(String name,
int
age, String country)
{
this
.name=name;
this
.age=age;
this
.country=country;
}
public
String toString() {
return
name +
" is "
+ age +
" years old, living in "
+ country;
}
}
Here the beans.xml file is used to do spring bean configuration. The following code shows how to set a property value thru constructor injection.
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
beans
xmlns
=
"http://www.springframework.org/schema/beans"
mlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
=
" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
>
<
bean
id
=
"user"
class
=
"com.vaanopensourzesupportnila.User"
>
<
constructor-arg
value
=
"Prasobh"
/>
<
constructor-arg
value
=
"26"
/>
<
constructor-arg
value
=
"India"
/>
</
bean
>
</
beans
>
User(
int
age, String country)
{
this
.age=age;
this
.country=country;
}
User(String name, String country)
{
this
.name=name;
this
.country=country;
}
<
bean
id
=
"user"
class
=
"com.opensourzesupport.User"
>
<
constructor-arg
value
=
"26"
/>
<
constructor-arg
value
=
"India"
/>
</
bean
>
<
bean
id
=
"user"
class
=
"com.opensourzesupport.User"
>
<
constructor-arg
type
=
"int"
value
=
"26"
/>
<
constructor-arg
type
=
"java.lang.String"
value
=
"India"
/>
</
bean
>
User(String name,
int
age)
{
this
.name=name;
this
.age=age;
}
User(
int
age, String country)
{
this
.age=age;
this
.country=country;
}
<
bean
id
=
"user"
class
=
"com.opensourzesupport.User"
>
<
constructor-arg
type
=
"int"
value
=
"26"
/>
<
constructor-arg
type
=
"java.lang.String"
value
=
"India"
/>
</
bean
>
Here is the bean configuration file after adding the index attribute.
<
bean
id
=
"user"
class
=
"com.opensourzesupport.User"
>
<
constructor-arg
index
=
"0"
type
=
"int"
value
=
"26"
/>
<
constructor-arg
index
=
"1"
type
=
"java.lang.String"
value
=
"India"
/>
</
bean
>
Spring MVC
Spring MVC helps in building flexible and loosely coupled web applications. The Model-view-controller design pattern helps in seperating the business logic, presentation logic and navigation logic. Models are responsible for encapsulating the application data. The Views render response to the user with the help of the model object . Controllers are responsible for receiving the request from the user and calling the back-end services.The figure below shows the flow of request in the Spring MVC Framework.
When a request is sent to the Spring MVC Framework the following sequence of events happen.
- The DispatcherServlet first receives the request.
- The DispatcherServlet consults the HandlerMapping and invokes the Controller associated with the request.
- The Controller process the request by calling the appropriate service methods and returns a ModeAndView object to the DispatcherServlet. The ModeAndView object contains the model data and the view name.
- The DispatcherServlet sends the view name to a ViewResolver to find the actual View to invoke.
- Now the DispatcherServlet will pass the model object to the View to render the result.
- The View with the help of the model data will render the result back to the user.
Go to File -> New -> Dynamic Web Project, to create a web project.
Enter the project name and click the Finish button.
Right click the project folder, and select Spring Tools -> Add Spring Project Nature, to add Spring capabilities to the web project. This feature will be available once you install the Spring IDE.
Create a new package com.opensourzesupport inside the src directory. The Spring controller class extends org.springframework.web.servlet.mvc.AbstractController class. To create a new controller class right click the src directory and create a new java class, enter the controller class name and super class name and the Finish button.
Copy the following code inside the HelloWorldController class.
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
import
org.springframework.web.servlet.ModelAndView;
import
org.springframework.web.servlet.mvc.AbstractController;
public
class
HelloWorldController
extends
AbstractController {
private
String message;
@Override
protected
ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws
Exception {
return
new
ModelAndView(
"welcomePage"
,
"welcomeMessage"
, message);
}
public
void
setMessage(String message) {
this
.message = message;
}
}
The DispatcherSevlet, as the name indicates, is a single servlet that manages the entire request-handling process. When a request is sent to the DispatcherServlet it delegates the job by invoking the appropriate controllers to process the request. Like any other servlet the DispatcherServlet need to be configured in the web deployment descriptor as shown.
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
web-app
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns
=
"http://java.sun.com/xml/ns/javaee"
xmlns:web
=
"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation
=
"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id
=
"WebApp_ID"
version
=
"2.5"
>
<
servlet
>
<
servlet-name
>dispatcher</
servlet-name
>
<
servlet-class
> org.springframework.web.servlet.DispatcherServlet </
servlet-class
>
<
load-on-startup
>1</
load-on-startup
>
</
servlet
>
<
servlet-mapping
>
<
servlet-name
>dispatcher</
servlet-name
>
<
url-pattern
>*.htm</
url-pattern
>
</
servlet-mapping
>
<
welcome-file-list
>
<
welcome-file
>redirect.jsp</
welcome-file
>
</
welcome-file-list
>
</
web-app
>
The redirect.jsp will be invoked first when we execute the Spring web application. This is the only jsp file outside the WEB-INF directory and it is here to provide a redirect to the DispatcherServlet. All the other views should be stored under the WEB-INF directory so that they can be invoked only through the controller process.
To create a bean configuration file right click the WebContent folder and select New -> Other. The following dialog box appears.
Select the Spring Bean Configuration file and click Next.
Enter the file name as "dispatcher-servlet.xml" and click the Finish button.
Now the Spring bean configuration file is created, we need to configure the Controller and the ViewResolver classes. The following code shows how to do this.
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
beans
xmlns
=
"http://www.springframework.org/schema/beans"
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.xsd"
>
<
bean
id
=
"viewResolver"
class
=
" org.springframework.web.servlet.view. InternalResourceViewResolver"
>
<
property
name
=
"prefix"
>
<
value
>/WEB-INF/jsp/</
value
>
</
property
>
<
property
name
=
"suffix"
>
<
value
>.jsp</
value
>
</
property
>
</
bean
>
<
bean
name
=
"/welcome.htm"
class
=
"com.opensourzesupport.HelloWorldController"
>
</
bean
>
</
beans
>
1.
<
bean
name
=
"/welcome.htm"
class
=
"com.opensourzesupport.HelloWorldController"
>
2.
<
property
name
=
"message"
value
=
"Hello World!"
/>
3.
</
bean
>
We set the message attribute of the HelloWorldController class thru setter injection. The HelloWorldController class is configured just like an another JavaBean class in the Spring application context, so like any other JavaBean we can set values to it through Dependency Injection(DI).
The redirect.jsp will redirect the request to the DispatcherServlet, which inturn consults with the BeanNameUrlHandlerMapping and invokes the HelloWorldController. The handleRequestInternal() method in the HelloWorldController class will be invoked. Here we return the message property under the name welcomeMessage and the view name welcomePage to the DispatcherServlet. As of now we only know the view name, and to find the actual view to invoke we need a ViewResolver.
The ViewResolver is configured using the following code.
<
bean
id
=
"viewResolver"
class
=
" org.springframework.web.servlet.view.InternalResourceViewResolver"
>
<
property
name
=
"prefix"
>
<
value
>/WEB-INF/jsp/</
value
>
</
property
>
<
property
name
=
"suffix"
>
<
value
>.jsp</
value
>
</
property
>
</
bean
>
The following library files are needed to run the example.
01.
antlr-runtime-3.0
02.
commons-logging-1.0.4
03.
org.springframework.asm-3.0.0.M3
04.
org.springframework.beans-3.0.0.M3
05.
org.springframework.context-3.0.0.M3
06.
org.springframework.context.support-3.0.0.M3
07.
org.springframework.core-3.0.0.M3
08.
org.springframework.expression-3.0.0.M3
09.
org.springframework.web-3.0.0.M3
10.
org.springframework.web.servlet-3.0.0.M3
Spring SimpleFormController
To handle forms in Spring you need to extend your controller class from SimpleFormController class. Here we will create a user registration form to understand how this works. The SimpleFormController is deprecated as of Spring 3.0 so if you are using Spring 3.0 or above use the annotate controllers instead.
package
com.opensourzesupport.web;
import
org.springframework.web.servlet.ModelAndView;
import
org.springframework.web.servlet.mvc.SimpleFormController;
import
com.opensourzesupport.domain.User;
import
com.opensourzesupport.service.UserService;
@SuppressWarnings
(
"deprecation"
)
public
class
UserController
extends
SimpleFormController {
private
UserService userService;
public
UserController() {
setCommandClass(User.
class
);
setCommandName(
"user"
);
}
public
void
setUserService(UserService userService) {
this
.userService = userService;
}
@Override
protected
ModelAndView onSubmit(Object command)
throws
Exception {
User user = (User) command;
userService.add(user);
return
new
ModelAndView(
"userSuccess"
,
"user"
,user);
}
}
You need to have a method to handle the form when the form is submitted, here the onSubmit() method is used for this purpose. The onSubmit() method has access to the command object, we first typecast the command object to User (our domain object) and then to register the user we call the add() method of the service class and finally return the ModelandView object.
All the forms field values will be submitted as Strings to the form controller. Spring has several pre registered property editors to convert the String values to common data types. Incase you have a custom data type you need to create custom property editors to handle them.
The User domain object has the following attributes.
package
com.opensourzesupport.domain;
public
class
User {
private
String name;
private
String password;
private
String gender;
private
String country;
private
String aboutYou;
private
String[] community;
private
Boolean mailingList;
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
public
String getPassword() {
return
password;
}
public
void
setPassword(String password) {
this
.password = password;
}
public
String getGender() {
return
gender;
}
public
void
setGender(String gender) {
this
.gender = gender;
}
public
String getCountry() {
return
country;
}
public
void
setCountry(String country) {
this
.country = country;
}
public
String getAboutYou() {
return
aboutYou;
}
public
void
setAboutYou(String aboutYou) {
this
.aboutYou = aboutYou;
}
public
String[] getCommunity() {
return
community;
}
public
void
setCommunity(String[] community) {
this
.community = community;
}
public
Boolean getMailingList() {
return
mailingList;
}
public
void
setMailingList(Boolean mailingList) {
this
.mailingList = mailingList;
}
}
package
com.opensourzesupport.service;
import
com.opensourzesupport.domain.User;
public
interface
UserService {
public
void
add(User user);
}
package
com.opensourzesupport.service;
import
com.opensourzesupport.domain.User;
public
class
UserServiceImpl
implements
UserService {
@Override
public
void
add(User user) {
//Persist the user object here.
System.out.println(
"User added successfully"
);
}
}
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<
html
>
<
head
>
<
title
>Registration Page</
title
>
</
head
>
<
body
>
<
form:form
method
=
"POST"
commandName
=
"user"
>
<
table
>
<
tr
>
<
td
>User Name :</
td
>
<
td
><
form:input
path
=
"name"
/></
td
>
</
tr
>
<
tr
>
<
td
>Password :</
td
>
<
td
><
form:password
path
=
"password"
/></
td
>
</
tr
>
<
tr
>
<
td
>Gender :</
td
>
<
td
>
<
form:radiobutton
path
=
"gender"
value
=
"M"
label
=
"M"
/>
<
form:radiobutton
path
=
"gender"
value
=
"F"
label
=
"F"
/>
</
td
>
</
tr
>
<
tr
>
<
td
>Country :</
td
>
<
td
>
<
form:select
path
=
"country"
>
<
form:option
value
=
"0"
label
=
"Select"
/>
<
form:option
value
=
"1"
label
=
"India"
/>
<
form:option
value
=
"2"
label
=
"USA"
/>
<
form:option
value
=
"3"
label
=
"UK"
/>
</
form:select
></
td
>
</
tr
>
<
tr
>
<
td
>About you :</
td
>
<
td
><
form:textarea
path
=
"aboutYou"
/></
td
>
</
tr
>
<
tr
>
<
td
>Community :</
td
>
<
td
>
<
form:checkbox
path
=
"community"
value
=
"Spring"
label
=
"Spring"
/>
<
form:checkbox
path
=
"community"
value
=
"Hibernate"
abel
=
"Hibernate"
/>
<
form:checkbox
path
=
"community"
value
=
"Struts"
label
=
"Struts"
/>
</
td
>
</
tr
>
<
tr
>
<
td
></
td
>
<
td
>
<
form:checkbox
path
=
"mailingList"
label
=
"Would you like to join our mailinglist?"
/></
td
>
</
tr
>
<
tr
>
<
td
colspan
=
"2"
><
input
type
=
"submit"
></
td
>
</
tr
>
</
table
>
</
form:form
>
</
body
>
</
html
>
The web.xml file.
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
web-app
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns
=
"http://java.sun.com/xml/ns/javaee"
xmlns:web
=
"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation
=
"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id
=
"WebApp_ID"
version
=
"2.5"
>
<
display-name
>SpringExample6</
display-name
>
<
servlet
>
<
servlet-name
>dispatcher</
servlet-name
>
<
servlet-class
>org.springframework.web.servlet. DispatcherServlet
</
servlet-class
>
<
load-on-startup
>1</
load-on-startup
>
</
servlet
>
<
servlet-mapping
>
<
servlet-name
>dispatcher</
servlet-name
>
<
url-pattern
>*.htm</
url-pattern
>
</
servlet-mapping
>
<
welcome-file-list
>
<
welcome-file
>redirect.jsp</
welcome-file
>
</
welcome-file-list
>
</
web-app
>
<?
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:p
=
"http://www.springframework.org/schema/p"
xsi:schemaLocation
=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
>
<
bean
id
=
"viewResolver"
class
=
"org.springframework.web.servlet.view. InternalResourceViewResolver"
p:prefix
=
"/WEB-INF/jsp/"
p:suffix
=
".jsp"
/>
<
bean
id
=
"userService"
class
=
"com.opensourzesupport.service.UserServiceImpl"
/>
<
bean
name
=
"/userRegistration.htm"
class
=
"com.opensourzesupport.web.UserController"
p:userService-ref
=
"userService"
p:formView
=
"userForm"
p:successView
=
"userSuccess"
/>
</
beans
>
For injecting the simple types we use property name in the "p" namespace and for injecting references we add "-ref" suffix to it. For example we use p:formView for injecting the form view property and p:userService-ref for injecting the user service.
During the HTTP GET request the formView will be rendered. When the form is submitted (during the HTTP POST request) the onSubmit() method of the UserController class will be called, on successful execution of the method the successView will be rendered. Incase of any type conversion errors or validation errors the formView will be automatically displayed the user.
Run the example by executing the redirect.jsp file. The redirect.jsp file, redirect the request to "userRegistration.htm".
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<% response.sendRedirect("userRegistration.htm"); %>
Fill the form and submit it.
The onSubmit() method of the UserController class will be called and the control will be transfered to the view "userSuccess". We use InternalResourceViewResolver here, so the userSuccess.jsp page will be dispalyed. In the userSuccess.jsp page we dispaly all the user details using the jstl tags.
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<
html
>
<
head
>
<
title
>Success Page</
title
>
</
head
>
<
body
>
User Details
<
hr
>
User Name : ${user.name} <
br
/>
Gender : ${user.gender} <
br
/>
Country : ${user.country} <
br
/>
About You : ${user.aboutYou} <
br
/>
Community : ${user.community[0]} ${user.community[1]} ${user.community[2]}<
br
/>
Mailing List: ${user.mailingList}
</
body
>
</
html
>
The Spring Workflow
Before taking a look over the various Components that are involved in the Spring MVC Framework, let us have a look on the style of Spring Web Flow.
- The Client requests for a Resource in the Web Application.
- The Spring Front Controller, which is implemented as a Servlet, will intercept the Request and then will try to find out the appropriate Handler Mappings.
- The Handle Mappings is used to map a request from the Client to its Controller object by browsing over the various Controllers defined in the Configuration file.
- With the help of Handler Adapters, the Dispatcher Servlet will dispatch the Request to the Controller.
- The Controller processes the Client Request and returns the Model and the View in the form of
ModelAndView
object back to the Front Controller. - The Front Controller then tries to resolve the actual View (which may be Jsp, Velocity or Free marker) by consulting the View Resolver object.
- Then the selected View is rendered back to the Client.
Let us look into the various Core Components that make up the Spring Web Tier. Following are the components covered in the next subsequent sections.
Dispatcher Servlet
The Dispatcher Servlet as represented by org.springframework.web.servlet.DispatcherServlet, follows the Front Controller Design Pattern for handling Client Requests. It means that whatever Url comes from the Client, this Servlet will intercept the Client Request before passing the Request Object to the Controller. The Web Configuration file should be given definition in such a way that this Dispatcher Servlet should be invoked for Client Requests.
Following is the definition given in the
web.xml
to invoke Spring's Dispatcher Servlet. web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4">
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.*</url-pattern>
</servlet-mapping>
</web-app>
Look into the definition of
servlet-mapping
tag. It tells that whatever be the Client Request (represented by *.* meaning any Url with any extension), invoke the Servlet by name 'dispatcher'
. In our case, the 'dispatcher' servlet is nothing but an instance of type 'org.springframework.web.servlet.DispatcherServlet'
. Closing associated term with the Dispatcher Servlet is the Application Context. An Application Context usually represents a set of Configuration Files that are used to provide Configuration Information to the Application. The Application Context is a Xml file that contain various Bean Definitions. By default the Dispatcher Servlet will try to look for a file by name
<servlet-name>-servlet.xml
in the WEB-INF
directory. So, in our case the Servlet will look for a file name called dispatcher-servlet.xml
file in the WEB-INF directory. It is wise sometimes to split all the Configuration information across multiple Configuration Files. In such a case we have to depend on a Listener Servlet called Context Loader represented by
org.springframework.web.context.ContextLoaderListener
.
<web-app>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
</web-app>
By default, this Context Listener will try to look for the Configuration File by name
web.xml 'applicationContext.xml'
in the '/WEB-INF'
directory. But with the help of the parameter 'contextConfigLocation'
the default location can be overridden. Even multiple Configuration Files each containing separate piece of Information is also possible.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4">
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/contacts.xml, /WEB-INF/resources.xml</param-value>
</context-param>
</web-app>
The above definition instructs the Framework to look and load for the Configuration Files by name
'contacts.xml'
and 'resources.xml'
in the WEB-INF
directory.
No comments:
Post a Comment