First application based on Spring MVC -------------------------------------------------------------- .. only:: html .. contents:: Index :depth: 3 :local: Before entering into the advanced usage of Spring MVC, it is better to understand Spring MVC by actually trying hands-on web application development using Spring MVC. Prerequisites ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The description of this chapter has been verified on the following environment. (For other environments, replace the contents mentioned here appropriately) .. tabularcolumns:: |p{0.25\linewidth}|p{0.75\linewidth}| .. list-table:: :header-rows: 1 :widths: 25 75 * - Classification - Product * - OS - Windows 7 * - JVM - Java 1.7 * - IDE - Spring Tool Suite 3.6.3.RELEASE (Hereafter referred as [STS]) * - Build Tool - Apache Maven 3.2.5 (Hereafter referred as [Maven]) * - Application Server - Pivotal tc Server Developer Edition v3.0 (Hereafter referred as [tc Server]) * - Web Browser - Google Chrome 39.0.2171.99 m .. note:: To connect the internet via proxy server, STS Proxy settings and \ `Maven Proxy settings `_\ are required for the following operations. Create a New Project ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Create project using `mvn archetype:generate` on internet. .. code-block:: console mvn archetype:generate -B^ -DarchetypeCatalog=http://repo.terasoluna.org/nexus/content/repositories/terasoluna-gfw-releases^ -DarchetypeGroupId=org.terasoluna.gfw.blank^ -DarchetypeArtifactId=terasoluna-gfw-web-blank-archetype^ -DarchetypeVersion=5.0.2.RELEASE^ -DgroupId=com.example.helloworld^ -DartifactId=helloworld^ -Dversion=1.0.0-SNAPSHOT Here, created a project on Windows environment. .. code-block:: console C:\work>mvn archetype:generate -B^ More? -DarchetypeCatalog=http://repo.terasoluna.org/nexus/content/repositories/terasoluna-gfw-releases^ More? -DarchetypeGroupId=org.terasoluna.gfw.blank^ More? -DarchetypeArtifactId=terasoluna-gfw-web-blank-archetype^ More? -DarchetypeVersion=5.0.2.RELEASE^ More? -DgroupId=com.example.helloworld^ More? -DartifactId=helloworld^ More? -Dversion=1.0.0-SNAPSHOT [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building Maven Stub Project (No POM) 1 [INFO] ------------------------------------------------------------------------ [INFO] [INFO] >>> maven-archetype-plugin:2.2:generate (default-cli) > generate-sources @ standalone-pom >>> [INFO] [INFO] <<< maven-archetype-plugin:2.2:generate (default-cli) < generate-sources @ standalone-pom <<< [INFO] [INFO] --- maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom --- [INFO] Generating project in Batch mode [INFO] Archetype repository missing. Using the one from [org.terasoluna.gfw.blank:terasoluna-gfw-web-blank-archetype:1.0.0.RELEASE -> http://repo.terasoluna.org/nexus/content/repositories/terasoluna-gfw-releases] found in catalog http://repo.terasoluna.org/nexus/content/repositories/terasoluna-gfw-releases [INFO] ---------------------------------------------------------------------------- [INFO] Using following parameters for creating project from Archetype: terasoluna-gfw-web-blank-archetype:5.0.2.RELEASE [INFO] ---------------------------------------------------------------------------- [INFO] Parameter: groupId, Value: com.example.helloworld [INFO] Parameter: artifactId, Value: helloworld [INFO] Parameter: version, Value: 1.0.0-SNAPSHOT [INFO] Parameter: package, Value: com.example.helloworld [INFO] Parameter: packageInPathFormat, Value: com/example/helloworld [INFO] Parameter: package, Value: com.example.helloworld [INFO] Parameter: version, Value: 1.0.0-SNAPSHOT [INFO] Parameter: groupId, Value: com.example.helloworld [INFO] Parameter: artifactId, Value: helloworld [INFO] project created from Archetype in dir: C:\work\helloworld [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.631 s [INFO] Finished at: 2015-07-31T08:47:12+00:00 [INFO] Final Memory: 11M/26M [INFO] ------------------------------------------------------------------------ C:\work> Select the archetype created project from STS menu [File] -> [Import] -> [Maven] -> [Existing Maven Projects] -> [Next]. .. figure:: images/NewMVCProjectImport.png :alt: New MVC Project Import :width: 60% Click on [Finish] by selecting \ ``C:\work\helloworld`` \ in Root Directory and selecting pom.xml of helloworld in Projects. .. figure:: images/NewMVCProjectCreate.png :alt: New MVC Project Import :width: 60% Following project is generated in the Package Explorer. .. figure:: images/HelloWorldWorkspace.png :alt: workspace To understand the configuration of Spring MVC, the generated Spring MVC configuration file (src/main/resources/META-INF/spring/spring-mvc.xml) is described briefly. .. code-block:: xml :emphasize-lines: 15-16, 27-28, 67-73 .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - Default settings of Spring MVC are configured by defining \ ````\. Refer to the official website `Enabling the MVC Java Config or the MVC XML Namespace `_ for default configuration of Spring framework. * - | (2) - Define the package which will be target of searching components used in Spring MVC. * - | (3) - Define the location of the JSP by specifying \ ``ViewResolver`` \ for JSP. .. tip:: \ ```` \ element is a XML element that added from Spring Framework 4.1. By using \ ```` \ element, it is possible to define \ ``ViewResolver`` \ simply. The definition example of using the conventional \ ```` \ element is shown below. .. code-block:: xml | Next, Controller (\ ``com.example.helloworld.app.welcome.HomeController``\ ) for displaying the Welcome page is described briefly. .. code-block:: java :emphasize-lines: 17,26,36,38 package com.example.helloworld.app.welcome; import java.text.DateFormat; import java.util.Date; import java.util.Locale; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; /** * Handles requests for the application home page. */ @Controller // (4) public class HomeController { private static final Logger logger = LoggerFactory .getLogger(HomeController.class); /** * Simply selects the home view to render by returning its name. */ @RequestMapping(value = "/", method = {RequestMethod.GET, RequestMethod.POST}) // (5) public String home(Locale locale, Model model) { logger.info("Welcome home! The client locale is {}.", locale); Date date = new Date(); DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale); String formattedDate = dateFormat.format(date); model.addAttribute("serverTime", formattedDate); // (6) return "welcome/home"; // (7) } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (4) - It can be read automatically by DI container if ``@Controller`` annotation is used. As stated earlier in [explanation of Spring MVC configuration files (2)], it is the target of component-scan. * - | (5) - It gets executed when the HTTP method is GET or POST and the Resource is (or request URL) is "/". * - | (6) - Set \ ``Model`` \ object to be delivered to View. * - | (7) - Return View name. "WEB-INF/views/welcome/home.jsp" is rendered as per the configuration [Explanation of Spring MVC configuration files (3)] . | Lastly, JSP (\ ``src/main/webapp/WEB-INF/views/welcome/home.jsp``\ ) for displaying the Welcome page is described briefly. .. code-block:: jsp :emphasize-lines: 12 Home

