SlideShare ist ein Scribd-Unternehmen logo
1 von 173
Spring MVC - Web forms
Ilio Catallo - info@iliocatallo.it
Outline
• First principles
• Data binding
• Data valida3on
• The PRG pa:ern
• References
First principles
Handling user input
Web apps o)en have to perform some logic against one or more
pieces of informa(on coming from the user
User User's
interaction +-------------+ information +-------------+
| | | |
+--------------> Browser +-------------------> Web app |
| | | |
+-------------+ +-------------+
Request parameters
This informa,on is made available through the request parameters
HTTP request
+-------------+
User | Request |
interaction +-------------+ | parameters | +-------------+
| | +-------------+ | |
+--------------> Browser +---------------------> Web app |
| | | |
+-------------+ +-------------+
Request parameters
Request parameters are sent as part of the HTTP request message
issued by the client
HTTP request
+-------------+
User | Request |
interaction +-------------+ | parameters | +-------------+
| | +-------------+ | |
+--------------> Browser +---------------------> Web app |
| | | |
+-------------+ +-------------+
Request parameters
Request parameters can be transferred as part of
• The query string
• The HTTP en1ty body
Request parameters
Request parameters can be transferred as part of
• The query string
• The HTTP en)ty body
Query string
Request parameters are specified as a sequence of URL
parameters appended to the request URL
http://my.server/resource?par1=val1&par2=val2
<----------------->
URL parameters
Query string
In other words, request parameters are appended to the
query string
http://my.server/resource?par1=val1&par2=val2
<----------------->
query string
HTTP request
HTTP request
+--------------------------------------+
| GET /webapp/greeting?name=Jon |
| &surname=Snow |
+--------------------------------------+
| |
| Host: myserver.com |
| User-Agent: ... |
| Accept-Encoding: ... |
| |
+--------------------------------------+
Gree$ng by name
Assume that we want our applica2on to be able to accept the
name and the surname of the user to greet
Gree$ng by name
In order to do so, we first provide an addi1onal overload of
getRandomGreeting()
public interface GreetingService {
public String getRandomGreeting();
public String getRandomGreeting(String name, String surname);
}
Parsing request parameters
Second, we need a mechanism for parsing the HTTP request so as
to extract the related request parameters
HTTP request
+--------------------------------------+
| GET /webapp/greeting?name=Jon |
| &surname=Snow |
+--------------------------------------+
| |
| Host: myserver.com |
| User-Agent: ... |
| Accept-Encoding: ... |
| |
+--------------------------------------+
@RequestParam
One such mechanism is the @RequestParam annota.on
HTTP request
+--------------------------------------+
| GET /webapp/greeting?name=Jon |
| &surname=Snow |
+--------------------------------------+
| |
| Host: myserver.com |
| User-Agent: ... |
| Accept-Encoding: ... |
| |
+--------------------------------------+
@RequestParam
The @RequestParam annota)on binds request parameters to
method parameters
@RequestMapping("/custom-greeting")
public String getGreeting(@RequestParam("name") String name,
@RequestParam("surname") String surname,
Model model) { ... }
Request vs. method parameters
The name request parameter binds to the name method parameter
@RequestMapping("/custom-greeting")
public String getGreeting(@RequestParam("name") String name,
@RequestParam("surname") String surname,
Model model) { ... }
Request vs. method parameters
The surname request parameter binds to the surname method
parameter
@RequestMapping("/custom-greeting")
public String getGreeting(@RequestParam("name") String name,
@RequestParam("surname") String surname,
Model model) { ... }
@RequestParam
We can now add an addi+onal overload of getGreeting() and
associate it with the /custom-greeting endpoint
public class GreetingController {
@RequestMapping("/greeting")
public String getGreeting(Model model) { ... }
@RequestMapping("/custom-greeting")
public String getGreeting(@RequestParam("name") String name,
@RequestParam("surname") String surname,
Model model) { ... }
}
getGreeting()
@RequestMapping("/custom-greeting")
public String getGreeting(@RequestParam("name") String name,
@RequestParam("surname") String surname,
Model model) {
String greeting = service.getRandomGreeting(name, surname);
model.addAttribute("greeting", greeting);
return "greeting";
}
Required by default
Request parameters specified using @RequestParam are required
by default
URL templates
To trigger the execu-on of getGreeting(), we should construct
a URL according to the following URL template
http://myserver.com/webapp/custom-greeting?name={name}
&surname={surname}
HTML forms
A possible way to construct URLs from a URL template is to use an
HTML form
<form action="..." method="...">
</form>
HTML forms
HTML forms are hypermedia controls that allow users to supply
data towards an applica7on endpoint
<form action="..." method="...">
</form>
HTML forms
We provide one text field per URL parameter, as well as a submit
bu3on
<form action="..." method="...">
<input type="text" name="name">
<input type="text" name="surname">
<button type="submit">Get your greeting!</button>
</form>
HTML forms
Since we want values to be sent as part of the query string, we
specify GET as the HTTP method
<form action="..." method="GET">
<input type="text" name="name">
<input type="text" name="surname">
<button type="submit">Get your greeting!</button>
</form>
HTML forms
Finally, we provide the endpoint where to send the parameters;
intui6vely we would like to do the following
<form action="/custom-greeting" method="GET">
<input type="text" name="name">
<input type="text" name="surname">
<button type="submit">Get your greeting!</button>
</form>
HTML forms
Since a single Web container may host several Web applica4ons,
the correct endpoint is /webapp/custom-greeting1
<form action="/webapp/custom-greeting" method="GET">
<input type="text" name="name">
<input type="text" name="surname">
<button type="submit">Get your greeting!</button>
</form>
1
Where webapp is the name of our Web applica4on
HTML forms
However, we would much prefer not to hard-code the name of the
Web applica7on
The <spring:url> tag
When using JSP as view technology, we can take advantage of the
<spring:url> tag
<spring:url value="/custom-greeting" var="customGreeting"/>
The <spring:url> tag
Given an URL, <spring:url> generates the corresponding
context-aware URL, which is then saved into a page variable
<spring:url value="/custom-greeting" var="customGreeting"/>
The <spring:url> tag
That is, links of the form /endpoint are automa2cally
transformed into links of the form /webapp/endpoint
/endpoint → /webapp/endpoint
HTML forms
The final HTML form thus reads
<spring:url value="/custom-greeting" var="customGreeting"/>
<form action="${customGreeting}" method="GET">
<input type="text" name="name">
<input type="text" name="surname">
<button type="submit">Get your greeting!</button>
</form>
The Spring tag library
The <spring:url> tag is part of the Spring tag library, which is
in turn part of Spring MVC
<spring:url value="/custom-greeting" var="customGreeting"/>
The Spring tag library
The Spring tag library can be imported into a JSP page by means of
the taglib direc8ve2
<%@ taglib prefix="spring"
uri="http://www.springframework.org/tags" %>
2
Remember that the taglib direc.ve does not actually load anything, we s.ll need to deploy the Spring tag library
together with the applica.on
Request parameters
Request parameters can be transferred as part of
• The query string
• The HTTP en1ty body
Request parameters
Request parameters can be transferred as part of
• The query string
• The HTTP en(ty body
En#ty body
The en&ty body is an op#onal part of HTTP messages
HTTP message
+----------------------------+
| Start line |
+----------------------------+
| |
| Headers |
| |
+----------------------------+
| |
| Entity body |
| |
+----------------------------+
En#ty body
Unlike the start line and the headers, the body can contain text or
binary data
HTTP message
+----------------------------+
| Start line |
+----------------------------+
| |
| Headers |
| |
+----------------------------+
| |
| Entity body |
| |
+----------------------------+
En#ty body
While any HTTP request is allowed to contain a body, some
servers will refuse to, e.g., process a GET request with a body3
3
One prominent example is Google (see references)
POST
The POST verb is among the HTTP verbs that explicitly admit the
presence of an en5ty body
HTTP message
+--------------------------------+
| POST /custom-greeting HTTP/1.1 |
+--------------------------------+
| |
| Content-Type: ... |
| |
+--------------------------------+
| |
| Entity body |
| |
+--------------------------------+
POST
As a ma&er of fact, the POST method is specifically designed to
send input data to the server
POSTing our gree-ng
+--------------------------------------------------+
| POST /webapp/custom-greeting HTTP/1.1 |
+--------------------------------------------------+
| Host: myserver.com |
| User-Agent: ... |
| Content-Type: application/x-www-form-urlencoded |
+--------------------------------------------------+
| name=Jon&surname=Snow |
| |
+--------------------------------------------------+
HTML form
As before, we can use an HTML form to issue a POST request
<spring:url value="/custom-greeting" var="customGreeting"/>
<form action="${customGreeting}" method="POST">
<input type="text" name="name"/>
<input type="text" name="surname"/>
<button type="submit">Get your greeting!</button>
</form>
HTML form
Since we want our parameters to be transferred as part of the
en4ty body, we specify POST as the HTTP method
<spring:url value="/custom-greeting" var="customGreeting"/>
<form action="${customGreeting}" method="POST">
<input type="text" name="name"/>
<input type="text" name="surname"/>
<button type="submit">Get your greeting!</button>
</form>
How can we decide between GET and POST requests?
"...the GET and HEAD methods SHOULD NOT have the significance of
taking an ac?on other than retrieval. These methods ought to be
considered "safe"."
(RFC 2616)
"This allows user agents to represent other methods, such as POST,
PUT and DELETE, in a special way, so that the user is made aware of
the fact that a possibly unsafe ac/on is being requested."
(RFC 2616)
"The important dis0nc0on here is that the user did not request the
side-effects, so therefore cannot be held accountable for them."
(RFC 2616)
Unsafe ac)ons
The user is accountable for the POST requests she executes, as
they represent unsafe ac-ons on the Web applica:on
Unsafe ac)ons
Unsafe ac)ons may alter the state of the Web applica)on. For
instance, causing external informa)on sent as form data to be
stored
Accountability
That’s why the browser informs us when we try to send again a
HTTP POST request
Data binding
HTML form vs. Web apps
HTML forms give users a place where to enter data
Text parameters
The browser sends the data up to the server as a list of name-value
pairs
+--------------------------------------------------+
| POST /webapp/custom-greeting HTTP/1.1 |
+--------------------------------------------------+
| Host: myserver.com |
| User-Agent: ... |
| Content-Type: application/x-www-form-urlencoded |
+--------------------------------------------------+
| name=Jon&surname=Snow |
| |
+--------------------------------------------------+
Text parameters
Everything is going to be transferred to the Web app as text
+--------------------------------------------------+
| POST /webapp/custom-greeting HTTP/1.1 |
+--------------------------------------------------+
| Host: myserver.com |
| User-Agent: ... |
| Content-Type: application/x-www-form-urlencoded |
+--------------------------------------------------+
| name=Jon&surname=Snow |
| |
+--------------------------------------------------+
HTML form vs. Web apps
But, what if...
• A field has to be interpreted as something different than a
String (e.g., as a Date)?
• The user forgets to provide a mandatory field? does she have to
re-type everything from scratch?
• We want to check that a field respects a given paDern?
HTML form vs. Web apps
But, what if...
• We need to perform data conversion?
• We need to perform data buffering?
• We need to perform data valida2on?
HTML form vs. Web apps
HTTP/HTML does not provide a component that can buffer,
validate4
and convert inputs coming from a form
4
Here, we are not considering HTML5 Constraint Valida8on API
HTML form vs. Web apps
When trying to solve these issues, HTML and HTTP are of no use
to us
HTML form vs. Web apps
This is how HTTP and HTML work, Web apps cannot control this
The "Sign-up" example
Let us assume that our Web applica2on requires the user to sign up
for a new account
The "Sign-up" example
To this end, we introduce:
• An annotated controller named AccountController
• A registra1on page
AccountController
@Controller
public class AccountController {
@RequestMapping("/account")
public String addAccount(...) { ... }
}
Registra)on form
<spring:url value="/account" var="account"/>
<form action="${account}" method="POST">
Name: <input type="text" name="name"/> <br/>
Surname: <input type="text" name="surname"/> <br/>
Email: <input type="text" name="email"/> <br/>
Birthday: <input type="text" name="birthday"/> <br/>
<button type="submit">Sign-up</button>
</form>
The Account bean
Once we get the data, we may want to store them in a JavaBean
public class Account {
private String name;
private String surname;
private String email;
private Date birthday;
// getters and setters
}
The Account bean
Which is the best way of moving from the request parameters to
the corresponding Account object?
+------------------------------------------------+
| POST /webapp/account HTTP/1.1 | public class Account {
+------------------------------------------------+
| Host: myserver.com | private String name;
| User-Agent: ... | private String surname;
| Content-Type: application/x-www-form-urlencoded| private String email;
+------------------------------------------------+ +-----> private Date birthday;
| name=Jon& |
| surname=Snow& | // getters and setters
| birthday=10-1-1956 | }
+------------------------------------------------+
The naïve solu-on
We could try to get each single request parameter individually
@RequestMapping("/account")
public String addAccount(@RequestParam("name") String name,
@RequestParam("surname") String surname,
@RequestParam("email") String email,
@RequestParam("birthday") Date birthday,
Model model) {
// we manually populate the Account object with
// the data coming from the user
Account a = new Account();
a.setName(name);
...
}
Method parameters in OOP
“The ideal number of arguments for a func5on is zero. Next comes one,
followed closely by two. Three arguments should be avoided where
possible. More than three requires very special jus5fica5on - and then
shouldn’t be used anyway.”
(B. Mar(n)
The naïve solu-on
By doing so, we effec/vely clu$ered the handler method signature
@RequestMapping("/account")
public String addAccount(@RequestParam("name") String name,
@RequestParam("surname") String surname,
@RequestParam("email") String email,
@RequestParam("birthday") Date birthday,
Model model) {
Account a = new Account();
a.setName(name);
...
}
Data binding
Wouldn’t it be great if data coming from the form could be
automa&cally bound to an Account object?
+------------------------------------------------+
| POST /webapp/account HTTP/1.1 | public class Account {
+------------------------------------------------+
| Host: myserver.com | private String name;
| User-Agent: ... | private String surname;
| Content-Type: application/x-www-form-urlencoded| private String email;
+------------------------------------------------+ +-----> private Date birthday;
| name=Jon& |
| surname=Snow& | // getters and setters
| birthday=10-1-1956 | }
+------------------------------------------------+
Data binding
Data binding is the process of binding the request parameters to a
so called form bean
public class Account {
private String name;
private String surname;
private String email;
private Date birthday;
// getters and setters
}
Data binding
The form bean is also called the form-backing bean, the form
object or the command object
public class Account { ... }
Data binding
It turns out that all we need to do is to declare an Account object
as a method parameter
@RequestMapping("/account")
public String addAccount(Account account) {
// account will be automatically populated
// with the request parameters
}
Data binding
The following sequence of opera3ons occurs:
• A new form bean is instan(ated
• The form bean is added to the model
• The form bean is populated from the request parameters
The form bean is a model a0ribute
The account form bean will be automa&cally added to the model
Model
+----------------+
| |
| account |
HTTP +-------------------+ +----------------+ +--------------------+
request | | | |
+--------> DispatcherServlet +----------------------> AccountController |
| | | |
+-------------------+ +--------------------+
The form bean is a model a0ribute
Hence, views can access and render the form bean content
Model Model
+--------------+ +--------------+
| | | |
| account | | account |
+----------+ +--------------+ +-------------------+ +--------------+ +--------------------+
| | | | | |
| View <--------------------+ DispatcherServlet <--------------------+ AccountController |
| | | | | |
+----------+ +-------------------+ +--------------------+
The form bean is a model a0ribute
<html>
<head>
<title>Thanks</title>
</head>
<body>
Hi, ${account.name} ${account.surname}.
You have successfully registered. <br/>
</body>
</html>
Default values
Assume that we want to ask the user for the permission of sending
marke&ng e-mails
Default values
To this end, we add a marketingOk property in the Account
form bean
public class Account {
private String name;
private String surname;
private String email;
private Date birthday;
private boolean marketingOk;
// getters and setters
}
Default values
By default, we would like the marketingOk property to be true
public class Account {
private String name;
private String surname;
private String email;
private Date birthday;
private boolean marketingOk = true;
// getters and setters
}
Prepopula)ng Account
As a ma&er of fact, we are prepopula(ng the Account bean
public class Account {
private String name;
private String surname;
private String email;
private Date birthday;
private boolean marketingOk = true;
// getters and setters
}
Showing prepopulated data
We want the registra-on page to use proper-es coming from a
prepopulated Account bean
+--------------------------------------+
| |
| +----------------------+ |
| Name: | | |
| +----------------------+ |
| |
| +----------------------+ |
| Surname: | | | +--------------+
| +----------------------+ | | |
| <----------+ Account bean |
| +----------------------+ | | |
| Date: | | | +--------------+
| +----------------------+ |
| |
| +-+ |
| |✓| Please send me product updates |
| +-+ |
| +-------------+ |
| | Sign-up! | |
| +-------------+ |
+--------------------------------------+
Showing prepopulated data
Recall that we can send data to the view through the model object
+--------------------------------------+
| |
| +----------------------+ |
| Name: | | |
| +----------------------+ |
| |
| +----------------------+ |
| Surname: | | | +--------------+
| +----------------------+ | | |
| <----------+ Account bean |
| +----------------------+ | | |
| Date: | | | +--------------+
| +----------------------+ |
| |
| +-+ |
| |✓| Please send me product updates |
| +-+ |
| +-------------+ |
| | Sign-up! | |
| +-------------+ |
+--------------------------------------+
Showing prepopulated data
What if we let the AccountController return a prepopulated
form bean as part of the model?
Model Model
+--------------+ +--------------+
| | | |
| account | | account |
+----------+ +--------------+ +-------------------+ +--------------+ +--------------------+
| | | | | |
| View <--------------------+ DispatcherServlet <--------------------+ AccountController |
| | | | | |
+----------+ +-------------------+ +--------------------+
AccountController
@Controller
public class AccountController {
@RequestMapping(value="/account/new", method=RequestMethod.GET)
public String getEmptyAccount(Model model) {
model.addAttribute(new Account());
return "account/new";
}
@RequestMapping(value="/account/new", method=RequestMethod.POST)
public String addAccount(Account account) { ... }
}
Data binding-aware forms
Once the prepopulated Account object is available in the view, we
need to bind its content to the Web form
+--------------------------------------+
| |
| +----------------------+ |
| Name: | | |
| +----------------------+ |
| |
| +----------------------+ |
| Surname: | | | +--------------+
| +----------------------+ | | |
| <----------+ Account bean |
| +----------------------+ | | |
| Date: | | | +--------------+
| +----------------------+ |
| |
| +-+ |
| |✓| Please send me product updates |
| +-+ |
| +-------------+ |
| | Sign-up! | |
| +-------------+ |
+--------------------------------------+
Spring form tag library
To deal with prepopulated form beans, Spring provides a set of
data binding-aware tags
The revised registra-on form
<form:form modelAttribute="account">
Name: <form:input path="name"/> <br/>
Surname: <form:input path="surname"/> <br/>
Email: <form:input path="email"/> <br/>
Birthday: <form:input path="birthday"/> <br/>
<form:checkbox path="marketingOk"/>
Please send me product updates via e-mail <br/>
<button type="submit">Sign-up<button/>
</form:form>
Form tags vs. HTML tags
┌───────────────────────────────────┬───────────────────────────┐
│ Spring form tag library │ HTML │
├───────────────────────────────────┼───────────────────────────┤
│ <form:form> │ <form> │
├───────────────────────────────────┼───────────────────────────┤
│ <input:text> │ <input type="text"> │
├───────────────────────────────────┼───────────────────────────┤
│ <input:password> │ <input type="password"> │
├───────────────────────────────────┼───────────────────────────┤
│ <input:checkbox> │ <input type="checkbox"> │
└───────────────────────────────────┴───────────────────────────┘
Spring form tags
The <form:input>, <form:password> and
<form:checkbox> tags are data-binding versions of the
corresponding HTML elements
Spring form tags
The tag library does not provide anything for submit bu(ons, as
there is nothing to bind to
<button type="submit">Sign-up<button/>
Spring form tag library
To use the tags from the form library, the following direc7ve needs
to be added at the top of the JSP page:
<%@ taglib prefix=”form"
uri="http://www.springframework.org/tags/form" %>
Data valida)on
Users make mistakes
No ma&er how intui/ve the registra/on form, users will
accidentally fill it out with invalid informa,on
+--------------------------------------+
| |
| +----------------------+ |
| Name: | | |
| +----------------------+ |
| |
| +----------------------+ |
| Surname: | | |
| +----------------------+ |
| |
| +----------------------+ |
| Date: | | |
| +----------------------+ |
| |
| +-+ |
| |✓| Please send me product updates |
| +-+ |
| +-------------+ |
| | Sign-up! | |
| +-------------+ |
+--------------------------------------+
Users make mistakes
When this happens, we want to explain the error in nontechnical
language and help the users to overcome it
+--------------------------------------+
| |
| +----------------------+ |
| Name: | | |
| +----------------------+ |
| |
| +----------------------+ |
| Surname: | | |
| +----------------------+ |
| |
| +----------------------+ |
| Date: | | |
| +----------------------+ |
| |
| +-+ |
| | | Please send me product updates |
| +-+ |
| +-------------+ |
| | Sign-up! | |
| +-------------+ |
+--------------------------------------+
Data valida)on
To detect user’s errors, we need to validate the form data that are
encapsulated in the form bean
public class Account {
private String name;
private String surname;
private String email;
private Date birthday;
private boolean marketingOk = true;
// getters and setters
}
Data valida)on
Example: the email property should respect the pa/ern
username@provider.tld
public class Account {
private String name;
private String surname;
private String email;
private Date birthday;
private boolean marketingOk = true;
// getters and setters
}
Bean Valida*on API
The Bean Valida*on API (JSR-303) is a specifica3on that defines a
metadata model and API for JavaBean valida3on
Bean Valida*on API
Using this API, it is possible to annotate bean proper4es with
declara*ve valida*on constraints
• @NotNull, @Pattern, @Size
Constraining Account
public class Account {
@Pattern(regexp="^[A-Z]{1}[a-z]+$")
@Size(min=2, max=50)
private String name;
@Pattern(regexp="^[A-Z]{1}[a-z]+$")
@Size(min=2, max=50)
private String surname;
@NotNull
@Email
private String email;
@NotNull
private Date birthday;
}
Constraining Account
We impose name and surname to start with a capital le2er and
have at least one addi4onal lowercase le2er
public class Account {
@Pattern(regexp="^[A-Z]{1}[a-z]+$")
@Size(min=2, max=50)
private String name;
@Pattern(regexp="^[A-Z]{1}[a-z]+$")
@Size(min=2, max=50)
private String surname;
}
Constraining Account
We impose email to respect the username@provider.tld
pa.ern
public class Account {
@NotNull @Email
private String email;
}
Hibernate Validator
As with any other Java Enterprise Edi3on API, the standard defines
only the API specifica,on
Hibernate Validator
We are going to use Hibernate Validator, which is the reference
implementa5on of the JSR-303 specifica5on
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.3.Final</version>
</dependency>
Custom annota*ons
Along with the standard constraints, Hibernate Validator provides
some custom annota*ons (e.g., @Email)
public class Account {
@Email
private String email;
}
Custom annota*ons
Remember: those annota)ons are Hibernate-specific and they will
not work with any other JSR-303 implementa)on
public class Account {
@Email
private String email;
}
Valida&ng account
Valida&on is achieved through the @Valid annota&on
@RequestMapping(...)
public String addAccount(@Valid Account account) { ... }
Valida&ng account
The @Valid annota)on causes the account object to be first
validated and then added to the model
@RequestMapping(...)
public String addAccount(@Valid Account account) { ... }
Valida&ng account
The handler method may ask for a BindingResult object, which
represent th result of the valida9on process
@RequestMapping(...)
public String addAccount(@Valid Account account,
BindingResult bindingResult) { ... }
Valida&ng account
We can then inspect the bindingResult object for possible
valida&on errors
@RequestMapping(...)
public String addAccount(@Valid Account account,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) return "account/new";
...
}
Data buffering
Since the account bean is part of the model, it will be sent back
to the view even in case of errors
Model Model
+--------------+ +--------------+
| | | |
| account | | account |
+----------+ +--------------+ +-------------------+ +--------------+ +--------------------+
| | | | | |
| View <--------------------+ DispatcherServlet <--------------------+ AccountController |
| | | | | |
+----------+ +-------------------+ +--------------------+
Data buffering
Hence, the user is not forced to re-enter the data from scratch
when asked to correct her mistakes
+--------------------------------------+
| |
| +----------------------+ |
| Name: | Jon | |
| +----------------------+ |
| |
| +----------------------+ |
| Surname: | 1234 | |
| +----------------------+ |
| |
| +----------------------+ |
| Date: | | |
| +----------------------+ |
| |
| +-+ |
| | | Please send me product updates |
| +-+ |
| +-------------+ |
| | Sign-up! | |
| +-------------+ |
+--------------------------------------+
Data buffering
Hence, the user can correct her mistakes, while keeping the correct
data untouched
+--------------------------------------+
| |
| +----------------------+ |
| Name: | Jon | |
| +----------------------+ |
| |
| +----------------------+ |
| Surname: | 1234 | |
| +----------------------+ |
| |
| +----------------------+ |
| Date: | | |
| +----------------------+ |
| |
| +-+ |
| | | Please send me product updates |
| +-+ |
| +-------------+ |
| | Sign-up! | |
| +-------------+ |
+--------------------------------------+
Error messages
Even if we returned the ini.al form, we s.ll have to inform the user
on the reason why the data have been rejected
+--------------------------------------+
| |
| +----------------------+ |
| Name: | Jon | |
| +----------------------+ |
| |
| +----------------------+ | "Hey user, the
| Surname: | snow <----------+ surname should
| +----------------------+ | start with a
| | capital letter"
| +----------------------+ |
| Date: | | |
| +----------------------+ |
| |
| +-+ |
| | | Please send me product updates |
| +-+ |
| +-------------+ |
| | Sign-up! | |
| +-------------+ |
+--------------------------------------+
Error messages
To this end, the BindingResult object is automa&cally inserted
into the model and sent back to the view
Model Model
+--------------+ +--------------+
| account | | account |
+--------------+ +--------------+
|bindingResult | |bindingResult |
+----------+ +--------------+ +-------------------+ +--------------+ +--------------------+
| | | | | |
| View <--------------------+ DispatcherServlet <--------------------+ AccountController |
| | | | | |
+----------+ +-------------------+ +--------------------+
<form:errors>
Spring MVC provides the <form:errors> tag as part of the
Spring’s form tag library
<form:errors path="name"/>
<form:errors>
The <form:errors> tag renders in HTML error messages taken
from the BindingResult object
<form:errors>
<form:form modelAttribute="account">
Name: <form:input path="name"/> <form:errors path="name"/> <br/>
Surname: <form:input path="surname"/> <form:errors path="surname"/> <br/>
Email: <form:input path="email"/> <form:errors path="email"/> <br/>
...
</form:form>
User-centric error messages
Unfortunately, most of the default Hibernate validator error
messages are not par8cularly user-centric
User-centric error messages
For instance, @Pattern's default message shows a reference to
the regular expression to be respected
Message interpola.on
Message interpola.on is the process of crea-ng error messages
for violated Bean Valida-on constraints
+--------------------------------------+
| |
| +----------------------+ |
| Name: | | |
| +----------------------+ |
| |
| +----------------------+ |
| Surname: | | |
| +----------------------+ |
| |
| +----------------------+ |
| Date: | | |
| +----------------------+ |
| |
| +-+ |
| | | Please send me product updates |
| +-+ |
| +-------------+ |
| | Sign-up! | |
| +-------------+ |
+--------------------------------------+
Message interpola.on
We can define the message descriptor of each property through
the message a4ribute
public class Account {
@NotNull(message = "the email address cannot be empty")
@Email(message = "please provide a valid e-mail address")
private String email;
}
Message interpola.on
The problem with message a1ributes is that we are hard-coding
the error messages
public class Account {
@NotNull(message = "the email address cannot be empty")
@Email(message = "please provide a valid e-mail address")
private String email;
}
What if we want the messages to change according to, e.g., the user’s
locale?
Resource bundle
A be%er alterna+ve is to store the error messages in a separate file,
called the resource bundle
Resource bundle
By doing so, error messages can be updated independently of the
source code (and vice versa)
Resource bundle
We may devise the following resource bundle:
NotBlank.account.email=the email address cannot be empty
Email.account.email=please provide a valid e-mail address
NotNull.account.birthday=The date cannot be empty
Resource bundle
Spring’s conven.on dictates the following syntax for messages:
[ConstraintName].[ClassName].[FieldName]=[Message]
MessageSource
If we decide to externalize messages from the code, we need a
source from which to get the messages, i.e., a MessageSource
MessageSource
Specifically, in order to load messages from a resource bundle, we
need a ReloadableResourceBundleMessageSource bean
Adding a MessageSource
We therefore change frontcontroller-servlet.xml in order
to have the Spring DI Container load the MessageSource5
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:validationMessages" />
</bean>
5
Remember: the MessageSource bean must have the id equal to messageSource
Using message codes
We can now specify the message code in lieu of the message itself
public class Account {
@NotBlank(message = "{NotBlank.account.email}")
@Email(message = "{Email.account.email}")
private String email;
}
The PRG pa*ern
Duplicate submissions
Most of the )mes, form data are submi2ed as POST requests
+--------------+ +--------------+
| +------- POST --------> |
| Browser | | Web app |
| <------ 200 OK -------+ |
+--------------+ +--------------+
Duplicate submissions
What if the user presses refresh on the browser?
+--------------+ +--------------+
| +------- POST --------> |
| Browser | | Web app |
| <------ 200 OK -------+ |
+--------------+ +--------------+
Duplicate submissions
Since refreshing means resending the latest HTTP request, it will
cause the HTTP POST to be resubmi+ed
+--------------+ +--------------+
+-------> +------- POST --------> |
Refresh | | Browser | | Web app |
+-------+ <------ 200 OK -------+ |
+--------------+ +--------------+
Duplicate submissions
Given the unsafe nature of POST, resending the latest POST
request may lead to unwanted results
+--------------+ +--------------+
+-------> +------- POST --------> |
Refresh | | Browser | | Web app |
+-------+ <------ 200 OK -------+ |
+--------------+ +--------------+
The PRG pa*ern
The Post/Redirect/Get (PRG) pa/ern solves the duplicate
submission problem
The PRG pa*ern
According to the PRG pa2ern, the Web app should not immediately
return the outcome of the POST opera?ons
+--------------+ +--------------+
| +------- POST --------> |
| Browser | | Web app |
| <------ 200 OK -------+ |
+--------------+ +--------------+
The PRG pa*ern
Instead, the Web applica1on should answer with a redirect
response
+--------------+ +--------------+
| +------- POST --------> |
| Browser | | Web app |
| <--- 3xx REDIRECT ----+ |
+--------------+ +--------------+
The PRG pa*ern
This causes the client to automa/cally issue a new GET request, to
which the Web app finally answers with the actual content
+--------------+ +--------------+
| +------- GET -------> |
| Browser | | Web app |
| <------ 200 OK -------+ |
+--------------+ +--------------+
The PRG pa*ern
Thus, if the user refreshes the page, the GET request will be send,
instead of the original HTTP POST
+--------------+ +--------------+
+-------> +------- GET -------> |
Refresh | | Browser | | Web app |
+-------+ <------ 200 OK -------+ |
+--------------+ +--------------+
Redirec'ng
In order to force a redirect, it is sufficient to return the redirect
URL prefixed with the label redirect:
@RequestMapping(...)
public String addAccount(@Valid Account account,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) return "account/edit";
service.saveAccount(account);
return "redirect:/account/thanks";
}
Redirec'ng
The redirect: prefix is used as a special indica+on that a
redirect is needed
@RequestMapping(...)
public String addAccount(@Valid Account account,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) return "account/edit";
service.saveAccount(account);
return "redirect:/account/thanks";
}
Redirec'ng
Note that what follows redirect: is used as the redirect URL
@RequestMapping(...)
public String addAccount(@Valid Account account,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) return "account/edit";
service.saveAccount(account);
return "redirect:/account/thanks";
}
Redirec'ng
That is, /account/thanks has to be intended as
http://myserver.com/webapp/account/thanks
@RequestMapping(...)
public String addAccount(@Valid Account account,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) return "account/edit";
service.saveAccount(account);
return "redirect:/account/thanks";
}
View controllers
We need to associate a handler method with /account/thanks
@Controller
@RequestMapping("/account")
public class AccountController {
@RequestMapping("/thanks")
public String getThanks() { return "thanks"; }
}
View controllers
The sole responsibility of such a handler method would be to
return the /account/thanks view name
@RequestMapping("/thanks")
public String getThanks() { return "thanks"; }
View controllers
Star%ng from Spring 3, it is possible to declara've set up
controllers whose unique responsibility is to return a view name
View controllers
The following declares in frontcontroller-servlet.xml a
controller capable of answering to /account/thanks
<mvc:view-controller path="/account/thanks”
view-name="account/thanks"/>
Model life)me
As the model contains the data to be rendered by the view, its
life6me is limited by the request/response lifecycle
Model life)me
In other words, a new model object is created for each request
that hits DispatcherServlet
+-------+
HTTP | Model |
request +---------------------+ +-------+ +--------------+
| | | |
+-------> DispatcherServlet +-------------> Controller |
| | | |
+---------------------+ +--------------+
PRG pa'ern vs. model a'ributes
A redirect creates a new request, hence causing the model
a3ributes to be discarded
+--------------+ +--------------+
| +------- POST --------> |
| Browser | | Web app |
| <--- 3xx REDIRECT ----+ |
+--------------+ +--------------+
What if we want to retain some model a1ributes?
The flash scope
A possible solu+on is store a0ributes of interest in the flash scope
The flash scope
The flash scope works similarly to the session scope
+-----+ Request +-----+
| +----------------> | +--+-------+-+
| | | | | |
| | Response | | | F |
| <----------------+ | | l |
| B | | W | | a |
| r | Request | e | S | s |
| o +----------------> b | e | h |
| w | | | s | |
| s | Response | a | s | |
| e <----------------+ p +------ i | ------v--
| r | | p | o |
| | Request | | n |
| +----------------> | |
| | | | |
| | Response | | |
| <----------------+ +---------v---
+-----+ +-----+
The flash scope
The difference is that flash a&ributes are kept solely for the
subsequent request
+-----+ Request +-----+
| +----------------> | +--+-------+-+
| | | | | |
| | Response | | | F |
| <----------------+ | | l |
| B | | W | | a |
| r | Request | e | S | s |
| o +----------------> b | e | h |
| w | | | s | |
| s | Response | a | s | |
| e <----------------+ p +------ i | ------v--
| r | | p | o |
| | Request | | n |
| +----------------> | |
| | | | |
| | Response | | |
| <----------------+ +---------v---
+-----+ +-----+
The flash scope
Flash a'ributes are stored before the redirect and made available
as model a'ributes a2er the redirect
+-----+ Request +-----+
| +----------------> | +--+-------+-+
| | | | | |
| | Response | | | F |
| <----------------+ | | l |
| B | | W | | a |
| r | Request | e | S | s |
| o +----------------> b | e | h |
| w | | | s | |
| s | Response | a | s | |
| e <----------------+ p +------ i | ------v--
| r | | p | o |
| | Request | | n |
| +----------------> | |
| | | | |
| | Response | | |
| <----------------+ +---------v---
+-----+ +-----+
RedirectAttributes
A handler method can declare an argument of type
RedirectAttributes...
@RequestMapping(...)
public String addAccount(@Valid Account account,
BindingResult bindingResult,
RedirectAttributes redirectAttributes) {...}
RedirectAttributes
...and use its addFlashAttribute() method to add a.ributes in
the flash scope
@RequestMapping(...)
public String addAccount(@Valid Account account,
BindingResult bindingResult,
RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors()) return "account/new";
redirectAttributes.addFlashAttribute("account", account);
return ”redirect:/account/thanks”;
}
The "Thank you" page
account is accessible in the view, since it has been automa2cally
inserted into the next request model
<html>
<head>
<title>Thanks</title>
</head>
<body>
Hi, ${account.name} ${account.surname}.
You have been successfully registered. <br/>
</body>
</html>
Recap
Form beans
Form beans are versa&le objects, as they play different roles at the
same 1me
• Data binder
• Data buffer
• Data validator
Data binder
Developers can work with a trusty POJO and leave all the HTML/
HTTP issues to the framework
• Binding
• Coercion
Data buffer
The form bean is not the des0na0on of the input, but a buffer that
preserves the input un0l it can be validated and commi7ed to the
service layer
Data validator
Many fields must be the correct type before they can be processed
by the business logic
References
References
• Stackoverflow, GET vs. POST does it really ma;er?
• Stackoverflow, HTTP GET with request body
• R. Fielding, Introductory REST ArHcle
• IETF, Hypertext Transfer Protocol – HTTP/1.1 (RFC 2616)
• SpringSource, Spring Framework Reference
References
• SpringSource, Java-doc APIs
• Wikipedia, Post/Redirect/Get
• Wikipedia, Bean Valida@on
• Hibernate, Hibernate Validator reference guide
References
• Craig Walls, Spring in Ac1on (3rd ed.), Manning Publica1ons
• Willie Wheeler, Spring in Prac1ce, Manning Publica1ons
• T. N. Husted et al., Struts 1 In Ac1on, Manning Publica1ons

