Monday 6 May 2013

Developing a Spring MVC project using Maven, JSTL tags, and data persistence

This Scotts Digital Community article falls into a general programming discussion (as opposed to an Adobe Enterprise development article) and provides details on developing a Spring MVC application that persists data. You can create this Spring MVC project by using Maven and JSTL tags. For information about Spring MVC, see http://static.springsource.org/spring/docs/2.0.x/reference/mvc.html.


Assume, for example, that you want to create a Spring MVC project that saves, displays, and deletes customer data.


A Spring MVC application that supports saving, viewing, and deleting customer data

This development article guides you through how to create this Spring MVC project, including how to configure the Spring DispatcherServlet. Included in this article is the use of Spring annotations such as @Autowired. This annotation informs the Spring framework to use dependency injection on a constructor, class field, setter method or config method. 

The JavaServer Pages Standard Tag Library (JSTL) is a collection of  JSP tags which uses functionality common to JSP applications. For example, using a JSTL tag, you can iterate through a data collection and display the results within a web page. 

To create a Spring MVC project using Maven, perform these tasks:
1. Setup Maven in your development environment.
2. Create a Maven project structure.
3. Convert the Maven project to a Spring MVC project.
4. Build the Maven project.
5. Deploy the Maven project to an application server (in this development environment, the project is ran on Tomcat). 

NOTE: To learn how to create a secure Spring application that uses a custom login page, click: http://scottsdigitalcommunity.blogspot.ca/2014/08/creating-custom-login-page-for-secure.html.

SETUP MAVEN IN YOUR DEVELOPMENT ENVIRONMENT


You can use Maven to build and manage Java projects. One benefit of Maven is dependency management. What does this mean? Well -- it means that Maven manages required JAR files that a Java project needs in its class path. Therefore instead of hunting through the Internet trying to find and download third-party JAR files to include in your class path, Maven will manage these dependencies for you.

You can download Maven 3 from the following URL:


After you download and extract Maven, create an environment variable named M3_HOME. Assign the Maven install location to this environment variable. For example:

C:\Programs\Apache\apache-maven-3.0.4

You can test to determine if Maven is properly setup by entering the following command into a command prompt:

%M3_HOME%\bin\mvn -version

This command provides Maven and Java install details and resembles the following message:

Apache Maven 3.0.4 (r1232337; 2012-01-17 03:44:56-0500)
Maven home: C:\Programs\Apache\Maven\apache-maven-3.0.4
Java version: 1.6.0_31, vendor: Sun Microsystems Inc.
Java home: C:\Programs\Java64-6\jre
Default locale: en_US, platform encoding: Cp1252
OS name: “windows 7”, version: “6.1”, arch: “amd64”, family: “windows”

CREATE A MAVEN PROJECT STRUCTURE

You can use a Maven archetype plugin to create a project. To create a Java application, you can  use the maven-archetype-quickstart plugin. The following example creates a Maven Java application project in the C:\apache-maven-3.0.4\ folder.

To create a Maven project structure:
1. Open the command prompt and go to the C:\apache-maven-3.0.4 directory.
2. Run the following Maven command:
mvn archetype:generate -DgroupId=com.sdc.controller -DartifactId=FirstController -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false


You will see a Maven message similar to the following:

 [INFO] Using following parameters for creating project from Old (1.x) Archetype:
 maven-archetype-quickstart:1.0
[INFO] 
[INFO] Parameter: groupId, Value: com.sdc.controller
[INFO] Parameter: packageName, Value: com.sdc.controller
[INFO] Parameter: package, Value: com.sdc.controller
[INFO] Parameter: artifactId, Value: FirstController
[INFO] Parameter: basedir, Value: C:\apache-maven-3.0.4
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: C:\apache-maven-3.0.4\FirstController
[INFO] BUILD SUCCESS
[INFO] Total time: 3.347s
[INFO] Finished at: Sun Jan 20 16:49:18 EST 2013
[INFO] Final Memory: 8M/122M

This Maven command produces a basic project structure that contains a POM file and basic Java class.


