using-lishys-notes.notes
Guide
The guide pane on the right contains information organized into sections.
Use the

and

buttons to move through the sections, or click an accordion tab (shown below) to go directly to a particular topic.

Code Reference
Each paragraph in the guide is usually associated with a particular piece of code. An orange arrow indicates that the code displayed in the middle pane is relevant to the guide text.

If the arrow is gray, simply click anywhere on the paragraph and the relevant code will be displayed.

Code Highlighter
The highlight feature identifies areas of the code which relate to a word or term in the guide. Hover the mouse over any underlined word and the relevant code will be highlighted.
You can disable the highlighting feature at any time by clicking on the

button.
Don't forget to make the appropriate code page visible by clicking on any paragraph with a gray arrow.
MyService.java
package lishy.forms.service;
import lishy.forms.MyDomainObject;
public interface MyService {
public void someBusinessLogic(MyDomainObject obj);
}
MyServiceImpl.java
package lishy.forms.service;
import static java.lang.System.out;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import lishy.forms.MyDomainObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MyServiceImpl implements MyService{
@Autowired
private Validator validator;
@Override
public void someBusinessLogic(MyDomainObject obj) {
Set<ConstraintViolation<MyDomainObject>> violations = validator.validate(obj);
System.out.println("Violation count: " + violations.size() + "\n");
for (ConstraintViolation<MyDomainObject> violation : violations) {
out.println(violation.getPropertyPath() + ": " + violation.getMessage());
}
}
}
MyFormController.java
package lishy.forms.web;
import java.math.BigDecimal;
import java.util.Date;
import javax.validation.Valid;
import lishy.forms.MyDomainObject;
import lishy.forms.MyDomainValidator;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
@Controller
@RequestMapping("/my-form")
@SessionAttributes("myDomainObject")
public class MyFormController {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.setDisallowedFields("id");
binder.registerCustomEditor(String.class, new StringTrimmerEditor(false));
binder.setRequiredFields("dateInThePast", "emailAddress");
}
@RequestMapping(method=RequestMethod.GET)
public MyDomainObject setUpForm(@RequestParam(value="id", required=false) Integer id) {
return id==null ? new MyDomainObject() :
new MyDomainObject(id, "abc", new BigDecimal(12345.67),
new Date(), "XYZ", "x@y.com");
}
@RequestMapping(params="save", method=RequestMethod.POST)
public String save(@Valid MyDomainObject domain,
BindingResult result,
SessionStatus status,
Model model) {
MyDomainValidator validator = new MyDomainValidator();
validator.validate(domain, result);
if (result.hasErrors()) {
validator.showBindingResults(result);
return "my-form";
}
status.setComplete();
model.addAttribute("status", "success!");
return "my-details";
}
}
MyDomainObject.java
package lishy.forms;
import java.math.BigDecimal;
import java.util.Date;
import javax.validation.constraints.Min;
import javax.validation.constraints.Past;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat;
import org.springframework.format.annotation.NumberFormat.Style;
public class MyDomainObject {
private Integer id;
@NotBlank(message="must be entered")
private String mandatoryValue;
@Min(50)
@NumberFormat(style=Style.CURRENCY)
private BigDecimal minimumValue;
@Past
@DateTimeFormat(style="SM")
private Date dateInThePast;
@Pattern(regexp="x.*",
flags=Pattern.Flag.CASE_INSENSITIVE,
message="must start with x or X")
private String regExp;
@Email
private String emailAddress;
public MyDomainObject () {}
public MyDomainObject(Integer id,
String mandatoryValue,
BigDecimal minimumValue,
Date dateInThePast,
String regExp,
String emailAddress) {
setId(id);
setMandatoryValue(mandatoryValue);
setMinimumValue(minimumValue);
setDateInThePast(dateInThePast);
setRegExp(regExp);
setEmailAddress(emailAddress);
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getMandatoryValue() {
return mandatoryValue;
}
public void setMandatoryValue(String mandatoryValue) {
this.mandatoryValue = mandatoryValue;
}
public BigDecimal getMinimumValue() {
return minimumValue;
}
public void setMinimumValue(BigDecimal minimumValue) {
this.minimumValue = minimumValue;
}
public Date getDateInThePast() {
return dateInThePast;
}
public void setDateInThePast(Date dateInThePast) {
this.dateInThePast = dateInThePast;
}
public String getRegExp() {
return regExp;
}
public void setRegExp(String regExp) {
this.regExp = regExp;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
}
MyDomainValidator.java
package lishy.forms;
import static java.lang.System.out;
import java.util.List;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
public class MyDomainValidator {
public void validate(MyDomainObject domain, Errors errors) {
if (domain.getMandatoryValue().equals(domain.getRegExp())) {
errors.reject("validation.global", "global error");
}
}
public void showBindingResults(BindingResult result) {
out.println("Global errors: " + result.getGlobalErrorCount());
List<ObjectError> global = result.getGlobalErrors();
for (ObjectError err : global) {
out.println(" " + err.getObjectName() + ", " + err.getCode());
}
out.println("Field errors: " + result.getFieldErrorCount());
List<FieldError> field = result.getFieldErrors();
for (FieldError err : field) {
out.println(" '" + err.getRejectedValue() +
"' in " + err.getField() +
", " + err.getCode() +
" (" + (err.isBindingFailure() ? "binding)" :
"validation)"));
}
out.println("Disallowed fields targeted: " +
result.getSuppressedFields().length);
String[] suppressed = result.getSuppressedFields();
for (int i = 0; i < suppressed.length; i++) {
out.println(" " + suppressed[i]);
}
}
}
my-details.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:url var="myForm" value="/app/my-form.html">
<html>
<body>
<h1>Forms</h1>
<p>
<a href="${myForm}">create</a>
</p>
<p>
<a href="${myForm}?id=321">update</a>
</p>
<p style="color:green">${status}</p>
</body>
</html>
my-form.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<c:url var="myForm" value="/app/my-form.html">
<c:url var="myDetails" value="/app/my-details.html">
<html>
<head>
<link rel="stylesheet" href="<c:url value=" /css/validation.css">" type="text/css"/>
</head>
<body>
<h1>Forms</h1>
<a href="${myDetails}">cancel</a>
<form:form modelAttribute="myDomainObject" action="${myForm}" method="post">
<form:errors cssClass="error" element="p">
<c:if test="${not empty myDomainObject.id}">
<p>Identifier: ${myDomainObject.id}</p>
</c:if>
<p>
Mandatory:
<form:input path="mandatoryValue">
<form:errors path="mandatoryValue" cssClass="error">
</p>
<p>
Minimum:
<form:input path="minimumValue">
<form:errors path="minimumValue" cssClass="error">
</p>
<p>
Date in the past:
<form:input path="dateInThePast">
<form:errors path="dateInThePast" cssClass="error">
</p>
<p>
Regular expression:
<form:input path="regExp">
<form:errors path="regExp" cssClass="error">
</p>
<p>
Email address:
<form:input path="emailAddress">
<form:errors path="emailAddress" cssClass="error">
</p>
<form:errors path="*" cssClass="error" element="p">
<button type="submit" name="save">
${(empty myDomainObject.id) ? 'create' : 'update'}
</button> ${status}
</form:form>
</body>
</html>
messages.properties
validation.global=Global validation (not related to a single field)
typeMismatch.myDomainObject.minimumValue=minimum value must be a valid number
typeMismatch.dateInThePast=this date must be valid
typeMismatch.int={0} must be a valid number
typeMismatch.java.util.Date={0} must be a valid date
typeMismatch={0} is not valid
required.myDomainObject.minimumValue=minimum value is required
required.dateInThePast=past date must be entered
required.int=you must specify a value for {0}
required.java.util.Date=this date must be entered
required={0} is mandatory
forms-servlet.xml
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.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="lishy.forms"/>
<mvc:view-controller path="/my-details.html" view-name="my-details"/>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp"/>
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
p:basename="/WEB-INF/messages/messages"/>
</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.4"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>forms</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>forms</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>app/my-details.html</welcome-file>
</welcome-file-list>
</web-app>
console.log
INFO: Global errors: 1
INFO: myDomainObject, validation.global
INFO: Field errors: 4
INFO: 'abc' in minimumValue, typeMismatch (binding)
INFO: 'xyz' in emailAddress, Email (validation)
INFO: '' in mandatoryValue, NotBlank (validation)
INFO: '' in regExp, Pattern (validation)
INFO: Disallowed fields targeted: 1
INFO: id