Weitere ähnliche Inhalte

Was ist angesagt?

Configure Webserver & SSL secure & redirect in SuSE Linux Enterprise
Configure Webserver & SSL secure & redirect in SuSE Linux EnterpriseConfigure Webserver & SSL secure & redirect in SuSE Linux Enterprise
Configure Webserver & SSL secure & redirect in SuSE Linux EnterpriseTola LENG
 
Configure proxy firewall on SuSE Linux Enterprise Server 11
Configure proxy firewall on SuSE Linux Enterprise Server 11Configure proxy firewall on SuSE Linux Enterprise Server 11
Configure proxy firewall on SuSE Linux Enterprise Server 11Tola LENG
 
Dhcp & dhcp relay agent in cent os 5.3
Dhcp & dhcp relay agent in cent os 5.3Dhcp & dhcp relay agent in cent os 5.3
Dhcp & dhcp relay agent in cent os 5.3Sophan Nhean
 
New text document (2)
New text document (2)New text document (2)
New text document (2)Furqaan Aan
 
Tola.leng mail server (sq_mail &amp; rcmail)_q5_
Tola.leng mail server (sq_mail &amp; rcmail)_q5_Tola.leng mail server (sq_mail &amp; rcmail)_q5_
Tola.leng mail server (sq_mail &amp; rcmail)_q5_Tola LENG
 