The generated Maven POM file is located in the FirstController folder. Change this folder name to Customer and modify the folder structure under Customer to reflect the folder structure shown in the following illustration. Next, delete the folders under the java folder. New Java files are added in the following sections.
Under the java folder, create the following folder structure: java\com\springapp\mvc. These child folders correspond to the Java package named com.springapp.mvc that is used in this development article.

CONVERT THE MAVEN GENERATED PROJECT TO A SPRING MVC PROJECT

The next step is to convert the generated Maven project into a Spring MVC project. This involves performing the following tasks:

1. Add the Java classes to the com.springapp.mvc package.
2. Modify the POM file to include Spring MVC dependencies.
3. Add a data persistence XML configuration file to the resources folder.  
3. Add a new folder named webapp to the src/main folder. This folder contains the WEB-INF folder.

Add the User class 

Add a Customer class to the java\com\springapp\mvc folder that represents a Spring bean. This class uses the following annotations:
  • @Entity - indicates that this Spring bean is a persistent entity. 
  • @GeneratedValue - indicates a primary key property or field of an entity or mapped superclass in conjunction with the Id annotation.
  • @Basiccan be applied to a persistent property. In this example, first name, last name, and email fields are persisted. 
The following Java code represents the User class. 
package com.springapp.mvc;

import javax.persistence.*;

@Entity(name = "account")
public class User{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Basic
    private String firstName;

    @Basic
    private String lastName;

