Spencer Uresk

44
Spring MVC, Part 3 Spencer Uresk

description

Spring MVC, Part 3. Spencer Uresk. Notes. This is a training, NOT a presentation Please ask questions This is being recorded https://tech.lds.org/wiki/Java_Stack_Training Prerequisites Spring MVC 1 and 2. Objectives. Learn the basics of data binding - PowerPoint PPT Presentation

Transcript of Spencer Uresk

Page 1: Spencer  Uresk

Spring MVC, Part 3Spencer Uresk

Page 2: Spencer  Uresk

Notes

• This is a training, NOT a presentation• Please ask questions• This is being recorded• https://tech.lds.org/wiki/Java_Stack_Training• Prerequisites

– Spring MVC 1 and 2

Page 3: Spencer  Uresk

Objectives

• Learn the basics of data binding• Be able to write your own conversion service• Save time by using Spring’s form tags• Be able to validate your model objects in an easy,

reusable way

Page 4: Spencer  Uresk

Data Binding

• Binding is the way in which request parameters get turned into model objects

• Properties get set based on their names

/echo/person?name=Spencer&age=5

@RequestMapping("/echo/person")public @ResponseBody String doSomething(Person person) {

return person.getName();}

public class Person {private String name;private int age;// Getters and Setters

}

Page 5: Spencer  Uresk

Properties

• name - getName()/setName()• person.name –

getPerson().getName()/getPerson().setName()• person[1] – The first person in an array, list, or

other ordered collection named person.• people[BOB] – The value of the map entry

indexed by the key BOB in the Map people.

Page 6: Spencer  Uresk

Demo

DEMO

Page 7: Spencer  Uresk

ConversionService

• Since all parameters are Strings, how do they get turned into non-String values?

• How do they get turned back into Strings for display on the page?

• Spring’s ConversionService• Takes a type S and returns type T• Spring MVC comes with a lot of these pre-

configured, but you can add your own

Page 8: Spencer  Uresk

Some pre-configured converters

• String to Boolean• String to Number (ie, int, long, etc..)• String to Date• String to Locale• String to Enum• (and vice-versa for all of these)• Doesn’t always have to include a String on one

side

Page 9: Spencer  Uresk

Adding new Converters

• Figure out what source you want to use (S)• Figure out what the target type should be (T)• Implement the Converter<S, T> interfacepublic class BigIntNumberConverter implements Converter<String, BigInteger> {

public BigInteger convert(String source) {return new BigInteger(source);

}

}

Page 10: Spencer  Uresk

Custom Converter

• Add some configuration to tell Spring MVC to use a custom conversion service

• Add some configuration to your Spring MVC config to tell Spring MVC about your converter

<mvc:annotation-driven conversion-service="conversionService"/>

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="org.lds.view.BigIntNumberConverter" /> </set> </property></bean>

Page 11: Spencer  Uresk

Field Formatting

• Conversions are useful when just converting from one type of data to another

• Field formatting can be useful for when there is actual formatting that needs to occur

• Number and Date formatters are built in (Date formatters require Joda time)

public class Person {

@NumberFormat(style=Style.CURRENCY)private BigDecimal salary;

}

Page 12: Spencer  Uresk

What about errors?

• What happens if you put ‘asdf’ in a number field?• A conversion error occurs• Which throws an exception• You can tell Spring to add that error to an Errors

object to more gracefully deal with conversion errors

Page 13: Spencer  Uresk

Errors

• Errors holds a list of errors that apply to a model object

• Allows you to deal with binding (and other) errors yourself

• Must be positioned immediately after the model object in the parameter list

• Also used for Validation errors• BindingResult extends Errors and contains more

information about the model object itself

Page 14: Spencer  Uresk

Customizing Error Messages

• Default error messages are long and ugly• Customize them by adding properties to your

message bundle• By target type:

– typeMismatch.java.lang.Long={0} must be a number.– typeMismatch.int=Must be a number.

• Note primitives are different than their wrappers• Globally:

– typeMismatch=You entered something in wrong.

Page 15: Spencer  Uresk

Displaying Error Messages

• Add a <spring:hasBindErrors /> tag for your model object

• It makes an errors variable available that has a list of all error messages

• You choose how to display the actual messages<spring:hasBindErrors name="person">

The following errors were found:<br /><br /><ul>

<c:forEach items="${errors.allErrors}" var="error"><li><spring:message message="${error}"/></li>