Basic command to configure mikrotik
Basic command to configure mikrotikBasic command to configure mikrotik
Basic command to configure mikrotikTola LENG
 
Configure Proxy and Firewall (Iptables)
Configure Proxy and Firewall (Iptables)Configure Proxy and Firewall (Iptables)
Configure Proxy and Firewall (Iptables)Tola LENG
 
DNS windows server(2008R2) & linux(SLES 11)
DNS windows server(2008R2) & linux(SLES 11)DNS windows server(2008R2) & linux(SLES 11)
DNS windows server(2008R2) & linux(SLES 11)Tola LENG
 
How to configure IPA-Server & Client-Centos 7
How to configure IPA-Server & Client-Centos 7How to configure IPA-Server & Client-Centos 7
How to configure IPA-Server & Client-Centos 7Tola LENG
 
Basic security &amp; info
Basic security &amp; infoBasic security &amp; info
Basic security &amp; infoTola LENG
 
Open vpn server_linux
Open vpn server_linuxOpen vpn server_linux
Open vpn server_linuxTola LENG
 
Marcive Documents: Catching Up and Keeping Up
Marcive Documents: Catching Up and Keeping UpMarcive Documents: Catching Up and Keeping Up
Marcive Documents: Catching Up and Keeping UpRoy Zimmer
 