    @Basic
    private String email;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String name) {
        this.firstName = name;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

Add the UserController class 

Add a UserController class to the java\com\springapp\mvc folder that represents a Spring MVC controller. A controller  is responsible for receiving requests from users and invoking services for business processing. This class contains the following annotations:
  • @Controller - indicates that this class is a MVC controller. 
  • @Autowired-  informs the Spring framework to use dependency injection
  • @RequestMapping - specifies that the corresponding method is a controller handler method.
    The following Java code represents the UserController class. 

    package com.springapp.mvc;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.ModelMap;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.annotation.ModelAttribute;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;

    @Controller
    public class UserController {
        @Autowired
        private UserRepository userRepository;

        @RequestMapping(value = "/", method = RequestMethod.GET)
        public String listUsers(ModelMap model) {
            model.addAttribute("user", new User());
            model.addAttribute("users", userRepository.findAll());
            return "users";
        }

        @RequestMapping(value = "/add", method = RequestMethod.POST)
        public String addUser(@ModelAttribute("user") User user, BindingResult result) {

            userRepository.save(user);

            return "redirect:/";
        }

        @RequestMapping("/delete/{userId}")
        public String deleteUser(@PathVariable("userId") Long userId) {

            userRepository.delete(userRepository.findOne(userId));

            return "redirect:/";
        }
    }

    Add the UserRepository class

    Add the UserRepository class that extends org.springframework.data.jpa.repository.JpaRepository. The JpaRepository class lets a bean of this type modify data stored in the database.  

    The following Java code represents the UserRepository class.

    package com.springapp.mvc;

    import org.springframework.data.jpa.repository.JpaRepository;

    public interface UserRepository extends JpaRepository<User, Long> {
    }

    Modify the POM file to include Spring MVC dependencies

    Replace the POM that the Maven plug-in created with the following POM file. This new POM includes Spring dependencies that are required to use Spring MVC functionality. In addition, the dependency to use Hibernate functionality is also included. 

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.springapp.mvc</groupId>
        <artifactId>Customer</artifactId>
        <packaging>war</packaging>
        <version>1.0-SNAPSHOT</version>
        <name>SpringMVC Maven Webapp</name>
        <url>http://maven.apache.org</url>
    <properties>
            <spring.version>3.2.0.RELEASE</spring.version>
        </properties>
      <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>2.5</version>
            </dependency>

            <dependency>
                <groupId>javax.servlet.jsp</groupId>
                <artifactId>jsp-api</artifactId>
                <version>2.1</version>
                <scope>provided</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>${spring.version}</version>
                <scope>test</scope>
            </dependency>

            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.8.2</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>jstl</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
            </dependency>

            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-jpa</artifactId>
                <version>1.2.0.RELEASE</version>
            </dependency>

            <dependency>
                <groupId>org.hibernate.javax.persistence</groupId>
                <artifactId>hibernate-jpa-2.0-api</artifactId>
                <version>1.0.0.Final</version>
            </dependency>

            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-entitymanager</artifactId>
                <version>3.6.10.Final</version>
            </dependency>

            <dependency>
                <groupId>org.hsqldb</groupId>
                <artifactId>hsqldb</artifactId>
                <version>2.2.9</version>
            </dependency>

            <dependency>
                <groupId>org.json</groupId>
                <artifactId>json</artifactId>
                <version>20080701</version>
            </dependency>

        </dependencies>

    </project>

    Add a data persistence XML configuration file to the resources folder

    Add a data persistence XML configuration file that lets the Spring MVC application persist data into a database. In the resources folder, create a sub folder named META-INF. Add an XML file named persistence.xml in the META-INF folder.

    The following XML represents the  persistence.xml configuration file. In this example, a HSQL database is used. Notice that values such as user name and password are specified using property elements.   

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
        <persistence-unit name="defaultPersistenceUnit" transaction-type="RESOURCE_LOCAL">
            <provider>org.hibernate.ejb.HibernatePersistence</provider>
            <properties>
                <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
                <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:spring" />
                <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
                <property name="hibernate.connection.username" value="sa" />
                <property name="hibernate.connection.password" value="" />
                <property name="hibernate.hbm2ddl.auto" value="create-drop" />
            </properties>
        </persistence-unit>
    </persistence>

    Add the webapp folder to the Maven project structure

    Add a new folder named webapp to the main folder. Add a subfolder named WEB-INF to the webapp folder. You add the following three files to this WEB-INF folder: web.xml, mvc-dispatcher-servlet.xml, and users.jsp (this file is located in a sub folder named pages). The users.jsp file calls the Java application logic defined within the UserController class.

    The web.xml file defines servlets for the web application (after all, a Spring MVC project is a web application). Within the web.xml file,  you specify a Spring MVC servlet. A Spring MVC servlet is based on org.springframework.web.servlet.DispatcherServlet. In the following example, the name of the Spring dispatcher servlet is mvc-dispatcher.

    The following XML code represents the web.xml file.
    <web-app version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <display-name>Spring MVC Application</display-name>

        <servlet>
    <servlet-name>mvc-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
    <servlet-name>mvc-dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>
    </web-app>

    Notice the servlet-name element specifies mvc-dispatcher. This specifies the location of the mvc-dispatcher-servlet.xml. In this example, the name of the dispatcher servlet is mvc-dispatcher (this is the file that is created next). 

    The mvc-dispatcher-servlet.xml informs the Spring framework where to find the controller (in this article, the controller is the UserController  class. The dispatcher configuration uses the following element to specify the location of the controller:

    <context:component-scan base-package="com.springapp.mvc"/>

    This XML element informs the Spring framework to search the com.springapp.mvc package for a controller. The following XML represents the mvc-dispatcher-servlet.xml file.

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:jpa="http://www.springframework.org/schema/data/jpa"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

        <context:component-scan base-package="com.springapp.mvc"/>

        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/pages/"/>
            <property name="suffix" value=".jsp"/>
        </bean>

        <jpa:repositories base-package="com.springapp.mvc"/>

        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
            <property name="persistenceUnitName" value="defaultPersistenceUnit"/>
        </bean>

        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory" />
        </bean>

        <tx:annotation-driven transaction-manager="transactionManager"/>
    </beans>

    The last file to create is the user.jsp file. In this example, place the JSP file in a folder named pages (this is a sub-folder to WEB-INF). This JSP invokes Java methods defined in the UserController.

    <!doctype html>
    <%@taglib uri="http://www.springframework.org/tags" prefix="spring" %>
    <%@taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
    <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

    <html>
    <head>
        <meta charset="utf-8">
        <title>Spring MVC Application</title>

        <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <link href="http://twitter.github.io/bootstrap/assets/css/bootstrap.css" rel="stylesheet">
        <link href="http://twitter.github.io/bootstrap/assets/css/bootstrap-responsive.css" rel="stylesheet">
    </head>

    <body>

    <div class="container">
        <div class="row">
            <div class="span8 offset2">
                <h1>Users</h1>
                <form:form method="post" action="add" commandName="user" class="form-horizontal">
                <div class="control-group">
                    <form:label cssClass="control-label" path="firstName">First Name:</form:label>
                    <div class="controls">
                        <form:input path="firstName"/>
                    </div>
                </div>
                <div class="control-group">
                    <form:label cssClass="control-label" path="lastName">Last Name:</form:label>
                    <div class="controls">
                        <form:input path="lastName"/>
                    </div>
                </div>
                <div class="control-group">
                    <form:label cssClass="control-label" path="email">Email:</form:label>
                    <div class="controls">
                        <form:input path="email"/>
                    </div>
                </div>
                <div class="control-group">
                    <div class="controls">
                        <input type="submit" value="Add User" class="btn"/>
                        </form:form>
                    </div>
                </div>

                <c:if test="${!empty users}">
                    <h3>Users</h3>
                    <table class="table table-bordered table-striped">
                        <thead>
                        <tr>
                            <th>Name</th>
                            <th>Email</th>
                            <th>&nbsp;</th>
                        </tr>
                        </thead>
                        <tbody>
                        <c:forEach items="${users}" var="user">
                            <tr>
                                <td>${user.lastName}, ${user.firstName}</td>
                                <td>${user.email}</td>
                                <td>
                                    <form action="delete/${user.id}" method="post"><input type="submit" class="btn btn-danger btn-mini" value="Delete"/></form>
                                </td>
                            </tr>
                        </c:forEach>
                        </tbody>
                    </table>
                </c:if>
            </div>
        </div>
    </div>

    </body>
    </html>

    In this example, notice that JSTL tags are used. In this example, for each user in the database, a new table HTML table row is created and the user.lastName and user.FirstName methods (defined in the User class) are invoked. 

    Each row also has a button defined by this HTML tag: input type="submit".  When clicked, notice that the delete method defined in the UserController class is invoked. This deletes the user record from the database. 

    Finally a new user is added to the database by clicking the Add User button. When the Add User button is clicked, the addUser method located in the UserController is invoked. 

    @RequestMapping(value = "/add", method = RequestMethod.POST)
        public String addUser(@ModelAttribute("user") User user, BindingResult result) {

            userRepository.save(user);

            return "redirect:/";
        }

    BUILD THE MAVEN PROJECT

    After you convert the generated Maven project to a Spring MVC project, you can build the artifact by using Maven. The artifact that is built is a WAR file, as specified in the POM file. In this example, the packaging element in the POM file specifies war:

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.springapp.mvc</groupId>
    <artifactId>Customer</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>SpringMVC Maven Webapp</name>
    <url>http://maven.apache.org</url>

    To create the artifact by running Maven, perform these steps:
    1.Start the Command Prompt.
    2. Change the directory to the location of POM file.
    3. Enter the following command: %M3_HOME%\bin\mvn clean package.
    4. The WAR file is placed in the target directory. In this example, the WAR file is named Customer-1.0-SNAPSHOT.war.


    DEPLOY THE WAR FILE TO TOMCAT

    Deploy the WAR file that was built in the previous step by placing it in the Tomcat\webapps folder. Restart Tomcat. Once Tomcat is started, you can view the Spring MVC application by entering the following URL:

    http://[server name]:[port]/Customer-1.0-SNAPSHOT/

    The following illustration shows the Spring MVC application in a web browser. 

    CONCLUSION

    This article walked you through how to set-up a Spring MVC project using Maven and highlighted how the dispatcher, controller and view work together. Once you understand this, you can start to work on more complex Spring MVC applications.

    Join the Adobe Experience Cloud Community 

    Join the Adobe Experience Cloud Community by clicking this banner




    I (Scott Macdonald) am a Senior Digital Marketing Community Manager at Adobe Systems with 20 years in the high tech industry. I am also a programmer with knowledge in Java, JavaScript, C#,C++, HTML, XML and ActionScript. If  you would like to see more CQ or other Adobe Digital Marketing end to end articles like this, then leave a comment and let me know what content you would like to see.


    TwitterFollow the Digital Marketing Customer Care team on Twitter @AdobeExpCare.

    YouTube: Subscribe to the AEM Community Channel