Skip to content

attack7/gs-validating-form-input

 
 

Repository files navigation

This guide walks you through the process of configuring a web application form to support validation.

What you'll build

You'll build a simple Spring MVC application that take user input and checks the input using standard validation annotations. You'll also see how to display the error message on the screen so the user can re-enter a valid input.

What you'll need

How to complete this guide

Like all Spring's Getting Started guides, you can start from scratch and complete each step, or you can bypass basic setup steps that are already familiar to you. Either way, you end up with working code.

To start from scratch, move on to Set up the project.

To skip the basics, do the following:

  • [Download][zip] and unzip the source repository for this guide, or clone it using [Git][u-git]: git clone https://github.com/spring-guides/gs-validating-form-input.git
  • cd into gs-validating-form-input/initial.
  • Jump ahead to Create a Person object.

When you're finished, you can check your results against the code in gs-validating-form-input/complete. [zip]: https://github.com/spring-guides/gs-validating-form-input/archive/master.zip [u-git]: /understanding/Git

Set up the project

First you set up a basic build script. You can use any build system you like when building apps with Spring, but the code you need to work with Gradle and Maven is included here. If you're not familiar with either, refer to Building Java Projects with Gradle or Building Java Projects with Maven.

Create the directory structure

In a project directory of your choosing, create the following subdirectory structure; for example, with mkdir -p src/main/java/hello on *nix systems:

└── src
    └── main
        └── java
            └── hello

Create a Gradle build file

Below is the initial Gradle build file. But you can also use Maven. The pom.xml file is included right here. If you are using Spring Tool Suite (STS), you can import the guide directly.

build.gradle