Oauth2.0
Oauth2.0Oauth2.0
Oauth2.0iratao
 

Was ist angesagt? (15)

Configure Webserver & SSL secure & redirect in SuSE Linux Enterprise
Configure Webserver & SSL secure & redirect in SuSE Linux EnterpriseConfigure Webserver & SSL secure & redirect in SuSE Linux Enterprise
Configure Webserver & SSL secure & redirect in SuSE Linux Enterprise
 
Configure proxy firewall on SuSE Linux Enterprise Server 11
Configure proxy firewall on SuSE Linux Enterprise Server 11Configure proxy firewall on SuSE Linux Enterprise Server 11
Configure proxy firewall on SuSE Linux Enterprise Server 11
 
Dhcp & dhcp relay agent in cent os 5.3
Dhcp & dhcp relay agent in cent os 5.3Dhcp & dhcp relay agent in cent os 5.3
Dhcp & dhcp relay agent in cent os 5.3
 
New text document (2)
New text document (2)New text document (2)
New text document (2)
 
Tola.leng mail server (sq_mail &amp; rcmail)_q5_
Tola.leng mail server (sq_mail &amp; rcmail)_q5_Tola.leng mail server (sq_mail &amp; rcmail)_q5_
Tola.leng mail server (sq_mail &amp; rcmail)_q5_
 
Basic command to configure mikrotik
Basic command to configure mikrotikBasic command to configure mikrotik
Basic command to configure mikrotik
 
Configure Proxy and Firewall (Iptables)
Configure Proxy and Firewall (Iptables)Configure Proxy and Firewall (Iptables)
Configure Proxy and Firewall (Iptables)
 
DNS windows server(2008R2) & linux(SLES 11)
DNS windows server(2008R2) & linux(SLES 11)DNS windows server(2008R2) & linux(SLES 11)
DNS windows server(2008R2) & linux(SLES 11)
 
How to configure IPA-Server & Client-Centos 7
How to configure IPA-Server & Client-Centos 7How to configure IPA-Server & Client-Centos 7
How to configure IPA-Server & Client-Centos 7
 
Basic security &amp; info
Basic security &amp; infoBasic security &amp; info
Basic security &amp; info
 
Xb30330.xb30350 management guide
Xb30330.xb30350 management guideXb30330.xb30350 management guide
Xb30330.xb30350 management guide
 
Open vpn server_linux
Open vpn server_linuxOpen vpn server_linux
Open vpn server_linux
 
Marcive Documents: Catching Up and Keeping Up
Marcive Documents: Catching Up and Keeping UpMarcive Documents: Catching Up and Keeping Up
Marcive Documents: Catching Up and Keeping Up
 
Oauth2.0
Oauth2.0Oauth2.0
Oauth2.0
 
Eoip tunnel
Eoip tunnelEoip tunnel
Eoip tunnel
 

Andere mochten auch

Testing Spring MVC and REST Web Applications
Testing Spring MVC and REST Web ApplicationsTesting Spring MVC and REST Web Applications
Testing Spring MVC and REST Web ApplicationsSam Brannen
 
Struts 2 + Spring
Struts 2 + SpringStruts 2 + Spring
Struts 2 + SpringBryan Hsueh
 
Data Synchronization Patterns in Mobile Application Design
Data Synchronization Patterns in Mobile Application DesignData Synchronization Patterns in Mobile Application Design
Data Synchronization Patterns in Mobile Application DesignEric Maxwell
 
Authentication and Authorization
Authentication and AuthorizationAuthentication and Authorization
Authentication and AuthorizationTechMaster Vietnam
 
NetBeansでかんたんJava EE ○分間クッキング! #kuwaccho lt
NetBeansでかんたんJava EE ○分間クッキング! #kuwaccho ltNetBeansでかんたんJava EE ○分間クッキング! #kuwaccho lt
NetBeansでかんたんJava EE ○分間クッキング! #kuwaccho ltMasatoshi Tada
 
Building RESTful applications using Spring MVC
Building RESTful applications using Spring MVCBuilding RESTful applications using Spring MVC
Building RESTful applications using Spring MVCIndicThreads
 
Desenvolvimento Front end (AngularJS e Bootstrap)
Desenvolvimento Front end (AngularJS e Bootstrap)Desenvolvimento Front end (AngularJS e Bootstrap)
Desenvolvimento Front end (AngularJS e Bootstrap)Julian Cesar
 
JSP Standard Tag Library
JSP Standard Tag LibraryJSP Standard Tag Library
JSP Standard Tag LibraryIlio Catallo
 
#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...
#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...
#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...Toshiaki Maki
 
C++ Standard Template Library
C++ Standard Template LibraryC++ Standard Template Library
C++ Standard Template LibraryIlio Catallo
 
はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)Masatoshi Tada
 
Tools For jQuery Application Architecture (Extended Slides)
Tools For jQuery Application Architecture (Extended Slides)Tools For jQuery Application Architecture (Extended Slides)
Tools For jQuery Application Architecture (Extended Slides)Addy Osmani
 
Spring IO 2016 - Spring Cloud Microservices, a journey inside a financial entity
Spring IO 2016 - Spring Cloud Microservices, a journey inside a financial entitySpring IO 2016 - Spring Cloud Microservices, a journey inside a financial entity
Spring IO 2016 - Spring Cloud Microservices, a journey inside a financial entityToni Jara
 
Getting start Java EE Action-Based MVC with Thymeleaf
Getting start Java EE Action-Based MVC with ThymeleafGetting start Java EE Action-Based MVC with Thymeleaf
Getting start Java EE Action-Based MVC with ThymeleafMasatoshi Tada
 
Modern JavaScript Applications: Design Patterns
Modern JavaScript Applications: Design PatternsModern JavaScript Applications: Design Patterns
Modern JavaScript Applications: Design PatternsVolodymyr Voytyshyn
 
初窥Java网络IO
初窥Java网络IO初窥Java网络IO
初窥Java网络IOdigitalsonic
 
实战HotSpot JVM GC
实战HotSpot JVM GC实战HotSpot JVM GC
实战HotSpot JVM GCdigitalsonic
 

Andere mochten auch (20)

Testing Spring MVC and REST Web Applications
Testing Spring MVC and REST Web ApplicationsTesting Spring MVC and REST Web Applications
Testing Spring MVC and REST Web Applications
 
Struts 2 + Spring
Struts 2 + SpringStruts 2 + Spring
Struts 2 + Spring
 
Boostrap - Start Up
Boostrap - Start UpBoostrap - Start Up
Boostrap - Start Up
 
Data Synchronization Patterns in Mobile Application Design
Data Synchronization Patterns in Mobile Application DesignData Synchronization Patterns in Mobile Application Design
Data Synchronization Patterns in Mobile Application Design
 
Authentication and Authorization
Authentication and AuthorizationAuthentication and Authorization
Authentication and Authorization
 
Node.js căn bản
Node.js căn bảnNode.js căn bản
Node.js căn bản
 
NetBeansでかんたんJava EE ○分間クッキング! #kuwaccho lt
NetBeansでかんたんJava EE ○分間クッキング! #kuwaccho ltNetBeansでかんたんJava EE ○分間クッキング! #kuwaccho lt
NetBeansでかんたんJava EE ○分間クッキング! #kuwaccho lt
 
Building RESTful applications using Spring MVC
Building RESTful applications using Spring MVCBuilding RESTful applications using Spring MVC
Building RESTful applications using Spring MVC
 
Front end architecture
Front end architectureFront end architecture
Front end architecture
 
Desenvolvimento Front end (AngularJS e Bootstrap)
Desenvolvimento Front end (AngularJS e Bootstrap)Desenvolvimento Front end (AngularJS e Bootstrap)
Desenvolvimento Front end (AngularJS e Bootstrap)
 
JSP Standard Tag Library
JSP Standard Tag LibraryJSP Standard Tag Library
JSP Standard Tag Library
 
#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...
#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...
#jjug_ccc #ccc_gh5 What's new in Spring Framework 4.3 / Boot 1.4 + Pivotal's ...
 
C++ Standard Template Library
C++ Standard Template LibraryC++ Standard Template Library
C++ Standard Template Library
 
はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)はまる!JPA(初学者向けライト版)
はまる!JPA(初学者向けライト版)
 
Tools For jQuery Application Architecture (Extended Slides)
Tools For jQuery Application Architecture (Extended Slides)Tools For jQuery Application Architecture (Extended Slides)
Tools For jQuery Application Architecture (Extended Slides)
 
Spring IO 2016 - Spring Cloud Microservices, a journey inside a financial entity
Spring IO 2016 - Spring Cloud Microservices, a journey inside a financial entitySpring IO 2016 - Spring Cloud Microservices, a journey inside a financial entity
Spring IO 2016 - Spring Cloud Microservices, a journey inside a financial entity
 
Getting start Java EE Action-Based MVC with Thymeleaf
Getting start Java EE Action-Based MVC with ThymeleafGetting start Java EE Action-Based MVC with Thymeleaf
Getting start Java EE Action-Based MVC with Thymeleaf
 
Modern JavaScript Applications: Design Patterns
Modern JavaScript Applications: Design PatternsModern JavaScript Applications: Design Patterns
Modern JavaScript Applications: Design Patterns
 
初窥Java网络IO
初窥Java网络IO初窥Java网络IO
初窥Java网络IO
 
实战HotSpot JVM GC
实战HotSpot JVM GC实战HotSpot JVM GC
实战HotSpot JVM GC
 

Ähnlich wie Spring MVC - Web Forms

Building advanced data-driven applications
Building advanced data-driven applicationsBuilding advanced data-driven applications
Building advanced data-driven applicationsMariaDB plc
 
Form using html and java script validation
Form using html and java script validationForm using html and java script validation
Form using html and java script validationMaitree Patel
 
OAuth-as-a-service - using ASP.NET Web API and Windows Azure Access Control -...
OAuth-as-a-service - using ASP.NET Web API and Windows Azure Access Control -...OAuth-as-a-service - using ASP.NET Web API and Windows Azure Access Control -...
OAuth-as-a-service - using ASP.NET Web API and Windows Azure Access Control -...Maarten Balliauw
 
OSCamp #4 on Foreman | CLI tools with Foreman by Martin Bačovský
OSCamp #4 on Foreman | CLI tools with Foreman by Martin BačovskýOSCamp #4 on Foreman | CLI tools with Foreman by Martin Bačovský
OSCamp #4 on Foreman | CLI tools with Foreman by Martin BačovskýNETWAYS
 
OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control
OAuth-as-a-serviceusing ASP.NET Web API and Windows Azure Access ControlOAuth-as-a-serviceusing ASP.NET Web API and Windows Azure Access Control
OAuth-as-a-service using ASP.NET Web API and Windows Azure Access ControlMaarten Balliauw
 
How to create social apps for millions of users
How to create social apps for millions of users How to create social apps for millions of users
How to create social apps for millions of users Bastian Hofmann
 
M|18 User Defined Function
M|18 User Defined FunctionM|18 User Defined Function
M|18 User Defined FunctionMariaDB plc
 
Web Services with Objective-C
Web Services with Objective-CWeb Services with Objective-C
Web Services with Objective-CJuio Barros
 
Distributed Identities with OpenID
Distributed Identities with OpenIDDistributed Identities with OpenID
Distributed Identities with OpenIDBastian Hofmann
 
OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control - W...
OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control - W...OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control - W...
OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control - W...Maarten Balliauw
 
Derek Pearcy - Reading Users' Minds For Fun And Profit
Derek Pearcy - Reading Users' Minds For Fun And ProfitDerek Pearcy - Reading Users' Minds For Fun And Profit
Derek Pearcy - Reading Users' Minds For Fun And Profitbolt peters
 
Short Intro to PHP and MySQL
Short Intro to PHP and MySQLShort Intro to PHP and MySQL
Short Intro to PHP and MySQLJussi Pohjolainen
 
Maximizer 2018 API training
Maximizer 2018 API trainingMaximizer 2018 API training
Maximizer 2018 API trainingMurylo Batista
 
Web Application Development using PHP Chapter 5
Web Application Development using PHP Chapter 5Web Application Development using PHP Chapter 5
Web Application Development using PHP Chapter 5Mohd Harris Ahmad Jaal
 
Web-01-HTTP.pptx
Web-01-HTTP.pptxWeb-01-HTTP.pptx
Web-01-HTTP.pptxAliZaib71
 
Crossing the Boundaries of Web Applications with OpenSocial
Crossing the Boundaries of Web Applications with OpenSocialCrossing the Boundaries of Web Applications with OpenSocial
Crossing the Boundaries of Web Applications with OpenSocialBastian Hofmann
 

Ähnlich wie Spring MVC - Web Forms (20)

