Skip to main content

Part 3 - Validation

In this episode, I will show in easy steps how to integrate Hibernate Validator - the reference implementation of JSR 303 - Bean Validation into our application. Hibernate Validator is already part of our application thanks to the inclusion of the relevant jar in the parent pom file. Let us add a simple validation into our domain object - Lead - let us not allow a blank for the first name. The modified Lead class is shown in Listing 1.

Listing 1 - Lead.java

package com.effectivcrm.domain;

import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;

import org.hibernate.envers.Audited;
import org.hibernate.validator.constraints.NotEmpty;

/**
* The persistent class for the leads database table.
*
*/
@Entity
@Table(name = "t_lead")
@Audited
public class Lead extends PersistentObject {
private static final long serialVersionUID = 1L;

@Getter @Setter
@NotEmpty
@Column(name = "first_name", length = 100)
private String firstName;

@Getter @Setter
@Column(name = "last_name", length = 100)
private String lastName;

@Getter @Setter
@Column(name = "opportunity_amount")
private double opportunityAmount;

@Getter @Setter
@Column(name = "converted")
private boolean converted;

@Getter @Setter
@Column(name = "description", length = 250)
private String description;

@Getter @Setter
@Column(name = "email", length = 100)
private String email;

@Getter @Setter
@Column(name = "mobile", length = 30)
private String mobile;

@Getter @Setter
@Column(name = "work_phone", length = 30)
private String workPhone;

@Getter @Setter
@Column(name="fax")
private String fax;

@Getter @Setter
@Embedded
private Address address;

}

 

Next we will have to modify our view to to handle the error. Note the modified listing around the first name field.

Listing 2 - createlead.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">

<head th:include="common :: headerFragment">

<title>effectiv:Home</title>

</head>

<body>

<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">

<div class="container-fluid">
<a class="btn btn-navbar" data-toggle="collapse"
data-target=".nav-collapse"> <span class="icon-bar"></span> <span
class="icon-bar"></span> <span class="icon-bar"></span>
</a> <a class="brand" href="#">Project name</a>
<div class="nav-collapse collapse">

<p class="navbar-text pull-right">
Logged in as <a href="#" class="navbar-link">Username</a>
</p>
<ul class="nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#contact">Contact</a></li>

</ul>
</div>
<!--/.nav-collapse -->
</div>
</div>
</div>

<div class="container-fluid">
<div class="row-fluid">
<div class="span3">

<div class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">Sidebar</li>
<li class="active"><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>

<li class="nav-header">Sidebar</li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>

<li><a href="#">Link</a></li>
<li class="nav-header">Sidebar</li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
<li><a href="#">Link</a></li>
</ul>

</div>
<!--/.well -->
</div>
<!--/span-->

<div class="span9">

<div class="well">

<form class="form-horizontal" action="#" th:action="@{/savelead}"
th:object="${lead}" method="post">

<h4>New Lead</h4>

<div class="form-actions">
<button type="submit" class="btn btn-primary">Save</button>
<button type="button" class="btn">Cancel</button>
</div>

<div class="row-fluid">

<div class="span4">
<div class="control-group" th:class="${#fields.hasErrors('firstName')}? 'control-group error'">
<label class="control-label" for="firstName">First Name</label>
<div class="controls">
<input type="text" th:field="*{firstName}"
placeholder="First Name"></input> <span
class="help-inline error"
th:if="${#fields.hasErrors('firstName')}"
th:errors="*{firstName}">First Name is required.</span>
</div>
</div>
</div>

<div class="span4">
<div class="control-group">
<label class="control-label" for="lastName">Last Name</label>
<div class="controls">
<input type="text" placeholder="Last Name"
th:field="*{lastName}"></input> <span class="help-inline"
th:if="${#fields.hasErrors('lastName')}"
th:errors="*{lastName}">Last Name is required.</span>

</div>
</div>
</div>
</div>

