Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Install and configure MySql. Create a database named "quickstart" and run the script below to create the "Person" table. Later, on applicationContext.xml, we'll use 'root' as the user name and password for the database, remember to replace those values with the right ones for your database.

Code Block
SQLsqlSQL
sql
CREATE TABLE 'quickstart'.'Person' (
  'id' INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  'firstName' VARCHAR(45) NOT NULL,
  'lastName' VARCHAR(45) NOT NULL,
  PRIMARY KEY('id')
)
ENGINE = InnoDB;

...

your class will look like:

Code Block
JAVAjavaJAVA
java
titlePerson.java
package quickstart.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Person {
    @Id
    @GeneratedValue
    private Integer id;
    private String lastName;
    private String firstName;

    public String getFirstName() {
        return firstName;
    }

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

    public String getLastName() {
        return lastName;
    }

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

    public Integer getId() {
        return id;
    }

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

...

  1. Create a new interface (File -> New -> Interface), enter "PersonService" for the name, and "quickstart.service" for the namespace. Set its content to:
Code Block
JAVAjavaJAVA
java
titlePersonService.java
package quickstart.service;

import java.util.List;

import quickstart.model.Person;

public interface PersonService {
    public List<Person> findAll();

    public void save(Person person);

    public void remove(int id);

    public Person find(int id);
}
  1. Create a new class (File -> New -> Class), enter "PersonServiceImpl" for the name and "quickstart.service" for the namespace. Set its content to:
Code Block
JAVAjavaJAVA
java
titlePersonServiceImpl.java
package quickstart.service;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.transaction.annotation.Transactional;

import quickstart.model.Person;

@Transactional
public class PersonServiceImpl implements PersonService {
    private EntityManager em;

    @PersistenceContext
    public void setEntityManager(EntityManager em) {
        this.em = em;
    }

    @SuppressWarnings("unchecked")
    public List<Person> findAll() {
        Query query = getEntityManager().createQuery("select p FROM Person p");
        return query.getResultList();
    }

    public void save(Person person) {
        if (person.getId() == null) {
            // new
            em.persist(person);
        } else {
            // update
            em.merge(person);
        }
    }

    public void remove(int id) {
        Person person = find(id);
        if (person != null) {
            em.remove(person);
        }
    }

    private EntityManager getEntityManager() {
        return em;
    }

    public Person find(int id) {
        return em.find(Person.class, id);
    }

}

...

  1. Create a folder named "META-INF" under the "src" folder.
  2. Create a file named "persistence.xml" under the "META-INF" folder and set its content to:
Code Block
XMLxmlXML
xml
titlepersistence.xml
<persistence 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_1_0.xsd"
    version="1.0">
    <persistence-unit name="punit">
    </persistence-unit>
</persistence>

...

  1. Update the content of web.xml under /WebContent/WEB-INF/web.xml to:
Code Block
XMLzmlXML
zml
titleweb.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="person" 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>person</display-name>

    <!-- Include this if you are using Hibernate -->
    <filter>
        <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
        <filter-class>
            org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
        </filter-class>
    </filter>

    <filter-mapping>
        <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>
            org.apache.struts2.dispatcher.FilterDispatcher
        </filter-class>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
</web-app>

...

  1. Create a file named "applicationContext.xml" under /WebContent/WEB-INF, and set its content to:
Code Block
XMLxmlXML
xml
titleapplicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

    <bean
        class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <bean id="personService" class="quickstart.service.PersonServiceImpl" />

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter">
            <bean
                class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="database" value="MYSQL" />
                <property name="showSql" value="true" />
            </bean>
        </property>
    </bean>

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost/quickstart" />
        <property name="username" value="root" />
        <property name="password" value="root" />
    </bean>

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

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

    <bean id="personAction" scope="prototype"
        class="quickstart.action.PersonAction">
        <constructor-arg ref="personService" />
    </bean>
</beans>

...

  1. Open the new class dialog (File -> New -> Class) and enter "PersonAction" for the classname, and "quickstart.action" for the namespace. Set its content to:
Code Block
JAVAjavaJAVA
java
titlePersonAction.java
package quickstart.action;

import java.util.List;

import quickstart.model.Person;
import quickstart.service.PersonService;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.Preparable;

public class PersonAction implements Preparable {
    private PersonService service;
    private List<Person> persons;
    private Person person;
    private Integer id;

    public PersonAction(PersonService service) {
        this.service = service;
    }

    public String execute() {
        this.persons = service.findAll();
        return Action.SUCCESS;
    }

    public String save() {
        this.service.save(person);
        this.person = new Person();
        return execute();
    }

    public String remove() {
        service.remove(id);
        return execute();
    }

    public List<Person> getPersons() {
        return persons;
    }

    public Integer getId() {
        return id;
    }

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

    public void prepare() throws Exception {
        if (id != null)
            person = service.find(id);
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }
}

...

  1. Create a new file named "struts.xml" under the "src" folder. And set its content to:
Code Block
XMLxmlXML
xml
titlestruts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
    <constant name="struts.objectFactory" value="spring" />
    <constant name="struts.devMode" value="true" />

    <package name="person" extends="struts-default">

        <action name="list" method="execute" class="personAction">
            <result>pages/list.jsp</result>
            <result name="input">pages/list.jsp</result>
        </action>

        <action name="remove" class="personAction" method="remove">
            <result>pages/list.jsp</result>
            <result name="input">pages/list.jsp</result>
        </action>

        <action name="save" class="personAction" method="save">
            <result>pages/list.jsp</result>
            <result name="input">pages/list.jsp</result>
        </action>
    </package>

</struts>

...

  1. Create a new file named "list.jsp" under /WebContent/pages/ and set its content to:
Code Block
HTMLhtmlHTML
html
titlelist.jsp
<%@ taglib prefix="s" uri="/struts-tags"%>

<p>Persons</p>
<s:if test="persons.size > 0">
	<table>
		<s:iterator value="persons">
			<tr id="row_<s:property value="id"/>">
				<td>
					<s:property value="firstName" />
				</td>
				<td>
					<s:property value="lastName" />
				</td>
				<td>
					<s:url id="removeUrl" action="remove">
						<s:param name="id" value="id" />
					</s:url>
					<s:a href="%{removeUrl}" theme="ajax" targets="persons">Remove</s:a>
					<s:a id="a_%{id}" theme="ajax" notifyTopics="/edit">Edit</s:a>
				</td>
			</tr>
		</s:iterator>
	</table>
</s:if>

...

  1. Create a new file named "index.jsp" under /WebContent and set its content to:
Code Block
HTMLhtmlHTML
html
titleindex.jsp
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
	<head>
		<s:head theme="ajax" debug="true"/>
		<script type="text/javascript">
			dojo.event.topic.subscribe("/save", function(data, type, request) {
			    if(type == "load") {
					dojo.byId("id").value = "";
					dojo.byId("firstName").value = "";
					dojo.byId("lastName").value = "";
				}
			});

			dojo.event.topic.subscribe("/edit", function(data, type, request) {
			    if(type == "before") {
					var id = data.split("_")[1];

					var tr = dojo.byId("row_"+id);
					var tds = tr.getElementsByTagName("td");

					dojo.byId("id").value = id;
					dojo.byId("firstName").value = dojo.string.trim(dojo.dom.textContent(tds[0]));
					dojo.byId("lastName").value = dojo.string.trim(dojo.dom.textContent(tds[1]));
				}
			});
		</script>
	</head>
	<body>
	    <s:url action="list" id="descrsUrl"/>

        <div style="width: 300px;border-style: solid">
        	<div style="text-align: right;">
    			<s:a theme="ajax" notifyTopics="/refresh">Refresh</s:a>
    		</div>
    		<s:div id="persons" theme="ajax" href="%{descrsUrl}" loadingText="Loading..." listenTopics="/refresh"/>
        </div>

        <br/>

		<div style="width: 300px;border-style: solid">
			<p>Person Data</p>
			<s:form action="save" validate="true">
			    <s:textfield id="id" name="person.id" cssStyle="display:none"/>
				<s:textfield id="firstName" label="First Name" name="person.firstName"/>
				<s:textfield id="lastName" label="Last Name" name="person.lastName"/>
				<s:submit theme="ajax" targets="persons" notifyTopics="/save"/>
			</s:form>
		</div>
	</body>
</html>

...

Because we don't want any John Doe on our database, we will add some basic client side validation to our form. In Struts 2, validation can be placed on xml files with the name pattern ActionName-validation.xml, located on the same package as the action. To add validation to an specific alias of an action (like a method), the validation file name follows the pattern ActionName-alias-validation.xml, where "alias" is the action alias name (in this case a method name, "save"). Add a file named "PersonAction-save-validation.xml" under /src/quickstart/action, and set its content to:

Code Block
XMLxmlXML
xml
<!DOCTYPE validators PUBLIC 
	"-//OpenSymphonyApache GroupStruts//XWork Validator 1.0.2//EN"
	"http://wwwstruts.opensymphonyapache.comorg/xworkdtds/xwork-validator-1.0.2.dtd">
<validators>
    <field name="person.firstName">
        <field-validator type="requiredstring">
            <message>First name is required!</message>
        </field-validator>
    </field>
    <field name="person.lastName">
        <field-validator type="requiredstring">
            <message>Last name is required!</message>
        </field-validator>
    </field>
</validators>

...

  1. Add this to pom.xml
    Code Block
    XMLxmlXML
    xml
     <repositories>
         <repository>
             <id>java.net</id>
             <url>https://maven-repository.dev.java.net/nonav/repository</url>
             <layout>legacy</layout>
         </repository>
     </repositories>
    
  2. Add this to the dependencies node in pom.xml
    Code Block
    XML
    XML
    <dependency>
         <groupId>toplink.essentials</groupId>
         <artifactId>toplink-essentials</artifactId>
         <version>2.0-38</version>
         <exclusions>
             <exclusion>
                 <groupId>javax.transaction</groupId>
                 <artifactId>jta</artifactId>
             </exclusion>
         </exclusions>
    </dependency>
    
  3. Replace the jpaVendorAdapter element in applicationContext.xml with this:
    Code Block
    XMLxmlXML
    xml
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter">
            <property name="databasePlatform" value="oracle.toplink.essentials.platform.database.MySQL4Platform" />
            <property name="generateDdl" value="true" /> 
            <property name="showSql" value="true" />
        </bean>
    </property>
    

...