Enterprise Java

Spring MVC Form Tutorial

This tutorial will show how to handle a form submission in Spring MVC. We will define a controller to handle the page load and the form submission. You can grab the code on GitHub.

Prerequisites:

You should have a working Spring MVC Application. If you do not already have a working Spring MVC application set up, follow this tutorial. For this tutorial, we are going to make a simple form for subscribing to a newsletter. The form will have the following fields:

  • name – input field
  • age – input field
  • email – input field
  • gender – select drop-down
  • receiveNewsletter – checkbox
  • newsletterFrequency – select drop-down

Requirements:

  • The newsletterFrequency drop-down should only be active if the receiveNewsletter checkbox is checked
  • We will not be performing any validations in this example (stay-tuned for future tutorial)
  • When the user submits the form, the same page will reload
  • Reloaded page should display a message that indicates that the submission was successful and shows the saved values

When we’re done, we will have a page that looks like this:

Spring MVC form screenshot

First, let’s set up the object we will use to store the subscriber’s information. Create the class Subscriber in package com.codetutr.form. This is a basic Java bean. Notice we are using enumerations to store the gender and newsletter frequency fields. For simplicity, I defined the enums in the same class. Also notice that we are defining the toString. This is just so we can easily get the values to print after submission.

Subscriber.java

package com.codetutr.form;

public class Subscriber {

	private String name;
	private String email;
	private Integer age;
	private Gender gender;
	private Frequency newsletterFrequency;
	private Boolean receiveNewsletter;

	public enum Frequency {
		HOURLY, DAILY, WEEKLY, MONTHLY, ANNUALLY
	}

	public enum Gender {
		MALE, FEMALE
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public Gender getGender() {
		return gender;
	}

	public void setGender(Gender gender) {
		this.gender = gender;
	}

	public Frequency getNewsletterFrequency() {
		return newsletterFrequency;
	}

	public void setNewsletterFrequency(Frequency newsletterFrequency) {
		this.newsletterFrequency = newsletterFrequency;
	}

	public Boolean getReceiveNewsletter() {
		return receiveNewsletter;
	}

	public void setReceiveNewsletter(Boolean receiveNewsletter) {
		this.receiveNewsletter = receiveNewsletter;
	}

	@Override
	public String toString() {
		return "Subscriber [name=" + name + ", age=" + age + ", gender=" + gender
				+ ", newsletterFrequency=" + newsletterFrequency
				+ ", receiveNewsletter=" + receiveNewsletter + "]";
	}

}

Now, let’s create the controller. Create class FormController in package com.codetutr.controller:

FormController.java

package com.codetutr.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.codetutr.form.Subscriber;
import com.codetutr.form.Subscriber.Frequency;

@Controller
public class FormController {

	@ModelAttribute("frequencies")
	public Frequency[] frequencies() {
		return Frequency.values();
	}

	@RequestMapping(value="form", method=RequestMethod.GET)
	public String loadFormPage(Model m) {
		m.addAttribute("subscriber", new Subscriber());
		return "formPage";
	}