</c:forEach></ul>

</spring:hasBindErrors>

Page 16: Spencer  Uresk

Demo

DEMO

Page 17: Spencer  Uresk

Lab 1

• Create a model object that we’ll use for data binding

• Populate its values by adding parameters to the query string

• Create a simple form to do the same• Customize the conversion error messages

Page 18: Spencer  Uresk

Spring’s form tag library

• Binding-aware JSP tags for handling form elements

• Integrated with Spring MVC to give the tags access to the model object and reference data

• Comes from spring-webmvc.jar• Add the following to make the tags available:

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

Page 19: Spencer  Uresk

The form tag

• Renders a form tag and exposes the binding to inner tags

• You can specify any HTML attributes that are valid for an HTML form

• You can also tell it what the form backing object is (it uses ‘command’ by default).

Page 20: Spencer  Uresk

The form tag - Example

<form:form method=”get” commandName=”person”><form:input path=”name” />

</form:form>

<form method=”get”><input type=”text” name=”name” />

</form>

@RequestMapping("/person/add")public String addPerson(Model model) {

Person person = new Person();model.addAttribute(person);return "addPerson";

}

Page 21: Spencer  Uresk

The input tag

• Renders an HTML input tag with a type of ‘text’• You can specify any HTML attributes valid for an

HTML input• You bind it to your model object by specifying the

path relative to the backing object

Page 22: Spencer  Uresk

The input tag - Example

<form:form method=”get” commandName=”person”><form:input path=”name” />

</form:form>

<form method=”get”><input type=”text” name=”name” value=”Spencer” />

</form>

@RequestMapping("/person/add")public String addPerson(Model model) {

Person person = new Person();person.setName(”Spencer”);model.addAttribute(person);return "addPerson";

}

Page 23: Spencer  Uresk

The checkbox tag

• Renders an HTML input tag with a type of ‘checkbox’

<form:form commandName=”person”><form:checkbox path=”admin” /><form:checkbox path=“languages” value=“Java” /><form:checkbox path=“languages” value=“Scala” /></form:form>

<form><input type=”checkbox” name=”admin” value=”true” /><input type=”checkbox” name=”languages” value=”Java” /><input type=”checkbox” name=”languages” value=”Scala” /></form>

public class Person {private boolean admin;private String[] languages;

}

Page 24: Spencer  Uresk

The checkboxes tag

• Similar to checkbox tag, but creates multiple checkboxes instead of one

<form:form commandName=”person”><form:checkbox path=”admin” /><form:checkboxes path=”favoriteLanguages” items=”${allLanguages}” /></form:form>

<form><input type=”checkbox” name=”admin” value=”true” /><input type=”checkbox” name=” favoriteLanguages” value=”Java” /><input type=”checkbox” name=” favoriteLanguages” value=”Scala” /></form>

public class Person {private boolean admin;private String[] favoriteLanguages;private List<String> allLanguages;

}

Page 25: Spencer  Uresk

The password tag

• Renders an HTML input tag with a type of ‘password’

<form:form><form:input path=”username” /><form:password path=”password” />

</form:form>

<form><input type=”text” name=”username” /><input type=”password” name=”password” />

</form>

Page 26: Spencer  Uresk

The select tag

• Renders an HTML select tag• It can figure out whether multiple selections

should be allowed• You can bind options using this tag, as well as by

nesting option and options tags<form:select path=”favoriteLanguage” items=”${allLanguages}” />

<select name=”favoriteLanguage”><option value=”Java”>Java</option><option value=”Scala”>Scala</option>

</form>

Page 27: Spencer  Uresk

The option/options tags

• Renders an HTML option (or multiple options)• Nested within a select tag• Renders ‘selected’ based on the value bound to

the select tag<form:select path=”favoriteLanguage”>

<form:option value=”3” label=”.NET” /><form:options items=”${languages}” itemValue=”id”

itemLabel=”name” /></form:select>

<select name=”favoriteLanguage”><option value=”.NET”>.NET</option><option value=”Java”>Java</option><option value=”Scala”>Scala</option>

</form>

Page 28: Spencer  Uresk

The errors tag

• Renders an HTML span tag, containing errors for given fields

• You specify which fields to show errors for by specifying a path– path=“name” – Would display errors for name field.– path=“*” – Would display all errors