Building advanced data-driven applications
Building advanced data-driven applicationsBuilding advanced data-driven applications
Building advanced data-driven applications
 
Form using html and java script validation
Form using html and java script validationForm using html and java script validation
Form using html and java script validation
 
OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control
OAuth-as-a-service using ASP.NET Web API and Windows Azure Access ControlOAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control
OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control
 
OAuth-as-a-service - using ASP.NET Web API and Windows Azure Access Control -...
OAuth-as-a-service - using ASP.NET Web API and Windows Azure Access Control -...OAuth-as-a-service - using ASP.NET Web API and Windows Azure Access Control -...
OAuth-as-a-service - using ASP.NET Web API and Windows Azure Access Control -...
 
OSCamp #4 on Foreman | CLI tools with Foreman by Martin Bačovský
OSCamp #4 on Foreman | CLI tools with Foreman by Martin BačovskýOSCamp #4 on Foreman | CLI tools with Foreman by Martin Bačovský
OSCamp #4 on Foreman | CLI tools with Foreman by Martin Bačovský
 
OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control
OAuth-as-a-serviceusing ASP.NET Web API and Windows Azure Access ControlOAuth-as-a-serviceusing ASP.NET Web API and Windows Azure Access Control
OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control
 
How to create social apps for millions of users
How to create social apps for millions of users How to create social apps for millions of users
How to create social apps for millions of users
 
Spsl v unit - final
Spsl v unit - finalSpsl v unit - final
Spsl v unit - final
 
Oauth
OauthOauth
Oauth
 
M|18 User Defined Function
M|18 User Defined FunctionM|18 User Defined Function
M|18 User Defined Function
 
Web Services with Objective-C
Web Services with Objective-CWeb Services with Objective-C
Web Services with Objective-C
 
Distributed Identities with OpenID
Distributed Identities with OpenIDDistributed Identities with OpenID
Distributed Identities with OpenID
 
Development Workflows on AWS
Development Workflows on AWSDevelopment Workflows on AWS
Development Workflows on AWS
 
OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control - W...
OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control - W...OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control - W...
OAuth-as-a-service using ASP.NET Web API and Windows Azure Access Control - W...
 
Derek Pearcy - Reading Users' Minds For Fun And Profit
Derek Pearcy - Reading Users' Minds For Fun And ProfitDerek Pearcy - Reading Users' Minds For Fun And Profit
Derek Pearcy - Reading Users' Minds For Fun And Profit
 
Short Intro to PHP and MySQL
Short Intro to PHP and MySQLShort Intro to PHP and MySQL
Short Intro to PHP and MySQL
 
Maximizer 2018 API training
Maximizer 2018 API trainingMaximizer 2018 API training
Maximizer 2018 API training
 
Web Application Development using PHP Chapter 5
Web Application Development using PHP Chapter 5Web Application Development using PHP Chapter 5
Web Application Development using PHP Chapter 5
 
Web-01-HTTP.pptx
Web-01-HTTP.pptxWeb-01-HTTP.pptx
Web-01-HTTP.pptx
 
Crossing the Boundaries of Web Applications with OpenSocial
Crossing the Boundaries of Web Applications with OpenSocialCrossing the Boundaries of Web Applications with OpenSocial
Crossing the Boundaries of Web Applications with OpenSocial
 

Mehr von Ilio Catallo

Regular types in C++
Regular types in C++Regular types in C++
Regular types in C++Ilio Catallo
 
Resource wrappers in C++
Resource wrappers in C++Resource wrappers in C++
Resource wrappers in C++Ilio Catallo
 
Memory management in C++
Memory management in C++Memory management in C++
Memory management in C++Ilio Catallo
 
Operator overloading in C++
Operator overloading in C++Operator overloading in C++
Operator overloading in C++Ilio Catallo
 
Multidimensional arrays in C++
Multidimensional arrays in C++Multidimensional arrays in C++
Multidimensional arrays in C++Ilio Catallo
 
Pointers & References in C++
Pointers & References in C++Pointers & References in C++
Pointers & References in C++Ilio Catallo
 
Java and Java platforms
Java and Java platformsJava and Java platforms
Java and Java platformsIlio Catallo
 
Web application architecture
Web application architectureWeb application architecture
Web application architectureIlio Catallo
 
Introduction To Spring
Introduction To SpringIntroduction To Spring
Introduction To SpringIlio Catallo
 
Gestione della memoria in C++
Gestione della memoria in C++Gestione della memoria in C++
Gestione della memoria in C++Ilio Catallo
 
Puntatori e Riferimenti
Puntatori e RiferimentiPuntatori e Riferimenti
Puntatori e RiferimentiIlio Catallo
 
Java Persistence API
Java Persistence APIJava Persistence API
Java Persistence APIIlio Catallo
 
Internationalization in Jakarta Struts 1.3
Internationalization in Jakarta Struts 1.3Internationalization in Jakarta Struts 1.3
Internationalization in Jakarta Struts 1.3Ilio Catallo
 
Validation in Jakarta Struts 1.3
Validation in Jakarta Struts 1.3Validation in Jakarta Struts 1.3
Validation in Jakarta Struts 1.3Ilio Catallo
 
Introduction to Struts 1.3
Introduction to Struts 1.3Introduction to Struts 1.3
Introduction to Struts 1.3Ilio Catallo
 
Community Detection
Community DetectionCommunity Detection
Community DetectionIlio Catallo
 
WWW12 - The CUbRIK Project
WWW12 - The CUbRIK ProjectWWW12 - The CUbRIK Project
WWW12 - The CUbRIK ProjectIlio Catallo
 

Mehr von Ilio Catallo (19)

Regular types in C++
Regular types in C++Regular types in C++
Regular types in C++
 
Resource wrappers in C++
Resource wrappers in C++Resource wrappers in C++
Resource wrappers in C++
 
Memory management in C++
Memory management in C++Memory management in C++
Memory management in C++
 
Operator overloading in C++
Operator overloading in C++Operator overloading in C++
Operator overloading in C++
 
Multidimensional arrays in C++
Multidimensional arrays in C++Multidimensional arrays in C++
Multidimensional arrays in C++
 
Arrays in C++
Arrays in C++Arrays in C++
Arrays in C++
 
Pointers & References in C++
Pointers & References in C++Pointers & References in C++
Pointers & References in C++
 
Java and Java platforms
Java and Java platformsJava and Java platforms
Java and Java platforms
 
Web application architecture
Web application architectureWeb application architecture
Web application architecture
 
Introduction To Spring
Introduction To SpringIntroduction To Spring
Introduction To Spring
 
Gestione della memoria in C++
Gestione della memoria in C++Gestione della memoria in C++
Gestione della memoria in C++
 
Array in C++
Array in C++Array in C++
Array in C++
 
Puntatori e Riferimenti
Puntatori e RiferimentiPuntatori e Riferimenti
Puntatori e Riferimenti
 
Java Persistence API
Java Persistence APIJava Persistence API
Java Persistence API
 
Internationalization in Jakarta Struts 1.3
Internationalization in Jakarta Struts 1.3Internationalization in Jakarta Struts 1.3
Internationalization in Jakarta Struts 1.3
 
Validation in Jakarta Struts 1.3
Validation in Jakarta Struts 1.3Validation in Jakarta Struts 1.3
Validation in Jakarta Struts 1.3
 
Introduction to Struts 1.3
Introduction to Struts 1.3Introduction to Struts 1.3
Introduction to Struts 1.3
 
Community Detection
Community DetectionCommunity Detection
Community Detection
 
WWW12 - The CUbRIK Project
WWW12 - The CUbRIK ProjectWWW12 - The CUbRIK Project
WWW12 - The CUbRIK Project
 

Kürzlich hochgeladen

microwave assisted reaction. General introduction
microwave assisted reaction. General introductionmicrowave assisted reaction. General introduction
microwave assisted reaction. General introductionMaksud Ahmed
 
Student login on Anyboli platform.helpin
Student login on Anyboli platform.helpinStudent login on Anyboli platform.helpin
Student login on Anyboli platform.helpinRaunakKeshri1
 
The basics of sentences session 2pptx copy.pptx
The basics of sentences session 2pptx copy.pptxThe basics of sentences session 2pptx copy.pptx
The basics of sentences session 2pptx copy.pptxheathfieldcps1
 
18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf
18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf
18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdfssuser54595a
 
Contemporary philippine arts from the regions_PPT_Module_12 [Autosaved] (1).pptx
Contemporary philippine arts from the regions_PPT_Module_12 [Autosaved] (1).pptxContemporary philippine arts from the regions_PPT_Module_12 [Autosaved] (1).pptx
Contemporary philippine arts from the regions_PPT_Module_12 [Autosaved] (1).pptxRoyAbrique
 
Organic Name Reactions for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions  for the students and aspirants of Chemistry12th.pptxOrganic Name Reactions  for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions for the students and aspirants of Chemistry12th.pptxVS Mahajan Coaching Centre
 
Sanyam Choudhary Chemistry practical.pdf
Sanyam Choudhary Chemistry practical.pdfSanyam Choudhary Chemistry practical.pdf
Sanyam Choudhary Chemistry practical.pdfsanyamsingh5019
 
Employee wellbeing at the workplace.pptx
Employee wellbeing at the workplace.pptxEmployee wellbeing at the workplace.pptx
Employee wellbeing at the workplace.pptxNirmalaLoungPoorunde1
 
Web & Social Media Analytics Previous Year Question Paper.pdf
Web & Social Media Analytics Previous Year Question Paper.pdfWeb & Social Media Analytics Previous Year Question Paper.pdf
Web & Social Media Analytics Previous Year Question Paper.pdfJayanti Pande
 
Separation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and ActinidesSeparation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and ActinidesFatimaKhan178732
 
“Oh GOSH! Reflecting on Hackteria's Collaborative Practices in a Global Do-It...
“Oh GOSH! Reflecting on Hackteria's Collaborative Practices in a Global Do-It...“Oh GOSH! Reflecting on Hackteria's Collaborative Practices in a Global Do-It...
“Oh GOSH! Reflecting on Hackteria's Collaborative Practices in a Global Do-It...Marc Dusseiller Dusjagr
 
Introduction to AI in Higher Education_draft.pptx
Introduction to AI in Higher Education_draft.pptxIntroduction to AI in Higher Education_draft.pptx
Introduction to AI in Higher Education_draft.pptxpboyjonauth
 
Arihant handbook biology for class 11 .pdf
Arihant handbook biology for class 11 .pdfArihant handbook biology for class 11 .pdf
Arihant handbook biology for class 11 .pdfchloefrazer622
 
POINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptx
POINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptxPOINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptx
POINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptxSayali Powar
 
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptxSOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptxiammrhaywood
 
The Most Excellent Way | 1 Corinthians 13
The Most Excellent Way | 1 Corinthians 13The Most Excellent Way | 1 Corinthians 13
The Most Excellent Way | 1 Corinthians 13Steve Thomason
 
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...EduSkills OECD
 
How to Make a Pirate ship Primary Education.pptx
How to Make a Pirate ship Primary Education.pptxHow to Make a Pirate ship Primary Education.pptx
How to Make a Pirate ship Primary Education.pptxmanuelaromero2013
 
Advanced Views - Calendar View in Odoo 17
Advanced Views - Calendar View in Odoo 17Advanced Views - Calendar View in Odoo 17
Advanced Views - Calendar View in Odoo 17Celine George
 

Kürzlich hochgeladen (20)

microwave assisted reaction. General introduction
microwave assisted reaction. General introductionmicrowave assisted reaction. General introduction
microwave assisted reaction. General introduction
 
Student login on Anyboli platform.helpin
Student login on Anyboli platform.helpinStudent login on Anyboli platform.helpin
Student login on Anyboli platform.helpin
 
Código Creativo y Arte de Software | Unidad 1
Código Creativo y Arte de Software | Unidad 1Código Creativo y Arte de Software | Unidad 1
Código Creativo y Arte de Software | Unidad 1
 
The basics of sentences session 2pptx copy.pptx
The basics of sentences session 2pptx copy.pptxThe basics of sentences session 2pptx copy.pptx
The basics of sentences session 2pptx copy.pptx
 
18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf
18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf
18-04-UA_REPORT_MEDIALITERAСY_INDEX-DM_23-1-final-eng.pdf
 
Contemporary philippine arts from the regions_PPT_Module_12 [Autosaved] (1).pptx
Contemporary philippine arts from the regions_PPT_Module_12 [Autosaved] (1).pptxContemporary philippine arts from the regions_PPT_Module_12 [Autosaved] (1).pptx
Contemporary philippine arts from the regions_PPT_Module_12 [Autosaved] (1).pptx
 
Organic Name Reactions for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions  for the students and aspirants of Chemistry12th.pptxOrganic Name Reactions  for the students and aspirants of Chemistry12th.pptx
Organic Name Reactions for the students and aspirants of Chemistry12th.pptx
 
Sanyam Choudhary Chemistry practical.pdf
Sanyam Choudhary Chemistry practical.pdfSanyam Choudhary Chemistry practical.pdf
Sanyam Choudhary Chemistry practical.pdf
 
Employee wellbeing at the workplace.pptx
Employee wellbeing at the workplace.pptxEmployee wellbeing at the workplace.pptx
Employee wellbeing at the workplace.pptx
 