<div class="row-fluid">
<div class="span4">
<div class="control-group">
<label class="control-label" for="opportunityAmount">Opportunity
Amount</label>
<div class="controls">
<input type="text" placeholder="Opportunity Amount"
th:field="*{opportunityAmount}"></input> <span
class="help-inline"
th:if="${#fields.hasErrors('opportunityAmount')}"
th:errors="*{opportunityAmount}">Must be a valid
amount.</span>
</div>
</div>
</div>

<div class="span4">
<div class="control-group">
<label class="control-label" for="converted">Converted</label>
<div class="controls">
<input type="checkbox" disabled="true" th:field="*{converted}"></input>
</div>
</div>
</div>
</div>

<div class="row-fluid">
<div class="span4">
<div class="control-group">
<label class="control-label" for="email">Email</label>
<div class="controls">
<div class="input-prepend">
<span class="add-on"><i class="icon-envelope"></i></span> <input
type="text" placeholder="Email" th:field="*{email}"></input>
</div>
</div>
</div>
</div>

<div class="span4">
<div class="control-group">
<label class="control-label" for="mobile">Mobile</label>
<div class="controls">
<input type="text" placeholder="Mobile" th:field="*{mobile}"></input>
</div>
</div>
</div>
</div>

<div class="row-fluid">
<div class="span4">
<div class="control-group">
<label class="control-label" for="workPhone">Work Phone</label>
<div class="controls">
<input type="text" placeholder="Work Phone"
th:field="*{workPhone}"></input>
</div>
</div>
</div>

<div class="span4">
<div class="control-group">
<label class="control-label" for="fax">Fax</label>
<div class="controls">
<input type="text" placeholder="Fax" th:field="*{fax}"></input>
</div>
</div>
</div>
</div>

<div class="row-fluid">
<div class="span8">
<div class="control-group">
<label class="control-label" for="description">Description</label>
<div class="controls">

<textarea rows="4" cols="20" placeholder="Description"
th:field="*{description}"></textarea>
</div>
</div>
</div>
</div>

<hr></hr>
<h5>Address</h5>

<div class="row-fluid">
<div class="span4">
<div class="control-group">
<label class="control-label" for="city">City</label>
<div class="controls">

<input type="text" id="city" placeholder="City"
th:field="*{address.city}"></input>
</div>
</div>
</div>

<div class="span4">
<div class="control-group">
<label class="control-label" for="country">Country</label>
<div class="controls">
<input type="text" id="country" placeholder="country"
th:field="*{address.country}"></input>
</div>
</div>
</div>
</div>

<div class="row-fluid">
<div class="span4">
<div class="control-group">
<label class="control-label" for="postcode">Post Code</label>
<div class="controls">

<input type="text" id="postcode" placeholder="Post Code"
th:field="*{address.postcode}"></input>
</div>
</div>
</div>

<div class="span4">
<div class="control-group">
<label class="control-label" for="state">State</label>
<div class="controls">
<input type="text" id="state" placeholder="State"
th:field="*{address.state}"></input>
</div>
</div>
</div>
</div>

<div class="row-fluid">
<div class="span8">
<div class="control-group">

<label class="control-label" for="street">Street</label>
<div class="controls">

<textarea rows="4" cols="60" placeholder="Street"
th:field="*{address.street}"></textarea>
</div>
</div>

</div>
</div>

<div class="form-actions">
<button type="submit" class="btn btn-primary">Save</button>
<button type="button" class="btn">Cancel</button>
</div>
</form>
</div>

</div>
<!--/span-->

</div>
<!--/row-->

<hr></hr>

<footer>
<p>&copy; Company 2012</p>
</footer>

</div>
<!--/.fluid-container-->

<!-- Le javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="../assets/js/jquery.js"></script>
<script src="../assets/js/bootstrap-transition.js"></script>
<script src="../assets/js/bootstrap-alert.js"></script>
<script src="../assets/js/bootstrap-modal.js"></script>