	@RequestMapping(value="form", method=RequestMethod.POST)
	public String submitForm(@ModelAttribute Subscriber subscriber, Model m) {
		m.addAttribute("message", "Successfully saved person: " + subscriber.toString());
		return "formPage";
	}
}

Let’s look at a few things in the code above. First, notice that both request handlers (methods annotated with @RequestMapping) are mapped to the same URL – “form”. The only difference in the mapping is that one handles an HTTP GET request, and the other a POST. The first handler (for the GET request) will be invoked when the user navigates to the “form” page, because they will access the page using a GET request. The POST handler is invoked when the form is submitted (since it will be submitted via HTTP POST to the “form” URL). You could, of course, submit your form to any URL using any HTTP method – just make sure to map your handler accordingly here.

Let’s look at the GET handler. It takes a Model, which we populate with an empty Subscriber object. This object is what we will use to populate our form. We are not setting any values here, but if we wanted to, say default the receiveNewsletter checkbox to true and set default newsletter frequency to hourly, we could do:

Subscriber subscriber = new Subscriber();
subscriber.setReceiveNewsletter(true);
subscriber.setNewsletterFrequency(Frequency.HOURLY);
m.addAttribute("subscriber", subscriber);

Also note that if we do not add an object called “subscriber” to the model, Spring would complain when we try to access the JSP, because we will be setting up the JSP to bind the form to the “subscriber” model attribute. You would see a JSP error: “Neither BindingResult nor plain target object for bean name ‘subscriber’ available as request attribute” and the JSP would not render.

The last thing to look at in the controller code is the @ModelAttribute method. When a method is annotated with @ModelAttribute, Spring runs it before each handler method and adds the return value to the model. We specified in the annotation to add the Frequency values to the model as “frequencies”. This object will be used to populate the newsletter frequency drop-down box in the JSP form. Instead of using the @ModelAttribute method, we could have added the following line to each of the request handlers:

m.addAttribute("frequencies", Frequency.values())

Finally, let’s set up the jsp. Create a file called formPage.jsp in WEB-INF/view (or wherever you have configured your JSPs to reside):

formPage.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<!DOCTYPE HTML>
<html>
  <head>
    <title>Sample Form</title>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <style>
      body { background-color: #eee; font: helvetica; }
      #container { width: 500px; background-color: #fff; margin: 30px auto; padding: 30px; border-radius: 5px; box-shadow: 5px; }
      .green { font-weight: bold; color: green; }
      .message { margin-bottom: 10px; }
      label {width:70px; display:inline-block;}
      form {line-height: 160%; }
      .hide { display: none; }
    </style>
  </head>
  <body>

  <div id="container">

    <h2>Subscribe to The Newsletter!</h2>
    <c:if test="${not empty message}"><div class="message green">${message}</div></c:if>

    <form:form modelAttribute="subscriber">
      <label for="nameInput">Name: </label>
      <form:input path="name" id="nameInput" />
      <br/>

      <label for="ageInput">Age: </label>
      <form:input path="age" id="ageInput" />
      <br/>

      <label for="emailInput">Email: </label>
      <form:input path="email" id="emailInput" />
      <br/>

      <label for="genderOptions">Gender: </label>
      <form:select path="gender" id="genderOptions">
        <form:option value="">Select Gender</form:option>
        <form:option value="MALE">Male</form:option>
        <form:option value="FEMALE">Female</form:option>
      </form:select>
      <br/>

      <label for="newsletterCheckbox">Newsletter? </label>
      <form:checkbox path="receiveNewsletter" id="newsletterCheckbox" />
      <br/>
      <label for="frequencySelect">Freq:</label>
      <form:select path="newsletterFrequency" id="frequencySelect">
        <form:option value="">Select Newsletter Frequency: </form:option>
        <c:forEach items="${frequencies}" var="frequency">
          <form:option value="${frequency}">${frequency}</form:option>
        </c:forEach>
      </form:select>
      <br/>

      <br/>
      <input type="submit" value="Submit" />
    </form:form>
  </div>

  <script type="text/javascript">

    $(document).ready(function() {

      toggleFrequencySelectBox(); // show/hide box on page load

      $('#newsletterCheckbox').change(function() {
        toggleFrequencySelectBox();
      })

    });

    function toggleFrequencySelectBox() {
      if(!$('#newsletterCheckbox').is(':checked')) {
        $('#frequencySelect').val('');
        $('#frequencySelect').prop('disabled', true);
      } else {
        $('#frequencySelect').prop('disabled', false);
      }
    }

  </script>

  </body>
</html>

Let’s walk through the form tags we are using. Notice the line at the top of the page: <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>. This imports the Spring Form tags we will be using. When we open the form with the <form:form> tag, note that we are specifying the model attribute. This tells Spring to look for an attribute in the Model and bind it to the form. The action and method attributes can also be specified. If unspecified (as in this example), they default to the current URL and “POST”, respectively (just like regular HTML forms).

Notice that each of our input fields is using the Spring Form taglib (form: prefix). Each of these fields also specifies a path attribute. This must correspond to a getter or setter of the model attribute (in our case, the Subscriber class) according to the standard Java bean convention (get/is, set prefixed to field name with first letter capitalized). When the page is loaded, the input fields are populated by Spring, which calls the getter of each field bound to an input field. When the form is submitted, the setters are called to save the values of the form to the object.

The <form:input> tags are pretty self explanatory. Notice the two instances of <form:select> used. In the first select drop-down, for the gender field, notice that we manually list all of the options. In the newsletter frequency select drop-down, though, we loop through the frequencies model attribute (remember we added that to the model through the @ModelAttribute-annotated method in the Controller) and add each item as an option in the drop-down. Spring automatically will bind the form values to the enums when the form is submitted as long as the value of the selected option is a valid enum name.

When the form is submitted, the POST handler in the controller is invoked. The form is automatically bound to the subscriber argument that we passed in. The @ModelAttribute annotation isn’t actually necessary here. I will write more about that in another post.

There you have it! I strongly recommend you download the source and run the code. Post any questions you have in the comments below.

Full Source: ZIP, GitHub To run the code from this tutorial: Must have Gradle installed. Download the ZIP. Extract. Open command prompt to extracted location. Run gradle jettyRunWar. Navigate in browser to http://localhost:8080/form.

Resources

 

Reference: Spring MVC Form Tutorial from our JCG partner Steve Hanson at the CodeTutr blog.

Steve Hanson

Steve is a software developer interested in web development and new technologies. He currently works as a Java consultant at Credera in Dallas, TX.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

5 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Jeremy
Jeremy
9 years ago

WOW!!! Great job on this tutorial. This really cleared some things up for me. Thank you.

sathish
sathish
9 years ago

good tutorial….Thanks you

Cooler
Cooler
9 years ago

Thanks, this example helped me fix the problem with empty object in controller!

navinmurrari
navinmurrari
8 years ago

Nice tutorial please write about complete WEB flow

nisha
5 years ago

Awesome, very well written article. Many important points are covered here. I am glad for that. Kindly continue doing the same.

Back to top button