Saturday, 1 December 2018

Spring mvc: Custom form validation annotation

This is continuation to my previous post. In my previous posts, I explained how to validate the input using ‘javax.validation’ APIS.

In this post, I am going to show, how can you define a custom annotation and apply it on the model classes to validate the input.

Step 1: Create a custom annotation ‘ValidUserName’.
@Constraint(validatedBy = UserNameValidatior.class)
@Documented
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidUserName {
         String message() default "Please provide valid user name. User name must have more than 5 characters and < 15 and it shouldn't contain special characters other than _, -";

         Class<?>[] groups() default {};

         Class<? extends Payload>[] payload() default {};

}

As you observe the definition of the annotation ValidUserName, I specified the implementation class as UserNameValidator using Constraint annotation.

Step 2: Define the validator class ‘UserNameValidator.java’, that provides implementation to ‘ValidUserName’ annotation.

UserNameValidator.java
public class UserNameValidatior implements ConstraintValidator<ValidUserName, String> {
         private static final String USERNAME_PATTERN = "^[a-z0-9_-]{6,15}$";
         private static final Pattern pattern;

         static {
                  pattern = Pattern.compile(USERNAME_PATTERN);
         }

         @Override
         public boolean isValid(String userName, ConstraintValidatorContext context) {

                  if (userName == null) {
                           return false;
                  }

                  Matcher matcher = pattern.matcher(userName);
                  return matcher.matches();
         }

}

Step 3: Apply the annotation @ValidUserName on a field.
public class Student {

         @ValidUserName
         private String userName;
        
         .....
         .....
}

Find the below working example.

ValidUserName.java
package com.sample.myApp.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

import com.sample.myApp.validators.UserNameValidatior;

@Constraint(validatedBy = UserNameValidatior.class)
@Documented
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidUserName {
 String message() default "Please provide valid user name. User name must have more than 5 characters and < 15 and it shouldn't contain special characters other than _, -";

 Class<?>[] groups() default {};

 Class<? extends Payload>[] payload() default {};

}

HelloWorldController.java
package com.sample.myApp.controllers;

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.sample.myApp.model.Student;

@Controller
public class HelloWorldController {

 @RequestMapping("/registration")
 public String getRegistrationpage() {
  return "registration";
 }

 @RequestMapping("/registerMe")
 public ModelAndView getHelloMessage(@Valid @ModelAttribute("studentInfo") Student student,
   BindingResult bindingResult) {
  if (bindingResult.hasErrors()) {
   ModelAndView modelAndView = new ModelAndView("registration");
   return modelAndView;
  }

  ModelAndView modelAndView = new ModelAndView("welcome");

  modelAndView.addObject("message", "Dear User, your details are registered");

  return modelAndView;
 }

}

Student.java
package com.sample.myApp.model;

import java.util.Date;
import java.util.List;

import javax.validation.constraints.DecimalMax;

import com.sample.myApp.annotations.ValidUserName;

public class Student {

 @ValidUserName
 private String userName;

 @DecimalMax(value = "40")
 private int age;

 private List<String> hobbies;
 private Date dateOfBirth;

 public Date getDateOfBirth() {
  return dateOfBirth;
 }

 public void setDateOfBirth(Date dateOfBirth) {
  this.dateOfBirth = dateOfBirth;
 }

 public String getUserName() {
  return userName;
 }

 public void setUserName(String userName) {
  this.userName = userName;
 }

 public int getAge() {
  return age;
 }

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

 public List<String> getHobbies() {
  return hobbies;
 }

 public void setHobbies(List<String> hobbies) {
  this.hobbies = hobbies;
 }

}

UserNameValidator.java
package com.sample.myApp.validators;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import com.sample.myApp.annotations.ValidUserName;

public class UserNameValidatior implements ConstraintValidator<ValidUserName, String> {
 private static final String USERNAME_PATTERN = "^[a-z0-9_-]{6,15}$";
 private static final Pattern pattern;

 static {
  pattern = Pattern.compile(USERNAME_PATTERN);
 }

 @Override
 public boolean isValid(String userName, ConstraintValidatorContext context) {

  if (userName == null) {
   return false;
  }

  Matcher matcher = pattern.matcher(userName);
  return matcher.matches();
 }

}

Create registration.jsp, welcome.jsp files under WEB-INF/jsp folder.


registration.jsp
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<title>User Information Page</title>
</head>

<body>
 <h2 style="color:red;"><form:errors path="studentInfo.*" /></h2>

 <form method="post" action="/springdemo/registerMe" id="f1">
  <table>
   <tr>
    <td>User Name :</td>
    <td><input type="text" name="userName" value="" /></td>
   </tr>
   <tr>
    <td>Age :</td>
    <td><input type="text" name="age" value="" /></td>
   </tr>
   <tr>
    <td>Hobbies :</td>
    <td><select multiple name="hobbies">
      <option value="cricket">Cricket</option>
      <option value="chess">Chess</option>
      <option value="football">Football</option>
      <option value="tennis">Tennis</option>
    </select></td>
   </tr>
   
   <tr>
    <td>Date Of Birth</td>
    <td><input type="text" name="dateOfBirth" value="" /></td>
   </tr>
   <tr>
    <td><input type="submit" name="submit" value="submit"
     style="font-size: 18px;" /></td>
   </tr>
  </table>
 </form>

</body>
</html>

welcome.jsp
<%@ 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>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Hello World Spring Web MVC</title>
</head>
<body>
 <h1>${message}</h1>

 <h3>
  User Name : ${studentInfo.userName} <br /> 
  Age : ${studentInfo.age} <br />
  Hobbies: ${studentInfo.hobbies} <br />
  Date Of Birth: ${studentInfo.dateOfBirth}
 </h3>
</body>
</html>

Create HelloWorld-servlet.xml, studentMessages.properties, web.xml files under WEB-INF folder.


HelloWorld-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 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-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

 <mvc:annotation-driven />

 <context:component-scan
  base-package="com.sample.myApp" />

 <bean
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/WEB-INF/jsp/" />
  <property name="suffix" value=".jsp" />
 </bean>

 <bean id="messageSource"
  class="org.springframework.context.support.ReloadableResourceBundleMessageSource">

  <property name="basename" value="WEB-INF/studentMessages" />

 </bean>

</beans>

studentMessages.properties
DecimalMax.studentInfo.age={0} must be less than or equal to {1}

web.xml
<web-app id="WebApp_ID" version="2.4"
 xmlns="http://java.sun.com/xml/ns/j2ee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

 <display-name>Spring MVC Hello WorldApplication</display-name>

 <servlet>
  <servlet-name>HelloWorld</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
  <servlet-name>HelloWorld</servlet-name>
  <url-pattern>/</url-pattern>
 </servlet-mapping>

</web-app>

index.jsp
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<title>Welcome Page</title>
</head>

<body>
 <h3>Dear Student, click on below button to register yourself</h3>
 <form method="post" action="/springdemo/registration" id="f1">
  <input type="submit" name="submit" value="submit"
   style="font-size: 18px;" />
 </form>
</body>
</html>

Project structure looks like below.
Run the application on server, you can able to see below screen.
Click on submit button.
Enter some wrong information for username, age fields and click on submit button.





Previous                                                 Next                                                 Home

No comments:

Post a Comment