buildscript {
    repositories {
        maven { url "http://repo.spring.io/libs-snapshot" }
        mavenLocal()
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'

jar {
    baseName = 'gs-validating-form-input'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
    maven { url "http://repo.spring.io/libs-snapshot" }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:0.5.0.M4")
    compile("org.hibernate:hibernate-validator:4.3.1.Final")
    compile("org.thymeleaf:thymeleaf-spring3:2.0.16")
    testCompile("junit:junit:4.11")
}

task wrapper(type: Wrapper) {
    gradleVersion = '1.8'
}

Note: This guide is using Spring Boot.

Create a Person object

The application involves validating a user's age, so first you need to create a class to represent a person.

src/main/java/hello/Person.java

package hello;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;

public class Person {
    @NotNull
    @Min(18)
    private Integer age;

    public String toString() {
        return "Person(" + age + ")";
    }
    
    public Integer getAge() {
        return age;
    }

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

The Person class only has one attribute, age. It is flagged with standard validation annotations:

  • @NotNull won't allow an empty value
  • @Min(18) won't allow if the age is less than 18

In addition to that, you can also see getters/setters for age as well as a convenient toString() method.

Create a web controller

Now that you have defined an entity, it's time to create a simple web controller.

src/main/java/hello/WebController.java

package hello;

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@Controller
public class WebController {

    @RequestMapping(value="/", method=RequestMethod.GET)
    public String showForm(Person person) {
        return "form";
    }
    
    @RequestMapping(value="/", method=RequestMethod.POST)
    public String enterAge(@Valid Person person, BindingResult bindingResult, 
            RedirectAttributes redirectAttributes) {
        if (bindingResult.hasErrors()) {
            redirectAttributes.addFlashAttribute("error", bindingResult.getFieldError().getDefaultMessage());
            return "redirect:/";
        }
        return "results";
    }

}

This controller has a GET and a POST method, both mapped to /.

The showForm method returns the form template. It includes a Person in its method signature so the template can associate form attributes with a Person.

The enterAge method accepts three arguments:

  • A person object marked up with @Valid to gather the attributes filled out in the form you're about to build.
  • A bindingResult object so you can test for and retrieve validation errors.
  • A redirectAttributes object so you can create a flash-scoped error message to show the user what went wrong in the event of an error.

You can retrieve all the attributes from the form bound to the Person object. In the code, you test for errors, and if so, add a flash attribute named error, and redirect the user back to the / page. If there are no errors, you return the results template.

Build an HTML front end

Now you build the "main" page.

src/main/webapp/form.html

<html>
	<body>
		<form action="#" th:action="@{/}" th:object="${person}" method="post">
			<table>
				<tr>
					<td>How old are you?</td>
					<td><input type="text" th:field="*{age}" /></td>
					<td><div id="errors" th:text="${error}" /></td>
				</tr>
				<tr>
					<td><button type="submit">Submit</button></td>
				</tr>
			</table>
		</form>
	</body>
</html>

The page contains a simple form with each field in a separate slot of a table. The form is geared to post towards /enterAge. It is marked as being backed up by the person object that you saw in the GET method in the web controller. This is known as a bean-backed form. There is only one field in the Person bean, and you can see it tagged with th:field="*{age}".

Right next to that entry field is a <div> with th:text="${error}". This gives you a place to insert an error message.

Finally, you have a button to submit. In general, if the user enters an age that violates the @Valid constraints, it will bounce back to this page with the error message on display. If a valid age is entered, the user is routed to the next web page.

src/main/webapp/results.html

<html>
	<body>
		Congratulations! You are old enough to sign up for this site.
	</body>
</html>

Note: In this simple example, these web pages don't have any sophisticated CSS JavaScript. But for any professional web sites, it's very valuable to learn how to style your web pages.

Create an Application class

For this application, you are using the template language of Thymeleaf. This application needs more than raw HTML.

src/main/java/hello/Application.java

package hello;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.thymeleaf.spring3.SpringTemplateEngine;
import org.thymeleaf.spring3.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {
    
    @Bean
    ServletContextTemplateResolver templateResolver() {
        ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
        resolver.setSuffix(".html");
        resolver.setTemplateMode("HTML5");
        return resolver;
    }
    
    @Bean
    SpringTemplateEngine engine() {
        SpringTemplateEngine engine = new SpringTemplateEngine();
        engine.setTemplateResolver(templateResolver());
        return engine;
    }
    
    @Bean
    ThymeleafViewResolver viewResolver() {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(engine());
        return viewResolver;
    }
    
    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
    
}

To activate Spring MVC, you would normally add @EnableWebMvc to the Application class. But Spring Boot's @EnableAutoConfiguration already adds this annotation when it detects spring-webmvc on your classpath. The application also has @ComponentScan to find the annotated @Controller class and its methods.

The extra beans shown in this configuration are used to wire up Thymeleaf and integrate it with Spring MVC. The first one takes view names, appends .html, and looks for that file in src/main/webapp/. The rest are used to perform proper resolution and rendering.

Build an executable JAR

Now that your Application class is ready, you simply instruct the build system to create a single, executable jar containing everything. This makes it easy to ship, version, and deploy the service as an application throughout the development lifecycle, across different environments, and so forth.

Below are the Gradle steps, but if you are using Maven, you can find the updated pom.xml right here and build it by typing mvn clean package.

Update your Gradle build.gradle file's buildscript section, so that it looks like this:

buildscript {
    repositories {
        maven { url "http://repo.spring.io/libs-snapshot" }
        mavenLocal()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:0.5.0.M4")
    }
}

Further down inside build.gradle, add the following to the list of applied plugins:

apply plugin: 'spring-boot'

You can see the final version of build.gradle [right here]((https://github.com/spring-guides/gs-validating-form-input/blob/master/complete/build.gradle).

The Spring Boot gradle plugin collects all the jars on the classpath and builds a single "über-jar", which makes it more convenient to execute and transport your service. It also searches for the public static void main() method to flag as a runnable class.

Now run the following command to produce a single executable JAR file containing all necessary dependency classes and resources:

$ ./gradlew build

If you are using Gradle, you can run the JAR by typing:

$ java -jar build/libs/gs-validating-form-input-0.1.0.jar

If you are using Maven, you can run the JAR by typing:

$ java -jar target/gs-validating-form-input-0.1.0.jar

Note: The procedure above will create a runnable JAR. You can also opt to build a classic WAR file instead.

Run the web application

If you are using Gradle, you can run your web application at the command line this way:

$ ./gradlew clean build && java -jar build/libs/gs-validating-form-input-0.1.0.jar

Note: If you are using Maven, you can run your web application by typing mvn clean package && java -jar target/gs-validating-form-input-0.1.0.jar.

The application should be up and running within a few seconds.

If you visit http://localhost:8080/, you should see something like this:

What happens if you enter 15 and click on Submit?

Here you can see that because it violated the constraints in the Person class, you get bounced back to the "main" page. If you click on Submit with nothing in the entry box, you get a different error.

If you enter a valid age, you end up on the results page!

Summary

Congratulations! You have coded a simple web application with validation built into a domain object. This way you can ensure the data meets certain criteria and that the user inputs it correctly.

About

Validating Form Input :: Learn how to perform form validation with Spring.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Shell 78.4%
  • Java 14.1%
  • Groovy 7.5%