Friday, December 18, 2015

Spring Simple Form Handling

On my previous post "Helloworld Spring 4 MVC in Eclipse Luna" I have described setup Spring MVC project in Eclipse step by step. In this post I will describe basic Spring form handling process. I will use the same project to demonstrate this post as well and you can download the previous project source from on following GitHub location https://github.com/NirmalBalasooriya/SpringWeb. 
In this post I will show how to handle simple user details form using Spring Forms and JSTL.

Step 1 Create required model classes
First of lets create some model classes that we are going to use in this demonstration. First of all lets create new model class "User". Right click on "src" folder then go to New->Class. I will provide package as spring.first.model (You can use preferred package name you like) and class name as "User".

Figure 1: Add New User model class

Then lets add another model class "Address" to the same package.


Then I'll add some details in to User model class such as first name, last name, Address reference etc. For the Address class also I'll add details like No, Street Name, City, Province, Country. Then I'll encapsulate two model classes. (Provide limited accessibility to all the variables and provide setters and getter  methods) Please see the content of our two model classes. In addition to that I have override the  toString method so when we print particular object content on this method will be printed.
Address class content
package spring.first.model;

public class Address {
    private int no;
    private String Streat;
    private String city;
    private String area;
    private String country;
    public int getNo() {
        return no;
    }
    public void setNo(int no) {
        this.no = no;
    }
    public String getStreat() {
        return Streat;
    }
    public void setStreat(String streat) {
        Streat = streat;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public String getArea() {
        return area;
    }
    public void setArea(String area) {
        this.area = area;
    }
    public String getCountry() {
        return country;
    }
    public void setCountry(String country) {
        this.country = country;
    }
   
    @Override
    public String toString() {
        return "Address [no=" + no + ", Streat=" + Streat + ", city=" + city
                + ", area=" + area + ", country=" + country + "]";
    }

}
User class content

package spring.first.model;

import java.util.Arrays;
import java.util.List;

public class User {
    private String id;
    private String firstName;
    private String lastName;
    private Address address;
    private String[] preferredContactMethod;
    private String sex;
    private List<String> contactNumbers;
  
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public Address getAddress() {
        return address;
    }
    public void setAddress(Address address) {
        this.address = address;
    }
    public String[] getPreferredContactMethod() {
        return preferredContactMethod;
    }
    public void setPreferredContactMethod(String[] preferredContactMethod) {
        this.preferredContactMethod = preferredContactMethod;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public List<String> getContactNumbers() {
        return contactNumbers;
    }
    public void setContactNumbers(List<String> contactNumbers) {
        this.contactNumbers = contactNumbers;
    }
  
    @Override
    public String toString() {
        return "User [id=" + id + ", firstName=" + firstName + ", lastName="
                + lastName + ", address=" + address
                + ", preferredContactMethod="
                + Arrays.toString(preferredContactMethod) + ", sex=" + sex
                + ", contactNumbers=" + contactNumbers + "]";
    }
}

Now we have created our two model classes then lets go ahead with these two. Next lets create mock User service to load static User list and functionality to add newly added users to existing collection.

Step 2 Create mocked User service
Lets add new class "UserService" in new package "spring.first.data" by right click on "SRC" folder then new -> class. Please note that I will not use any database connection for this example. I will use mocked static data content to demonstrate this example.

Figure 2: Add new UserService

I will use following content on my static service.

package spring.first.data;

import java.util.ArrayList;
import java.util.List;

import spring.first.model.Address;
import spring.first.model.User;

public class UserService {
    private static List<User> users;
    public UserService()
    {
        users=new ArrayList<User>();
        loadMockedUsers();
    }
   
    public List<User> getMockedUsers()
    {
        return users;
    }
   
    private void loadMockedUsers()
    {
        User user1=new User();
        user1.setId("U0001");
        user1.setFirstName("Laksh");
        user1.setLastName("Jonsan");
        user1.setPreferredContactMethod(new String[]{"phone","email"});
        user1.setSex("male");
        Address address=new Address();
        address.setNo(1011);
        address.setCity("Collombo");
        address.setCountry("Sri lanka");
        user1.setAddress(address);
        users.add(user1);
       
        User user2=new User();
        user2.setId("U0002");
        user2.setFirstName("Ashly");
        user2.setLastName("Jenuri");
        user2.setPreferredContactMethod(new String[]{"phone"});
        user2.setSex("female");
        Address address2=new Address();
        address2.setNo(225);
        address2.setCity("Gampaha");
        address2.setCountry("Sri lanka");
        user2.setAddress(address2);
        users.add(user2);
    }
   
    public User saveUser(User user)
    {
        users.add(user);
        return findUser(user.getId());
    }
   
    public User findUser(String id)
    {
        for (User user : users) {
            if(user.getId().equalsIgnoreCase(id))
            {
                return user;
            }
        }
        return null;
    }
}


Step 3 Create User controller class

Now lets create UserController class which handles the requests related to the user activities in this project. Right click on spring.first.controller package then go to add -> class. The set class name as UserController.



Then lets add following method in to controller. This will load usermain.jsp in jsp folder. Next step lets add this.