Hello world!

The time on the server is ${serverTime}.

<%-- (8) --%>
.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (8) - As stated earlier in [explanation of Controller (6)] the object (serverTime) set in Model is stored in HttpServletRequest. Therefore the value passed from Controller can be output by mentioning \ ``${serverTime}`` \ in JSP. **However about ${XXX}, it is necessary to perform HTML escaping since there is possibility of XSS attack.** | Run on Server ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | Right click "helloworld" project in STS, and start helloworld project by executing "Run As" -> "Run On Server" -> "localhost" -> "Pivotal tc Server Developer Edition v3.0" -> "Finish". | Enter "http://localhost:8080/helloworld/" in browser to display the following screen. .. figure:: images/AppHelloWorldIndex.png :alt: Hello World .. note:: Since tc Server internally uses the Tomcat, it is possible to choose below two versions in the STS. * tomcat-8.0.15.A.RELEASE (version used by default) * tomcat-7-0.57.A.RELEASE If you want to switch the Tomcat to be used, change the [Version] field of ts Server by opening the [Edit Server Runtime Environment] dialog box. Java (JRE) version can also be changed from this dialog box. .. figure:: images/EditServerRuntimeEnvironment.png :alt: Edit Server Runtime Environment :width: 80% | .. _first-application-create-an-echo-application: Create an Echo Application ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Lets go ahead and create a simple application. It is a typical eco application in which message will be displayed if name is entered in the text field as given below. .. figure:: images/AppEchoIndex.png :alt: Form of Echo Application .. figure:: images/AppEchoHello.png :alt: Output of Echo Application | Creating a form object ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | First create a form object to accept the value of text field. | Create \ ``EchoForm`` \ class under \ ``com.example.helloworld.app.echo`` \ package. It is a simple JavaBean that has only one1 property. .. code-block:: java package com.example.helloworld.app.echo; import java.io.Serializable; public class EchoForm implements Serializable { private static final long serialVersionUID = 2557725707095364445L; private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } } | Create a Controller ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | Next, create the Controller class. | create the ``EchoController`` class under ``com.example.helloworld.app.echo`` package. .. code-block:: java :emphasize-lines: 10,13,19,21,24-26 package com.example.helloworld.app.echo; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping("echo") public class EchoController { @ModelAttribute // (1) public EchoForm setUpEchoForm() { EchoForm form = new EchoForm(); return form; } @RequestMapping // (2) public String index(Model model) { return "echo/index"; // (3) } @RequestMapping(value = "hello", method = RequestMethod.POST) // (4) public String hello(EchoForm form, Model model) {// (5) model.addAttribute("name", form.getName()); // (6) return "echo/hello"; } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | Add ``@ModelAttribute`` annotation to the method. Return value of such a method is automatically added to the Model. | Attribute name of the Model can be specified in ``@ModelAttribute``, but the class name with the first letter in lower case is the default attribute name. In this case it will be "echoForm". This attribute name must match with the value of ``modelAttribute`` of ``form:form tag``. * - | (2) - | When nothing is specified in ``value`` attribute of ``@RequestMapping`` annotation at the method level, it is mapped to ``@RequestMapping`` added at class level. In this case, ``index`` method is called, if "/echo" is accessed. | When nothing is set in ``method`` attribute, mapping is done for any HTTP method. * - | (3) - | Since "echo/index" is returned as View name, "WEB-INF/views/echo/index.jsp" is rendered by the ViewResolver. * - | (4) - | Since "hello" is specified in \ ``value`` \ attribute and \ ``RequestMethod.POST`` \ is specified in \ ``method`` \ attribute of the ``@RequestMapping`` annotation method, if "/echo/hello" is accessed with POST method, ``hello`` method is called. * - | (5) - | EchoForm object added to the model in (1) is passed as argument. * - | (6) - | ``name`` entered in form is passed as it is to the View. .. note:: The value specified in the \ ``method`` \ attribute of \ ``@RequestMapping`` \ annotation is generally varied by how the data transmitted from the client. * POST method in case of storing data to the server (in case of updating process). * GET method or unspecified (any method) in case of not storing data to the server (in case of referring process). In echo application, * \ ``index`` \ method is not going to save data to the server, it is unspecified (any method) * \ ``hello`` \ method is going to save data into \ ``Model`` \ object, it is POST method etc are specified. | Create JSP Files ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Finally create JSP for input screen and output screen. Each file path must match with View name as follows. Create input screen (src/main/webapp/WEB-INF/views/echo/index.jsp). .. code-block:: jsp :emphasize-lines: 7-8 Echo Application <%-- (1) --%> Input Your Name: .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | HTML form is constructed using tag library. Specify the name of form object created by Controller in ``modelAttribute`` attribute. | Refer `here `_ for tag library. .. note:: POST method is used if \ ``method`` \ attribute of \ ```` \ tag is omitted. The generated HTML is as follows .. code-block:: html :emphasize-lines: 7 Echo Application
| Create output screen (src/main/webapp/WEB-INF/views/echo/hello.jsp). .. code-block:: jsp :emphasize-lines: 8 Echo Application

Hello <%-- (2) --%>

.. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (2) - | Output "name" passed from Controller. Take countermeasures for XSS using ``c:out`` tag. .. note:: Here, XSS countermeasure taken using ``c:out`` standard tag, however, ``f:h()`` function provided in common library can be used easily. Refer to :doc:`../Security/XSS` for details. | | Implementation of Eco application is completed here. | Start the server and form will be displayed by accessing "http://localhost:8080/helloworld/echo". | Implement Input Validation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Till this point Input validation is not implemented in this application. In Spring MVC, `Bean Validation `_ \ and annotation based input validation can be easily implemented. For example name input validation is performed in Eco Application. Add annotation for Input check rule to the \ ``name`` \ of \ ``EchoForm``\. .. code-block:: java :emphasize-lines: 5,6,11,12 package com.example.helloworld.app.echo; import java.io.Serializable; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; public class EchoForm implements Serializable { private static final long serialVersionUID = 2557725707095364445L; @NotNull // (1) @Size(min = 1, max = 5) // (2) private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | Whether ``name`` parameter exists in HTTP request or not can be checked by ``@NotNull`` annotation. * - | (2) - | Whether the size of ``name`` is more than or equal to 1 and less than or equal to 5 can be checked by ``@Size(min = 1, max = 5)``. | Implement the input check and the error handling when an error occurs in the input check. .. code-block:: java :emphasize-lines: 5,6,27-30 package com.example.helloworld.app.echo; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; 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("echo") public class EchoController { @ModelAttribute public EchoForm setUpEchoForm() { EchoForm form = new EchoForm(); return form; } @RequestMapping public String index(Model model) { return "echo/index"; } @RequestMapping(value = "hello", method = RequestMethod.POST) public String hello(@Validated EchoForm form, BindingResult result, Model model) { // (1) if (result.hasErrors()) { // (2) return "echo/index"; } model.addAttribute("name", form.getName()); return "echo/hello"; } } .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | In Controller, add ``@Validated`` annotation to the argument on which validation needs to be executed. Also add ``BindingResult`` object to the arguments. | Input validation is automatically performed using Bean Validation and the result is stored in ``BindingResult`` object. * - | (2) - | Error can be checked by executing ``hasErrors`` method. If there is an input error, it returns View name to display the input screen. | Add the implementation of displaying input error message on input screen (src/main/webapp/WEB-INF/views/echo/index.jsp). .. code-block:: jsp :emphasize-lines: 10 Echo Application Input Your Name: <%-- (1) --%> .. tabularcolumns:: |p{0.10\linewidth}|p{0.90\linewidth}| .. list-table:: :header-rows: 1 :widths: 10 90 * - Sr. No. - Description * - | (1) - | Add ``form:errors`` tag for displaying error message when an error occurs on input screen. | | Implementation of input validation is completed. | Error message is displayed in the following conditions: * When an empty name is sent * Size is more than 5 characters. .. figure:: images/AppValidationEmpty.png :alt: Validation Error (name is empty) .. figure:: images/AppValidationSizeOver.png :alt: Validation Error (name's size is over 5) The generated HTML is as follows. .. code-block:: html :emphasize-lines: 10 Echo Application
size must be between 1 and 5
| Summary ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The following are the learnings from this chapter. #. How to create blank project using \ ``mvn archetype:generate``\. #. Basic Spring MVC configuration set-up #. Simplified level screen transition #. Way to pass values between screens #. Simple input validation If above points are still not understood, it is recommended to read this chapter again and start again from building the environment. .. raw:: latex \newpage