Web & Social Media Analytics Previous Year Question Paper.pdf
Web & Social Media Analytics Previous Year Question Paper.pdfWeb & Social Media Analytics Previous Year Question Paper.pdf
Web & Social Media Analytics Previous Year Question Paper.pdf
 
Separation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and ActinidesSeparation of Lanthanides/ Lanthanides and Actinides
Separation of Lanthanides/ Lanthanides and Actinides
 
“Oh GOSH! Reflecting on Hackteria's Collaborative Practices in a Global Do-It...
“Oh GOSH! Reflecting on Hackteria's Collaborative Practices in a Global Do-It...“Oh GOSH! Reflecting on Hackteria's Collaborative Practices in a Global Do-It...
“Oh GOSH! Reflecting on Hackteria's Collaborative Practices in a Global Do-It...
 
Introduction to AI in Higher Education_draft.pptx
Introduction to AI in Higher Education_draft.pptxIntroduction to AI in Higher Education_draft.pptx
Introduction to AI in Higher Education_draft.pptx
 
Arihant handbook biology for class 11 .pdf
Arihant handbook biology for class 11 .pdfArihant handbook biology for class 11 .pdf
Arihant handbook biology for class 11 .pdf
 
POINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptx
POINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptxPOINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptx
POINT- BIOCHEMISTRY SEM 2 ENZYMES UNIT 5.pptx
 
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptxSOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
SOCIAL AND HISTORICAL CONTEXT - LFTVD.pptx
 
The Most Excellent Way | 1 Corinthians 13
The Most Excellent Way | 1 Corinthians 13The Most Excellent Way | 1 Corinthians 13
The Most Excellent Way | 1 Corinthians 13
 
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
Presentation by Andreas Schleicher Tackling the School Absenteeism Crisis 30 ...
 
How to Make a Pirate ship Primary Education.pptx
How to Make a Pirate ship Primary Education.pptxHow to Make a Pirate ship Primary Education.pptx
How to Make a Pirate ship Primary Education.pptx
 
Advanced Views - Calendar View in Odoo 17
Advanced Views - Calendar View in Odoo 17Advanced Views - Calendar View in Odoo 17
Advanced Views - Calendar View in Odoo 17
 