   @RequestMapping("/userHandling")
    public String home()
    {
        return "usermain";
    }


Then lets add related JSP file in to JSP folder inside the WEB-INF JSP foler.
Lets add following content in to this. 

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="springform" uri="http://www.springframework.org/tags/form" %>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>User Handling Page</title>
</head>
<body>
<a href="<spring:url value='/addUser'/>">New User</a>
<br>
<a href="<spring:url value='/allUsers'/>">All Users</a>
</body>
</html>


So now if you run the application you can see the content on

localhost:port//springfirst/userHandling

For my PC it looks as follows

http://localhost:8080/SpringFirstWeb/userHandling

On this JSP we have added two links to add user and view all users. Still we have not added these methods to controller lets add those methods as follows.

@RequestMapping("/addUser")
public String newUser(Model model)
{
model.addAttribute("user", new User());
List<String> prefContctMethods=new ArrayList<String>();
prefContctMethods.add("E-mail");
prefContctMethods.add("Call");
model.addAttribute("prefContct", prefContctMethods);
List<String> sexType=new ArrayList<String>();
sexType.add("Male");
sexType.add("Female");
model.addAttribute("sexType", sexType);
return "newUser";
}

In this I have added two variables in to model which we will use to load data on the JSP. Those two variables are prefContct and sexType. Then after that it will load newUser.jsp. To add this JSP in to JSP folder inside the WEB-INF. Add following content in to that.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="springform" uri="http://www.springframework.org/tags/form" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>New User</title>
</head>
<body>

Enter your User details
<spring:url value="/saveUser" var="springUrl"/>
<springform:form action="${springUrl}" method="POST" modelAttribute="user">
<table style="width:100%">
 <tr>
   <td>User ID</td>
   <td>
    <springform:input path="id"/>
<springform:errors path="id"  />
   </td> 
 </tr>
 <tr>
   <td>First Name</td>
   <td>
<springform:input path="firstName"/>
<springform:errors path="firstName"  />
</td> 
 </tr>
 <tr>
   <td>Last Name</td>
   <td>
<springform:input path="lastName"/>
<springform:errors path="lastName"  />
</td> 
 </tr>
 <tr><td><br/>Address Details</td></tr>
 <tr>
   <td>No</td>
   <td>
<springform:input path="address.no"/>
</td> 
 </tr>
 <tr>
   <td>Street</td>
   <td>
<springform:input path="address.Streat"/>
</td> 
 </tr>
 <tr>
   <td>City</td>
   <td>
<springform:input path="address.city"/>
</td> 
 </tr>    
 <tr>
   <td>Area</td>
   <td>
<springform:input path="address.area"/>
</td> 
 </tr>    
 <tr>
   <td>Country</td>
   <td>
<springform:input path="address.country"/>
</td> 
 </tr>        
 <tr>
   <td><br/>Preffered Contact Methods</td>
   <td>
<springform:select path="preferredContactMethod" items="${prefContct}"></springform:select>
</td> 
 </tr>        
 <tr>
   <td>Gender</td>
   <td>
<springform:radiobuttons id="radio" items="${sexType}" path="sex"/>
</td> 
 </tr>        

</table>

<button type="submit"> Submit</button>
</springform:form>

</body>
</html>

You can see I have used I have used both variables which I have added in to model in the controller.
Following code will generate drop down with values which contains on prefContct.
<springform:select path="preferredContactMethod" items="${prefContct}">

Following line will generate radio button group with values on sexType

<springform:radiobuttons id="radio" items="${sexType}" path="sex"/>

You can see as normal HTML form we can see action method on Spring Forms as well. It will tell which URL mapped should be called on form submission.

Still we have not added this new method in to controller lets add that in to UserController as follows. So whole UserController will be similar to this.

@RequestMapping(value="saveUser", method=RequestMethod.POST )
public String saveUser(@ModelAttribute User user,Errors errors, Model model)
{
System.out.println(user);
return "allUsers";
}

I have added println line to print user objects toString method return value. So we can see whether the actual values are sent to the server or not. After that it will load allUser.JSP file.

package spring.first.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import spring.first.data.UserService;
import spring.first.model.User;

@Controller
public class UserController {

@Autowired
UserService userService;

@RequestMapping("/userHandling")
public String home()
{
return "userMain";
}

@RequestMapping("/addUser")
public String newUser(Model model)
{
model.addAttribute("user", new User());
List<String> prefContctMethods=new ArrayList<String>();
prefContctMethods.add("E-mail");
prefContctMethods.add("Call");
model.addAttribute("prefContct", prefContctMethods);
List<String> sexType=new ArrayList<String>();
sexType.add("Male");
sexType.add("Female");
model.addAttribute("sexType", sexType);
return "newUser";
}

@RequestMapping(value="saveUser", method=RequestMethod.POST )
public String saveUser(@ModelAttribute User user,Errors errors, Model model)
{
System.out.println(user);
userService.saveUser(user);
model.addAttribute("users", userService.getMockedUsers());
return "allUsers";
}

@RequestMapping("/allUsers")
public String allUsers( Model model)
{
model.addAttribute("users", userService.getMockedUsers());
return "allUsers";
}
}


You can see I have use @Autowired annotations . To support this we have to register the bean UserService it can done by adding following line in to the springFirst-servlet.xml.

<bean id="UserService" class="data.UserService"/>

Our final springFirst-servlet.xml will contains following content.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">

<mvc:annotation-driven/>
<context:component-scan base-package="spring.first.controller"></context:component-scan>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>

<bean id="UserService" class="spring.first.data.UserService"/>
<mvc:resources location="/resources/" mapping="/resources/**"></mvc:resources>
</beans>

So when you access the http://localhost:8080/SpringFirstWeb/userHandling You can see similar interface to below image.


Then when you click on New User You can see similar interface to below image(Note that I have fill the form with sample data).


Final result page will be similar to below image.



We have completed our second Spring tutorial which discussed about Spring Form Handling. You can access the project on following URL Repository https://github.com/NirmalBalasooriya/SpringFormHandling. In future post I will provide more advance features in form handling.

No comments:

Post a Comment