<script src="../assets/js/bootstrap-dropdown.js"></script>
<script src="../assets/js/bootstrap-scrollspy.js"></script>
<script src="../assets/js/bootstrap-tab.js"></script>
<script src="../assets/js/bootstrap-tooltip.js"></script>
<script src="../assets/js/bootstrap-popover.js"></script>
<script src="../assets/js/bootstrap-button.js"></script>

<script src="../assets/js/bootstrap-collapse.js"></script>
<script src="../assets/js/bootstrap-carousel.js"></script>
<script src="../assets/js/bootstrap-typeahead.js"></script>

</body>
</html>

 

Last but not the least if there is a problem with binding the domain object from request we need to redirect it back to the original form page - createlead. This is handled int he controller as shown in Listing 3.

Listing 3 - SaveLeadController.java

package com.effectivcrm.controller;

import javax.validation.Valid;

import lombok.extern.slf4j.Slf4j;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import com.effectivcrm.domain.Lead;

@Controller
@Slf4j
public class SaveLeadController {

@RequestMapping("/savelead")
public String saveLead(@Valid Lead lead, BindingResult result){
log.info("Lead for saving = {}", lead);
if (result.hasErrors()) {
return "createlead";
} else {
return "Done";
}
}

}

In the next post, I will create the page for listing of leads and then move on to integrate Tiles, Spring Security and yes i18n. I intend to keep this application simple and I am fine with full page loads and keeping it away from Ajax at the moment.

Comments

Popular posts from this blog

Part 3 - Integrating Tiles, Thymeleaf and Spring MVC 3

In this post I will demonstrate how to integrate Apache Tiles with Thymeleaf. This is very simple. The first step is to include the tiles and thymeleaf-tiles extension dependencies. I will include them in the pom.xml. Note we wil lbe using Tiles 2.2.2 Listing 1 - parent/pom.xml --- thymeleaf-tiles and tiles dependencies <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <!-- Tiles --> <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <dependency> <groupId>org.apache.tiles</groupId> <artifactId>tiles-core</artifactId> <version>${tiles.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.apache.tiles</groupId> <artifactId>tiles-template</artifactId> <version>${tiles.version}</version> <scope>compile</s...

CKEDITOR 3.x - Simplest Ajax Submit Plugin

  I have assumed that you have downloaded and got started with CKEDITOR. Step 1 – The html file is shown below: <html> <head> <title>Writer</title> <meta content="text/html; charset=utf-8" http-equiv="content-type" /> <script type="text/javascript" src="ckeditor/ckeditor.js"></script> <script type="text/javascript" src="js/jquery-1.4.2.min.js"></script> <style> .cke_contents { height: 400px !important; } </style> </head> <body> <form action="sample_posteddata.php" method="post"> <textarea id="editor" > </textarea> <script type="text/javascript"> //<![CDATA[ CKEDITOR.replace( 'editor', { fullPage : true, uiColor : '#9AB8F3', toolbar : 'MyToolbar' }); //]]> </script> </form> </body> </html> Note that the jquery js...

Getting started with Prime faces 2

Prime faces is an amazing JSF framework from Cagatay Civici ( http://cagataycivici.wordpress.com/ ). Its wonderful because it is easy to use, minimal dependencies, has probably the widest set of controls among all JSF frameworks, easy to integrate with Spring (including Spring Security) , Java EE EJBs, and last but not the least mobile UI support. So I decided to give Prime faces a try, before selecting it to use in my projects. Step 1 – Create Maven 2 project As a first step to integrating Prime faces, create a Maven 2 project in Eclipse. You will need to select ‘maven-archetype-webapp’. Step 2 – Add repositories and dependencies in pom.xml I will be using Prime faces 2 with JSF 2 on Tomcat 6. Since the dependencies for Prime Faces and JSF 2 (JSF 2.0.3 is required) are available on different repositories, I will add them to my pom file first. The listing below shows my pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/X...