Input Validation ================================================================================ .. only:: html .. contents:: Table of Contents :depth: 4 Overview -------------------------------------------------------------------------------- It is mandatory to check whether the value entered by the user is correct. Validation of input value is broadly classified into #. Validation to determine whether the input value is valid by just looking at it irrespective of the context such as size and format. #. Validation of whether the changes in input value are valid depending on the system status. 1. is an example of mandatory check and number of digits check and 2. is an example of check of whether EMail is registered and whether order count is within the count of the available stock. In this section, 1. is explained and this check is called "Input validation". 2. is called "Business logic check". For business logic check, refer to \ :doc:`../../ImplementationAtEachLayer/DomainLayer`\ . In this guideline, validation check should be performed in application layer whereas business logic check should be performed in domain layer. Input validation of Web application is performed at server side and client side (JavaScript). It is mandatory to check at the Server Side. However, if the same check is performed at the client side also, usability improves since validation results can be analyzed without communicating with the server. .. warning:: Input validation should be performed at the server side as the process at client side may be altered using JavaScript. If the validation is performed only at the client side without performing at the server side, the system may be exposed to danger. .. todo:: Input validation at client side will be explained later. Only input validation at the server side is mentioned in the first version. Classification of input validation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Input validation is classified into single item check and correlation item check. .. tabularcolumns:: |p{0.15\linewidth}|p{0.30\linewidth}|p{0.25\linewidth}|p{0.30\linewidth}| .. list-table:: :header-rows: 1 :widths: 15 30 25 30 * - Type - Description - Example - Implementation method * - Single item check - | Check completed in single field - | Input mandatory check | Digit check | Type check - | Bean Validation (Hibernate Validator is used as implementation library) * - Correlation item check - | Check comparing multiple fields - | Password and confirm password check - | Bean Validation or Validation class implementing `org.springframework.validation.Validator `_\ | interface Spring supports Bean Validation which is a Java standard. This Bean Validation is used for single item check. Bean Validation or \ ``org.springframework.validation.Validator``\ interface provided by Spring is used for correlation item check. .. _Validation_how_to_use: How to use -------------------------------------------------------------------------------- .. ValidationAddDependencyLibrary: Adding dependent libraries ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When Bean validation 1.1 (Hibernate Validator 5.x) or higher version is to be used, in addition to jar file of Hibernate Validator and jar file storing API specifications class (\ ``javax.validation``\ package class) of Bean Validation, libraries that store the following classes are required. * API specifications class of Expression Language 2.2 or higher version (\ ``javax.el``\ package class) * Reference implementation class of Expression Language 2.2 or higher version If the file is run by deploying on application server, dependent libraries need not be added; since these libraries are provided by application server. However, when it is run in standalone environment (JUnit etc.), these libraries need to be added as dependent libraries. An example of adding libraries which are required when running Bean Validation 1.1 or higher version in standalone environment is given below. .. code-block:: xml org.apache.tomcat.embed tomcat-embed-el test .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - Add a library wherein a class for Expression Language is stored, in :file:`pom.xml` file of the project to be run in standalone environment. In the above example, libraries provided for Apache Tomcat to be embedded are specified. API specifications classes of Expression Language and reference implementation classes are both stored in jar file of \ ``tomcat-embed-el``\ . * - | (2) - When dependent libraries are required to execute JUnit, an appropriate scope is \ ``test``\ . .. note:: In the above setting example, since it is assumed that the dependent library version is managed by the parent project terasoluna-gfw-parent , specifying the version in pom.xml is not necessary. The above dependent library used by terasoluna-gfw-parent is defined by \ `Spring IO Platform `_\ . .. _Validation_single_check: Single item check ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For the implementation of single item check following points are necessary, * Bean Validation annotation should be assigned to the field of form class * \ ``@Validated``\ annotation should be assigned in Controller for validation * Tag for displaying validation error message should be added to JSP .. note:: \ ````\ settings are carried out in spring-mvc.xml, Bean Validation is enabled. .. _Validation_basic_validation: Basic single item check """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" Implementation method is explained using "New user registration" process as an example. Rules for checking "New user registration" form are provided below. .. tabularcolumns:: |p{0.20\linewidth}|p{0.30\linewidth}|p{0.50\linewidth}| .. list-table:: :header-rows: 1 :widths: 20 30 50 * - Field name - Type - Rules * - | name - | ``java.lang.String`` - | Mandatory input | Between 1 and | 20 characters * - | email - | ``java.lang.String`` - | Mandatory input | Between 1 and | 50 characters | Email format * - | age - | ``java.lang.Integer`` - | Mandatory input | Between 1 and | 200 * Form class Assign Bean Validation annotation to each field of form class. .. code-block:: java package com.example.sample.app.validation; import java.io.Serializable; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import org.hibernate.validator.constraints.Email; public class UserForm implements Serializable { private static final long serialVersionUID = 1L; @NotNull // (1) @Size(min = 1, max = 20) // (2) private String name; @NotNull @Size(min = 1, max = 50) @Email // (3) private String email; @NotNull // (4) @Min(0) // (5) @Max(200) // (6) private Integer age; // omitted setter/getter } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | Assign \ ``javax.validation.constraints.NotNull``\ indicating that the target field is not \ ``null``\ . | | In Spring MVC, when form is sent with input fields left blank, | \ **empty string instead of null binds**\ to form object by default. | This \ ``@NotNull``\ checks that \ ``name``\ exists as request parameter. * - | (2) - | Assign \ ``javax.validation.constraints.Size``\ indicating that the string length (or collection size) of the target field is within the specified size range. | | Since empty string binds to the field where string is left blank by default in Spring MVC, | '1 or more character' rule indicates Mandatory input. * - | (3) - | Assign \ ``org.hibernate.validator.constraints.Email``\ indicating that the target field is in RFC2822-compliant E-mail format. | When E-mail format requirements are flexible than RFC2822-compliant constraints, regular expression should be specified using \ ``javax.validation.constraints.Pattern``\ instead of \ ``@Email``\ . * - | (4) - | When form is sent without entering any number in input field, \ ``null`` \ binds to form object so \ ``@NotNull``\ indicates mandatory input of \ ``age``\. * - | (5) - | Assign \ ``javax.validation.constraints.Min``\ indicating that the target field value must be greater than the specified value. * - | (6) - | Assign \ ``javax.validation.constraints.Max``\ indicating that the target field value must be less than the specified value. .. tip:: Refer to \ :ref:`Validation_jsr303_doc`\ and \ :ref:`Validation_validator_list`\ for standard annotations of Bean Validation and annotations provided by Hibernate. .. tip:: Refer to \ :ref:`Validation_string_trimmer_editor`\ for the method of binding \ ``null``\ when input field is left blank. * Controller class Assign \ ``@Validated``\ to form class for input validation. .. code-block:: java package com.example.sample.app.validation; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping("user") public class UserController { @ModelAttribute public UserForm setupForm() { return new UserForm(); } @RequestMapping(value = "create", method = RequestMethod.GET, params = "form") public String createForm() { return "user/createForm"; // (1) } @RequestMapping(value = "create", method = RequestMethod.POST, params = "confirm") public String createConfirm(@Validated /* (2) */ UserForm form, BindingResult /* (3) */ result) { if (result.hasErrors()) { // (4) return "user/createForm"; } return "user/createConfirm"; } @RequestMapping(value = "create", method = RequestMethod.POST) public String create(@Validated UserForm form, BindingResult result) { // (5) if (result.hasErrors()) { return "user/createForm"; } // omitted business logic return "redirect:/user/create?complete"; } @RequestMapping(value = "create", method = RequestMethod.GET, params = "complete") public String createComplete() { return "user/createComplete"; } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | Display "New user registration" form screen. * - | (2) - | Assign \ ``org.springframework.validation.annotation.Validated``\ to the form class argument to perform input validation. * - | (3) - | Add \ ``org.springframework.validation.BindingResult``\ that stores check result of input validation performed in step (2). | This \ ``BindingResult``\ must be specified immediately after the form argument. | | When not specified immediately, \ ``org.springframework.validation.BindException``\ is thrown. * - | (4) - | Use \ ``BindingResult.hasErrors()``\ method to determine the check result of step (2). | When the result of \ ``hasErrors()``\ is \ ``true``\ , return to form display screen as there is an error in input value. * - | (5) - | \ **Input validation should be executed again**\ even at the time of submission on the confirmation screen. | There is a possibility of data tempering and hence Input validation must be performed just before entering business logic. .. note:: \ ``@Validated``\ is not a standard Bean Validation annotation. It is an independent annotation provided by Spring. Bean Validation standard \ ``javax.validation.Valid``\ annotation can also be used. However, \ ``@Validated``\ is better as compared to \ ``@Valid``\ annotation. Validation group can be specified in case of \ ``@Validated``\ and hence \ ``@Validated``\ is recommended in this guideline. .. _Validation_jsp_impl_sample: * JSP When there is input error, it can be displayed in \ ````\ tag. .. code-block:: jsp <%-- WEB-INF/views/user/createForm.jsp --%> Name: <%--(1) --%>
Email:
Age:
Confirm
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | Specify target field name in \ ``path``\ attribute of \ ````\ tag. | Error message is displayed next to input field of each field. Form is displayed as follows. .. figure:: ./images_Validation/validations-first-sample1.png :width: 60% Error message is displayed as follows if this form is sent with all the input fields left blank. .. figure:: ./images_Validation/validations-first-sample2.png :width: 60% Error messages state that Name and Email are blank and Age is \ ``null``\ . .. note:: In Bean Validation, ``null``\ is a valid input value except the following annotations. * ``javax.validation.constraints.NotNull`` * ``org.hibernate.validator.constraints.NotEmpty`` * ``org.hibernate.validator.constraints.NotBlank`` In the above example, error messages related to ``@Min``\ and \ ``@Max``\ annotations are not displayed. This is because \ ``null``\ is a valid value for \ ``@Min``\ and \ ``@Max``\ annotations. Next, send the form by entering any value in the field. .. figure:: ./images_Validation/validations-first-sample3.png :width: 60% | Error message is not displayed since input value of Name fulfills validation conditions. | Error message is displayed since input value of Email is not in Email format though it fulfills the conditions related to string length. | Error message is displayed since input value of Age exceeds maximum value. Change the form as follows to change the style at the time of error. .. code-block:: jsp Name:<%-- (1) --%> <%-- (2) --%> <%-- (3) --%>
Email:
Age:
Confirm
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | Specify class name for \ ``