<form:errors path=”*” cssClass=”errorBox” /><form:errors path=”name” cssClass=”specificErrorBox” />

<span name=”*.errors” class=”errorBox”>Name is required.</span><span name=“name.errors” class=“specificErrorBox”>Name is required.</span>

Page 29: Spencer  Uresk

Demo

DEMO

Page 30: Spencer  Uresk

Lab 2

• Rewrite our form from Lab 1 to use Spring’s taglib

• Add in some errors tags to handle conversion errors

• Add a favorite language checkbox

Page 31: Spencer  Uresk

Validation

• Spring supports a number of different types of validation

• Validation shouldn’t be tied to the web tier• Should be easy to localize• Should be easy to plug in any validator• Spring MVC’s validation support provides all of

these attributes

Page 32: Spencer  Uresk

Validator interface

• org.springframework.validation.Validator

• supports – Returns a boolean indicating whether or not the target class can be validated by this validator

• validate – In charge of actually performing validation. Validation errors should be reported by adding them to the errors object.

public interface Validator {boolean supports(Class<?> clazz);void validate(Object target, Errors errors);

}

Page 33: Spencer  Uresk

Validator Example

public class PersonValidator implements Validator {

/** * This Validator validates just Person instances */ public boolean supports(Class clazz) { return Person.class.equals(clazz); }

public void validate(Object obj, Errors e) { ValidationUtils.rejectIfEmpty(e, "name", "name.empty"); Person p = (Person) obj; if (p.getAge() < 0) { e.rejectValue("age", "negativevalue"); } else if (p.getAge() > 110) { e.rejectValue("age", "too. old"); } }}

Page 34: Spencer  Uresk

Invoking our Validator

• We can invoke our Validator in our controller code

@RequestMapping(value = "/person/add", method = RequestMethod.POST)public String createPerson(Person person, Errors errors) {

PersonValidator pv = new PersonValidator();ValidationUtils.invokeValidator(pv, person, errors);

if(errors.hasErrors()) {return "addPerson";

}

return "viewPerson";}

Page 35: Spencer  Uresk

JSR-303 Bean Validator API

• We use the Hibernate Validator implementation of this API

• Standardizes validation metadata and declaration• To use it, you annotate model properties with

validation annotations• A number of useful built-in annotations are

available• You can also make your own (outside the scope

of this training)

Page 36: Spencer  Uresk

Some Examples

• What are we validating here?– Length of ‘name’ is between 3 and 7 chars (inclusive)– Age is between 0 and 120 (inclusive)

@Size(min=3, max=7)private String name;

@Max(value=120)@Min(0)private Integer age;

Page 37: Spencer  Uresk

Custom error messages

• Each validation error has an error message• How do we override it?• 1. Change the global message for that validator

• 2. Manually pass in a message

• 3. Define and use a specific property

javax.validation.constraints.Min.message=Value must be at least {value}

@Size(min=3, max=7, message = "Your name must be between 3 and 7 characters.")

@Max(value=120, message="{age.too.old}") // Annotationage.too.old=Age must be under 120.// Message bundle property

Page 38: Spencer  Uresk

Demo

DEMO

Page 39: Spencer  Uresk

Configuration

• How do we tell Spring we want to use JSR-303 validation?

• It is already done in the Stack• First, configure a validator in the main

applicationContext (remember, this is reusable across tiers!)

• Then, tell Spring MVC to use that validator

Page 40: Spencer  Uresk

Configuration

• applicationContext.xml (we’re also telling it to use our messageSource bean to find messges)

• *-servlet.xml

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"><property name="validationMessageSource" ref="messageSource"/>

</bean>

<mvc:annotation-driven validator="validator" />

Page 41: Spencer  Uresk

Validating Controller Input

• In Spring MVC, we can automatically validate controller inputs

• Causes person to be validated, will throw validation exceptions

• Allows us to gracefully handle validation errors

public String createPerson(@Valid Person person) {}

public String createPerson(@Valid Person person, Errors errors) {if(errors.hasErrors()) { return "addPerson"; }return "viewPerson";

}

Page 42: Spencer  Uresk

@Valid

• In theory, it should also work on parameters annotated with @RequestBody

• But it doesn’t• It will, however, work in Spring 3.1

Page 43: Spencer  Uresk

Lab 3

• Validate our person object• Make sure they supply a name that is at least 3

characters• Make sure they supply an age between 0 and 125• Customize the error messages