Spring MVC - Web Forms

  • 1. Spring MVC - Web forms Ilio Catallo - info@iliocatallo.it
  • 2. Outline • First principles • Data binding • Data valida3on • The PRG pa:ern • References
  • 4. Handling user input Web apps o)en have to perform some logic against one or more pieces of informa(on coming from the user User User's interaction +-------------+ information +-------------+ | | | | +--------------> Browser +-------------------> Web app | | | | | +-------------+ +-------------+
  • 5. Request parameters This informa,on is made available through the request parameters HTTP request +-------------+ User | Request | interaction +-------------+ | parameters | +-------------+ | | +-------------+ | | +--------------> Browser +---------------------> Web app | | | | | +-------------+ +-------------+
  • 6. Request parameters Request parameters are sent as part of the HTTP request message issued by the client HTTP request +-------------+ User | Request | interaction +-------------+ | parameters | +-------------+ | | +-------------+ | | +--------------> Browser +---------------------> Web app | | | | | +-------------+ +-------------+
  • 7. Request parameters Request parameters can be transferred as part of • The query string • The HTTP en1ty body
  • 8. Request parameters Request parameters can be transferred as part of • The query string • The HTTP en)ty body
  • 9. Query string Request parameters are specified as a sequence of URL parameters appended to the request URL http://my.server/resource?par1=val1&par2=val2 <-----------------> URL parameters
  • 10. Query string In other words, request parameters are appended to the query string http://my.server/resource?par1=val1&par2=val2 <-----------------> query string
  • 11. HTTP request HTTP request +--------------------------------------+ | GET /webapp/greeting?name=Jon | | &surname=Snow | +--------------------------------------+ | | | Host: myserver.com | | User-Agent: ... | | Accept-Encoding: ... | | | +--------------------------------------+
  • 12. Gree$ng by name Assume that we want our applica2on to be able to accept the name and the surname of the user to greet
  • 13. Gree$ng by name In order to do so, we first provide an addi1onal overload of getRandomGreeting() public interface GreetingService { public String getRandomGreeting(); public String getRandomGreeting(String name, String surname); }
  • 14. Parsing request parameters Second, we need a mechanism for parsing the HTTP request so as to extract the related request parameters HTTP request +--------------------------------------+ | GET /webapp/greeting?name=Jon | | &surname=Snow | +--------------------------------------+ | | | Host: myserver.com | | User-Agent: ... | | Accept-Encoding: ... | | | +--------------------------------------+
  • 15. @RequestParam One such mechanism is the @RequestParam annota.on HTTP request +--------------------------------------+ | GET /webapp/greeting?name=Jon | | &surname=Snow | +--------------------------------------+ | | | Host: myserver.com | | User-Agent: ... | | Accept-Encoding: ... | | | +--------------------------------------+
  • 16. @RequestParam The @RequestParam annota)on binds request parameters to method parameters @RequestMapping("/custom-greeting") public String getGreeting(@RequestParam("name") String name, @RequestParam("surname") String surname, Model model) { ... }
  • 17. Request vs. method parameters The name request parameter binds to the name method parameter @RequestMapping("/custom-greeting") public String getGreeting(@RequestParam("name") String name, @RequestParam("surname") String surname, Model model) { ... }
  • 18. Request vs. method parameters The surname request parameter binds to the surname method parameter @RequestMapping("/custom-greeting") public String getGreeting(@RequestParam("name") String name, @RequestParam("surname") String surname, Model model) { ... }
  • 19. @RequestParam We can now add an addi+onal overload of getGreeting() and associate it with the /custom-greeting endpoint public class GreetingController { @RequestMapping("/greeting") public String getGreeting(Model model) { ... } @RequestMapping("/custom-greeting") public String getGreeting(@RequestParam("name") String name, @RequestParam("surname") String surname, Model model) { ... } }
  • 20. getGreeting() @RequestMapping("/custom-greeting") public String getGreeting(@RequestParam("name") String name, @RequestParam("surname") String surname, Model model) { String greeting = service.getRandomGreeting(name, surname); model.addAttribute("greeting", greeting); return "greeting"; }
  • 21. Required by default Request parameters specified using @RequestParam are required by default
  • 22. URL templates To trigger the execu-on of getGreeting(), we should construct a URL according to the following URL template http://myserver.com/webapp/custom-greeting?name={name} &surname={surname}
  • 23. HTML forms A possible way to construct URLs from a URL template is to use an HTML form <form action="..." method="..."> </form>
  • 24. HTML forms HTML forms are hypermedia controls that allow users to supply data towards an applica7on endpoint <form action="..." method="..."> </form>
  • 25. HTML forms We provide one text field per URL parameter, as well as a submit bu3on <form action="..." method="..."> <input type="text" name="name"> <input type="text" name="surname"> <button type="submit">Get your greeting!</button> </form>
  • 26. HTML forms Since we want values to be sent as part of the query string, we specify GET as the HTTP method <form action="..." method="GET"> <input type="text" name="name"> <input type="text" name="surname"> <button type="submit">Get your greeting!</button> </form>
  • 27. HTML forms Finally, we provide the endpoint where to send the parameters; intui6vely we would like to do the following <form action="/custom-greeting" method="GET"> <input type="text" name="name"> <input type="text" name="surname"> <button type="submit">Get your greeting!</button> </form>
  • 28. HTML forms Since a single Web container may host several Web applica4ons, the correct endpoint is /webapp/custom-greeting1 <form action="/webapp/custom-greeting" method="GET"> <input type="text" name="name"> <input type="text" name="surname"> <button type="submit">Get your greeting!</button> </form> 1 Where webapp is the name of our Web applica4on
  • 29. HTML forms However, we would much prefer not to hard-code the name of the Web applica7on
  • 30. The <spring:url> tag When using JSP as view technology, we can take advantage of the <spring:url> tag <spring:url value="/custom-greeting" var="customGreeting"/>
  • 31. The <spring:url> tag Given an URL, <spring:url> generates the corresponding context-aware URL, which is then saved into a page variable <spring:url value="/custom-greeting" var="customGreeting"/>
  • 32. The <spring:url> tag That is, links of the form /endpoint are automa2cally transformed into links of the form /webapp/endpoint /endpoint → /webapp/endpoint
  • 33. HTML forms The final HTML form thus reads <spring:url value="/custom-greeting" var="customGreeting"/> <form action="${customGreeting}" method="GET"> <input type="text" name="name"> <input type="text" name="surname"> <button type="submit">Get your greeting!</button> </form>
  • 34. The Spring tag library The <spring:url> tag is part of the Spring tag library, which is in turn part of Spring MVC <spring:url value="/custom-greeting" var="customGreeting"/>
  • 35. The Spring tag library The Spring tag library can be imported into a JSP page by means of the taglib direc8ve2 <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> 2 Remember that the taglib direc.ve does not actually load anything, we s.ll need to deploy the Spring tag library together with the applica.on
  • 36. Request parameters Request parameters can be transferred as part of • The query string • The HTTP en1ty body
  • 37. Request parameters Request parameters can be transferred as part of • The query string • The HTTP en(ty body
  • 38. En#ty body The en&ty body is an op#onal part of HTTP messages HTTP message +----------------------------+ | Start line | +----------------------------+ | | | Headers | | | +----------------------------+ | | | Entity body | | | +----------------------------+
  • 39. En#ty body Unlike the start line and the headers, the body can contain text or binary data HTTP message +----------------------------+ | Start line | +----------------------------+ | | | Headers | | | +----------------------------+ | | | Entity body | | | +----------------------------+
  • 40. En#ty body While any HTTP request is allowed to contain a body, some servers will refuse to, e.g., process a GET request with a body3 3 One prominent example is Google (see references)
  • 41. POST The POST verb is among the HTTP verbs that explicitly admit the presence of an en5ty body HTTP message +--------------------------------+ | POST /custom-greeting HTTP/1.1 | +--------------------------------+ | | | Content-Type: ... | | | +--------------------------------+ | | | Entity body | | | +--------------------------------+
  • 42. POST As a ma&er of fact, the POST method is specifically designed to send input data to the server
  • 43. POSTing our gree-ng +--------------------------------------------------+ | POST /webapp/custom-greeting HTTP/1.1 | +--------------------------------------------------+ | Host: myserver.com | | User-Agent: ... | | Content-Type: application/x-www-form-urlencoded | +--------------------------------------------------+ | name=Jon&surname=Snow | | | +--------------------------------------------------+
  • 44. HTML form As before, we can use an HTML form to issue a POST request <spring:url value="/custom-greeting" var="customGreeting"/> <form action="${customGreeting}" method="POST"> <input type="text" name="name"/> <input type="text" name="surname"/> <button type="submit">Get your greeting!</button> </form>
  • 45. HTML form Since we want our parameters to be transferred as part of the en4ty body, we specify POST as the HTTP method <spring:url value="/custom-greeting" var="customGreeting"/> <form action="${customGreeting}" method="POST"> <input type="text" name="name"/> <input type="text" name="surname"/> <button type="submit">Get your greeting!</button> </form>
  • 46. How can we decide between GET and POST requests?
  • 47. "...the GET and HEAD methods SHOULD NOT have the significance of taking an ac?on other than retrieval. These methods ought to be considered "safe"." (RFC 2616)
  • 48. "This allows user agents to represent other methods, such as POST, PUT and DELETE, in a special way, so that the user is made aware of the fact that a possibly unsafe ac/on is being requested." (RFC 2616)
  • 49. "The important dis0nc0on here is that the user did not request the side-effects, so therefore cannot be held accountable for them." (RFC 2616)
  • 50. Unsafe ac)ons The user is accountable for the POST requests she executes, as they represent unsafe ac-ons on the Web applica:on
  • 51. Unsafe ac)ons Unsafe ac)ons may alter the state of the Web applica)on. For instance, causing external informa)on sent as form data to be stored
  • 52. Accountability That’s why the browser informs us when we try to send again a HTTP POST request
  • 54. HTML form vs. Web apps HTML forms give users a place where to enter data
  • 55. Text parameters The browser sends the data up to the server as a list of name-value pairs +--------------------------------------------------+ | POST /webapp/custom-greeting HTTP/1.1 | +--------------------------------------------------+ | Host: myserver.com | | User-Agent: ... | | Content-Type: application/x-www-form-urlencoded | +--------------------------------------------------+ | name=Jon&surname=Snow | | | +--------------------------------------------------+
  • 56. Text parameters Everything is going to be transferred to the Web app as text +--------------------------------------------------+ | POST /webapp/custom-greeting HTTP/1.1 | +--------------------------------------------------+ | Host: myserver.com | | User-Agent: ... | | Content-Type: application/x-www-form-urlencoded | +--------------------------------------------------+ | name=Jon&surname=Snow | | | +--------------------------------------------------+
  • 57. HTML form vs. Web apps But, what if... • A field has to be interpreted as something different than a String (e.g., as a Date)? • The user forgets to provide a mandatory field? does she have to re-type everything from scratch? • We want to check that a field respects a given paDern?
  • 58. HTML form vs. Web apps But, what if... • We need to perform data conversion? • We need to perform data buffering? • We need to perform data valida2on?
  • 59. HTML form vs. Web apps HTTP/HTML does not provide a component that can buffer, validate4 and convert inputs coming from a form 4 Here, we are not considering HTML5 Constraint Valida8on API
  • 60. HTML form vs. Web apps When trying to solve these issues, HTML and HTTP are of no use to us
  • 61. HTML form vs. Web apps This is how HTTP and HTML work, Web apps cannot control this
  • 62. The "Sign-up" example Let us assume that our Web applica2on requires the user to sign up for a new account
  • 63. The "Sign-up" example To this end, we introduce: • An annotated controller named AccountController • A registra1on page
  • 64. AccountController @Controller public class AccountController { @RequestMapping("/account") public String addAccount(...) { ... } }
  • 65. Registra)on form <spring:url value="/account" var="account"/> <form action="${account}" method="POST"> Name: <input type="text" name="name"/> <br/> Surname: <input type="text" name="surname"/> <br/> Email: <input type="text" name="email"/> <br/> Birthday: <input type="text" name="birthday"/> <br/> <button type="submit">Sign-up</button> </form>
  • 66. The Account bean Once we get the data, we may want to store them in a JavaBean public class Account { private String name; private String surname; private String email; private Date birthday; // getters and setters }
  • 67. The Account bean Which is the best way of moving from the request parameters to the corresponding Account object? +------------------------------------------------+ | POST /webapp/account HTTP/1.1 | public class Account { +------------------------------------------------+ | Host: myserver.com | private String name; | User-Agent: ... | private String surname; | Content-Type: application/x-www-form-urlencoded| private String email; +------------------------------------------------+ +-----> private Date birthday; | name=Jon& | | surname=Snow& | // getters and setters | birthday=10-1-1956 | } +------------------------------------------------+
  • 68. The naïve solu-on We could try to get each single request parameter individually @RequestMapping("/account") public String addAccount(@RequestParam("name") String name, @RequestParam("surname") String surname, @RequestParam("email") String email, @RequestParam("birthday") Date birthday, Model model) { // we manually populate the Account object with // the data coming from the user Account a = new Account(); a.setName(name); ... }
  • 69. Method parameters in OOP “The ideal number of arguments for a func5on is zero. Next comes one, followed closely by two. Three arguments should be avoided where possible. More than three requires very special jus5fica5on - and then shouldn’t be used anyway.” (B. Mar(n)
  • 70. The naïve solu-on By doing so, we effec/vely clu$ered the handler method signature @RequestMapping("/account") public String addAccount(@RequestParam("name") String name, @RequestParam("surname") String surname, @RequestParam("email") String email, @RequestParam("birthday") Date birthday, Model model) { Account a = new Account(); a.setName(name); ... }
  • 71. Data binding Wouldn’t it be great if data coming from the form could be automa&cally bound to an Account object? +------------------------------------------------+ | POST /webapp/account HTTP/1.1 | public class Account { +------------------------------------------------+ | Host: myserver.com | private String name; | User-Agent: ... | private String surname; | Content-Type: application/x-www-form-urlencoded| private String email; +------------------------------------------------+ +-----> private Date birthday; | name=Jon& | | surname=Snow& | // getters and setters | birthday=10-1-1956 | } +------------------------------------------------+
  • 72. Data binding Data binding is the process of binding the request parameters to a so called form bean public class Account { private String name; private String surname; private String email; private Date birthday; // getters and setters }
  • 73. Data binding The form bean is also called the form-backing bean, the form object or the command object public class Account { ... }
  • 74. Data binding It turns out that all we need to do is to declare an Account object as a method parameter @RequestMapping("/account") public String addAccount(Account account) { // account will be automatically populated // with the request parameters }
  • 75. Data binding The following sequence of opera3ons occurs: • A new form bean is instan(ated • The form bean is added to the model • The form bean is populated from the request parameters
  • 76. The form bean is a model a0ribute The account form bean will be automa&cally added to the model Model +----------------+ | | | account | HTTP +-------------------+ +----------------+ +--------------------+ request | | | | +--------> DispatcherServlet +----------------------> AccountController | | | | | +-------------------+ +--------------------+
  • 77. The form bean is a model a0ribute Hence, views can access and render the form bean content Model Model +--------------+ +--------------+ | | | | | account | | account | +----------+ +--------------+ +-------------------+ +--------------+ +--------------------+ | | | | | | | View <--------------------+ DispatcherServlet <--------------------+ AccountController | | | | | | | +----------+ +-------------------+ +--------------------+
  • 78. The form bean is a model a0ribute <html> <head> <title>Thanks</title> </head> <body> Hi, ${account.name} ${account.surname}. You have successfully registered. <br/> </body> </html>
  • 79. Default values Assume that we want to ask the user for the permission of sending marke&ng e-mails
  • 80. Default values To this end, we add a marketingOk property in the Account form bean public class Account { private String name; private String surname; private String email; private Date birthday; private boolean marketingOk; // getters and setters }
  • 81. Default values By default, we would like the marketingOk property to be true public class Account { private String name; private String surname; private String email; private Date birthday; private boolean marketingOk = true; // getters and setters }
  • 82. Prepopula)ng Account As a ma&er of fact, we are prepopula(ng the Account bean public class Account { private String name; private String surname; private String email; private Date birthday; private boolean marketingOk = true; // getters and setters }
  • 83. Showing prepopulated data We want the registra-on page to use proper-es coming from a prepopulated Account bean +--------------------------------------+ | | | +----------------------+ | | Name: | | | | +----------------------+ | | | | +----------------------+ | | Surname: | | | +--------------+ | +----------------------+ | | | | <----------+ Account bean | | +----------------------+ | | | | Date: | | | +--------------+ | +----------------------+ | | | | +-+ | | |✓| Please send me product updates | | +-+ | | +-------------+ | | | Sign-up! | | | +-------------+ | +--------------------------------------+
  • 84. Showing prepopulated data Recall that we can send data to the view through the model object +--------------------------------------+ | | | +----------------------+ | | Name: | | | | +----------------------+ | | | | +----------------------+ | | Surname: | | | +--------------+ | +----------------------+ | | | | <----------+ Account bean | | +----------------------+ | | | | Date: | | | +--------------+ | +----------------------+ | | | | +-+ | | |✓| Please send me product updates | | +-+ | | +-------------+ | | | Sign-up! | | | +-------------+ | +--------------------------------------+
  • 85. Showing prepopulated data What if we let the AccountController return a prepopulated form bean as part of the model? Model Model +--------------+ +--------------+ | | | | | account | | account | +----------+ +--------------+ +-------------------+ +--------------+ +--------------------+ | | | | | | | View <--------------------+ DispatcherServlet <--------------------+ AccountController | | | | | | | +----------+ +-------------------+ +--------------------+
  • 86. AccountController @Controller public class AccountController { @RequestMapping(value="/account/new", method=RequestMethod.GET) public String getEmptyAccount(Model model) { model.addAttribute(new Account()); return "account/new"; } @RequestMapping(value="/account/new", method=RequestMethod.POST) public String addAccount(Account account) { ... } }
  • 87. Data binding-aware forms Once the prepopulated Account object is available in the view, we need to bind its content to the Web form +--------------------------------------+ | | | +----------------------+ | | Name: | | | | +----------------------+ | | | | +----------------------+ | | Surname: | | | +--------------+ | +----------------------+ | | | | <----------+ Account bean | | +----------------------+ | | | | Date: | | | +--------------+ | +----------------------+ | | | | +-+ | | |✓| Please send me product updates | | +-+ | | +-------------+ | | | Sign-up! | | | +-------------+ | +--------------------------------------+
  • 88. Spring form tag library To deal with prepopulated form beans, Spring provides a set of data binding-aware tags
  • 89. The revised registra-on form <form:form modelAttribute="account"> Name: <form:input path="name"/> <br/> Surname: <form:input path="surname"/> <br/> Email: <form:input path="email"/> <br/> Birthday: <form:input path="birthday"/> <br/> <form:checkbox path="marketingOk"/> Please send me product updates via e-mail <br/> <button type="submit">Sign-up<button/> </form:form>
  • 90. Form tags vs. HTML tags ┌───────────────────────────────────┬───────────────────────────┐ │ Spring form tag library │ HTML │ ├───────────────────────────────────┼───────────────────────────┤ │ <form:form> │ <form> │ ├───────────────────────────────────┼───────────────────────────┤ │ <input:text> │ <input type="text"> │ ├───────────────────────────────────┼───────────────────────────┤ │ <input:password> │ <input type="password"> │ ├───────────────────────────────────┼───────────────────────────┤ │ <input:checkbox> │ <input type="checkbox"> │ └───────────────────────────────────┴───────────────────────────┘
  • 91. Spring form tags The <form:input>, <form:password> and <form:checkbox> tags are data-binding versions of the corresponding HTML elements
  • 92. Spring form tags The tag library does not provide anything for submit bu(ons, as there is nothing to bind to <button type="submit">Sign-up<button/>
  • 93. Spring form tag library To use the tags from the form library, the following direc7ve needs to be added at the top of the JSP page: <%@ taglib prefix=”form" uri="http://www.springframework.org/tags/form" %>
  • 95. Users make mistakes No ma&er how intui/ve the registra/on form, users will accidentally fill it out with invalid informa,on +--------------------------------------+ | | | +----------------------+ | | Name: | | | | +----------------------+ | | | | +----------------------+ | | Surname: | | | | +----------------------+ | | | | +----------------------+ | | Date: | | | | +----------------------+ | | | | +-+ | | |✓| Please send me product updates | | +-+ | | +-------------+ | | | Sign-up! | | | +-------------+ | +--------------------------------------+
  • 96. Users make mistakes When this happens, we want to explain the error in nontechnical language and help the users to overcome it +--------------------------------------+ | | | +----------------------+ | | Name: | | | | +----------------------+ | | | | +----------------------+ | | Surname: | | | | +----------------------+ | | | | +----------------------+ | | Date: | | | | +----------------------+ | | | | +-+ | | | | Please send me product updates | | +-+ | | +-------------+ | | | Sign-up! | | | +-------------+ | +--------------------------------------+
  • 97. Data valida)on To detect user’s errors, we need to validate the form data that are encapsulated in the form bean public class Account { private String name; private String surname; private String email; private Date birthday; private boolean marketingOk = true; // getters and setters }
  • 98. Data valida)on Example: the email property should respect the pa/ern username@provider.tld public class Account { private String name; private String surname; private String email; private Date birthday; private boolean marketingOk = true; // getters and setters }
  • 99. Bean Valida*on API The Bean Valida*on API (JSR-303) is a specifica3on that defines a metadata model and API for JavaBean valida3on
  • 100. Bean Valida*on API Using this API, it is possible to annotate bean proper4es with declara*ve valida*on constraints • @NotNull, @Pattern, @Size
  • 101. Constraining Account public class Account { @Pattern(regexp="^[A-Z]{1}[a-z]+$") @Size(min=2, max=50) private String name; @Pattern(regexp="^[A-Z]{1}[a-z]+$") @Size(min=2, max=50) private String surname; @NotNull @Email private String email; @NotNull private Date birthday; }
  • 102. Constraining Account We impose name and surname to start with a capital le2er and have at least one addi4onal lowercase le2er public class Account { @Pattern(regexp="^[A-Z]{1}[a-z]+$") @Size(min=2, max=50) private String name; @Pattern(regexp="^[A-Z]{1}[a-z]+$") @Size(min=2, max=50) private String surname; }
  • 103. Constraining Account We impose email to respect the username@provider.tld pa.ern public class Account { @NotNull @Email private String email; }
  • 104. Hibernate Validator As with any other Java Enterprise Edi3on API, the standard defines only the API specifica,on
  • 105. Hibernate Validator We are going to use Hibernate Validator, which is the reference implementa5on of the JSR-303 specifica5on <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.1.3.Final</version> </dependency>
  • 106. Custom annota*ons Along with the standard constraints, Hibernate Validator provides some custom annota*ons (e.g., @Email) public class Account { @Email private String email; }
  • 107. Custom annota*ons Remember: those annota)ons are Hibernate-specific and they will not work with any other JSR-303 implementa)on public class Account { @Email private String email; }
  • 108. Valida&ng account Valida&on is achieved through the @Valid annota&on @RequestMapping(...) public String addAccount(@Valid Account account) { ... }
  • 109. Valida&ng account The @Valid annota)on causes the account object to be first validated and then added to the model @RequestMapping(...) public String addAccount(@Valid Account account) { ... }
  • 110. Valida&ng account The handler method may ask for a BindingResult object, which represent th result of the valida9on process @RequestMapping(...) public String addAccount(@Valid Account account, BindingResult bindingResult) { ... }
  • 111. Valida&ng account We can then inspect the bindingResult object for possible valida&on errors @RequestMapping(...) public String addAccount(@Valid Account account, BindingResult bindingResult) { if (bindingResult.hasErrors()) return "account/new"; ... }
  • 112. Data buffering Since the account bean is part of the model, it will be sent back to the view even in case of errors Model Model +--------------+ +--------------+ | | | | | account | | account | +----------+ +--------------+ +-------------------+ +--------------+ +--------------------+ | | | | | | | View <--------------------+ DispatcherServlet <--------------------+ AccountController | | | | | | | +----------+ +-------------------+ +--------------------+
  • 113. Data buffering Hence, the user is not forced to re-enter the data from scratch when asked to correct her mistakes +--------------------------------------+ | | | +----------------------+ | | Name: | Jon | | | +----------------------+ | | | | +----------------------+ | | Surname: | 1234 | | | +----------------------+ | | | | +----------------------+ | | Date: | | | | +----------------------+ | | | | +-+ | | | | Please send me product updates | | +-+ | | +-------------+ | | | Sign-up! | | | +-------------+ | +--------------------------------------+
  • 114. Data buffering Hence, the user can correct her mistakes, while keeping the correct data untouched +--------------------------------------+ | | | +----------------------+ | | Name: | Jon | | | +----------------------+ | | | | +----------------------+ | | Surname: | 1234 | | | +----------------------+ | | | | +----------------------+ | | Date: | | | | +----------------------+ | | | | +-+ | | | | Please send me product updates | | +-+ | | +-------------+ | | | Sign-up! | | | +-------------+ | +--------------------------------------+
  • 115. Error messages Even if we returned the ini.al form, we s.ll have to inform the user on the reason why the data have been rejected +--------------------------------------+ | | | +----------------------+ | | Name: | Jon | | | +----------------------+ | | | | +----------------------+ | "Hey user, the | Surname: | snow <----------+ surname should | +----------------------+ | start with a | | capital letter" | +----------------------+ | | Date: | | | | +----------------------+ | | | | +-+ | | | | Please send me product updates | | +-+ | | +-------------+ | | | Sign-up! | | | +-------------+ | +--------------------------------------+
  • 116. Error messages To this end, the BindingResult object is automa&cally inserted into the model and sent back to the view Model Model +--------------+ +--------------+ | account | | account | +--------------+ +--------------+ |bindingResult | |bindingResult | +----------+ +--------------+ +-------------------+ +--------------+ +--------------------+ | | | | | | | View <--------------------+ DispatcherServlet <--------------------+ AccountController | | | | | | | +----------+ +-------------------+ +--------------------+
  • 117. <form:errors> Spring MVC provides the <form:errors> tag as part of the Spring’s form tag library <form:errors path="name"/>
  • 118. <form:errors> The <form:errors> tag renders in HTML error messages taken from the BindingResult object
  • 119. <form:errors> <form:form modelAttribute="account"> Name: <form:input path="name"/> <form:errors path="name"/> <br/> Surname: <form:input path="surname"/> <form:errors path="surname"/> <br/> Email: <form:input path="email"/> <form:errors path="email"/> <br/> ... </form:form>
  • 120. User-centric error messages Unfortunately, most of the default Hibernate validator error messages are not par8cularly user-centric
  • 121. User-centric error messages For instance, @Pattern's default message shows a reference to the regular expression to be respected
  • 122.
  • 123. Message interpola.on Message interpola.on is the process of crea-ng error messages for violated Bean Valida-on constraints +--------------------------------------+ | | | +----------------------+ | | Name: | | | | +----------------------+ | | | | +----------------------+ | | Surname: | | | | +----------------------+ | | | | +----------------------+ | | Date: | | | | +----------------------+ | | | | +-+ | | | | Please send me product updates | | +-+ | | +-------------+ | | | Sign-up! | | | +-------------+ | +--------------------------------------+
  • 124. Message interpola.on We can define the message descriptor of each property through the message a4ribute public class Account { @NotNull(message = "the email address cannot be empty") @Email(message = "please provide a valid e-mail address") private String email; }
  • 125. Message interpola.on The problem with message a1ributes is that we are hard-coding the error messages public class Account { @NotNull(message = "the email address cannot be empty") @Email(message = "please provide a valid e-mail address") private String email; }
  • 126. What if we want the messages to change according to, e.g., the user’s locale?
  • 127. Resource bundle A be%er alterna+ve is to store the error messages in a separate file, called the resource bundle
  • 128. Resource bundle By doing so, error messages can be updated independently of the source code (and vice versa)
  • 129. Resource bundle We may devise the following resource bundle: NotBlank.account.email=the email address cannot be empty Email.account.email=please provide a valid e-mail address NotNull.account.birthday=The date cannot be empty
  • 130. Resource bundle Spring’s conven.on dictates the following syntax for messages: [ConstraintName].[ClassName].[FieldName]=[Message]
  • 131. MessageSource If we decide to externalize messages from the code, we need a source from which to get the messages, i.e., a MessageSource
  • 132. MessageSource Specifically, in order to load messages from a resource bundle, we need a ReloadableResourceBundleMessageSource bean
  • 133.
  • 134. Adding a MessageSource We therefore change frontcontroller-servlet.xml in order to have the Spring DI Container load the MessageSource5 <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="classpath:validationMessages" /> </bean> 5 Remember: the MessageSource bean must have the id equal to messageSource
  • 135. Using message codes We can now specify the message code in lieu of the message itself public class Account { @NotBlank(message = "{NotBlank.account.email}") @Email(message = "{Email.account.email}") private String email; }
  • 137. Duplicate submissions Most of the )mes, form data are submi2ed as POST requests +--------------+ +--------------+ | +------- POST --------> | | Browser | | Web app | | <------ 200 OK -------+ | +--------------+ +--------------+
  • 138. Duplicate submissions What if the user presses refresh on the browser? +--------------+ +--------------+ | +------- POST --------> | | Browser | | Web app | | <------ 200 OK -------+ | +--------------+ +--------------+
  • 139. Duplicate submissions Since refreshing means resending the latest HTTP request, it will cause the HTTP POST to be resubmi+ed +--------------+ +--------------+ +-------> +------- POST --------> | Refresh | | Browser | | Web app | +-------+ <------ 200 OK -------+ | +--------------+ +--------------+
  • 140. Duplicate submissions Given the unsafe nature of POST, resending the latest POST request may lead to unwanted results +--------------+ +--------------+ +-------> +------- POST --------> | Refresh | | Browser | | Web app | +-------+ <------ 200 OK -------+ | +--------------+ +--------------+
  • 141. The PRG pa*ern The Post/Redirect/Get (PRG) pa/ern solves the duplicate submission problem
  • 142. The PRG pa*ern According to the PRG pa2ern, the Web app should not immediately return the outcome of the POST opera?ons +--------------+ +--------------+ | +------- POST --------> | | Browser | | Web app | | <------ 200 OK -------+ | +--------------+ +--------------+
  • 143. The PRG pa*ern Instead, the Web applica1on should answer with a redirect response +--------------+ +--------------+ | +------- POST --------> | | Browser | | Web app | | <--- 3xx REDIRECT ----+ | +--------------+ +--------------+
  • 144. The PRG pa*ern This causes the client to automa/cally issue a new GET request, to which the Web app finally answers with the actual content +--------------+ +--------------+ | +------- GET -------> | | Browser | | Web app | | <------ 200 OK -------+ | +--------------+ +--------------+
  • 145. The PRG pa*ern Thus, if the user refreshes the page, the GET request will be send, instead of the original HTTP POST +--------------+ +--------------+ +-------> +------- GET -------> | Refresh | | Browser | | Web app | +-------+ <------ 200 OK -------+ | +--------------+ +--------------+
  • 146. Redirec'ng In order to force a redirect, it is sufficient to return the redirect URL prefixed with the label redirect: @RequestMapping(...) public String addAccount(@Valid Account account, BindingResult bindingResult) { if (bindingResult.hasErrors()) return "account/edit"; service.saveAccount(account); return "redirect:/account/thanks"; }
  • 147. Redirec'ng The redirect: prefix is used as a special indica+on that a redirect is needed @RequestMapping(...) public String addAccount(@Valid Account account, BindingResult bindingResult) { if (bindingResult.hasErrors()) return "account/edit"; service.saveAccount(account); return "redirect:/account/thanks"; }
  • 148. Redirec'ng Note that what follows redirect: is used as the redirect URL @RequestMapping(...) public String addAccount(@Valid Account account, BindingResult bindingResult) { if (bindingResult.hasErrors()) return "account/edit"; service.saveAccount(account); return "redirect:/account/thanks"; }
  • 149. Redirec'ng That is, /account/thanks has to be intended as http://myserver.com/webapp/account/thanks @RequestMapping(...) public String addAccount(@Valid Account account, BindingResult bindingResult) { if (bindingResult.hasErrors()) return "account/edit"; service.saveAccount(account); return "redirect:/account/thanks"; }
  • 150. View controllers We need to associate a handler method with /account/thanks @Controller @RequestMapping("/account") public class AccountController { @RequestMapping("/thanks") public String getThanks() { return "thanks"; } }
  • 151. View controllers The sole responsibility of such a handler method would be to return the /account/thanks view name @RequestMapping("/thanks") public String getThanks() { return "thanks"; }
  • 152. View controllers Star%ng from Spring 3, it is possible to declara've set up controllers whose unique responsibility is to return a view name
  • 153. View controllers The following declares in frontcontroller-servlet.xml a controller capable of answering to /account/thanks <mvc:view-controller path="/account/thanks” view-name="account/thanks"/>
  • 154. Model life)me As the model contains the data to be rendered by the view, its life6me is limited by the request/response lifecycle
  • 155. Model life)me In other words, a new model object is created for each request that hits DispatcherServlet +-------+ HTTP | Model | request +---------------------+ +-------+ +--------------+ | | | | +-------> DispatcherServlet +-------------> Controller | | | | | +---------------------+ +--------------+
  • 156. PRG pa'ern vs. model a'ributes A redirect creates a new request, hence causing the model a3ributes to be discarded +--------------+ +--------------+ | +------- POST --------> | | Browser | | Web app | | <--- 3xx REDIRECT ----+ | +--------------+ +--------------+
  • 157. What if we want to retain some model a1ributes?
  • 158. The flash scope A possible solu+on is store a0ributes of interest in the flash scope
  • 159. The flash scope The flash scope works similarly to the session scope +-----+ Request +-----+ | +----------------> | +--+-------+-+ | | | | | | | | Response | | | F | | <----------------+ | | l | | B | | W | | a | | r | Request | e | S | s | | o +----------------> b | e | h | | w | | | s | | | s | Response | a | s | | | e <----------------+ p +------ i | ------v-- | r | | p | o | | | Request | | n | | +----------------> | | | | | | | | | Response | | | | <----------------+ +---------v--- +-----+ +-----+
  • 160. The flash scope The difference is that flash a&ributes are kept solely for the subsequent request +-----+ Request +-----+ | +----------------> | +--+-------+-+ | | | | | | | | Response | | | F | | <----------------+ | | l | | B | | W | | a | | r | Request | e | S | s | | o +----------------> b | e | h | | w | | | s | | | s | Response | a | s | | | e <----------------+ p +------ i | ------v-- | r | | p | o | | | Request | | n | | +----------------> | | | | | | | | | Response | | | | <----------------+ +---------v--- +-----+ +-----+
  • 161. The flash scope Flash a'ributes are stored before the redirect and made available as model a'ributes a2er the redirect +-----+ Request +-----+ | +----------------> | +--+-------+-+ | | | | | | | | Response | | | F | | <----------------+ | | l | | B | | W | | a | | r | Request | e | S | s | | o +----------------> b | e | h | | w | | | s | | | s | Response | a | s | | | e <----------------+ p +------ i | ------v-- | r | | p | o | | | Request | | n | | +----------------> | | | | | | | | | Response | | | | <----------------+ +---------v--- +-----+ +-----+
  • 162. RedirectAttributes A handler method can declare an argument of type RedirectAttributes... @RequestMapping(...) public String addAccount(@Valid Account account, BindingResult bindingResult, RedirectAttributes redirectAttributes) {...}
  • 163. RedirectAttributes ...and use its addFlashAttribute() method to add a.ributes in the flash scope @RequestMapping(...) public String addAccount(@Valid Account account, BindingResult bindingResult, RedirectAttributes redirectAttributes) { if (bindingResult.hasErrors()) return "account/new"; redirectAttributes.addFlashAttribute("account", account); return ”redirect:/account/thanks”; }
  • 164. The "Thank you" page account is accessible in the view, since it has been automa2cally inserted into the next request model <html> <head> <title>Thanks</title> </head> <body> Hi, ${account.name} ${account.surname}. You have been successfully registered. <br/> </body> </html>
  • 165. Recap
  • 166. Form beans Form beans are versa&le objects, as they play different roles at the same 1me • Data binder • Data buffer • Data validator
  • 167. Data binder Developers can work with a trusty POJO and leave all the HTML/ HTTP issues to the framework • Binding • Coercion
  • 168. Data buffer The form bean is not the des0na0on of the input, but a buffer that preserves the input un0l it can be validated and commi7ed to the service layer
  • 169. Data validator Many fields must be the correct type before they can be processed by the business logic
  • 171. References • Stackoverflow, GET vs. POST does it really ma;er? • Stackoverflow, HTTP GET with request body • R. Fielding, Introductory REST ArHcle • IETF, Hypertext Transfer Protocol – HTTP/1.1 (RFC 2616) • SpringSource, Spring Framework Reference
  • 172. References • SpringSource, Java-doc APIs • Wikipedia, Post/Redirect/Get • Wikipedia, Bean Valida@on • Hibernate, Hibernate Validator reference guide
  • 173. References • Craig Walls, Spring in Ac1on (3rd ed.), Manning Publica1ons • Willie Wheeler, Spring in Prac1ce, Manning Publica1ons • T. N. Husted et al., Struts 1 In Ac1on, Manning Publica1ons