For developing with Parancore you'll need:
You can start the development of a new Web application using the Parancoe Web Application archetype:
mvn archetype:create -DarchetypeGroupId=org.parancoe \ -DarchetypeArtifactId=parancoe-webarchetype \ -DarchetypeVersion=2.0.3 \ -DgroupId=com.mycompany \ -DartifactId=testApp \ -DpackageName=com.mycompany.testapp
Of course you can personalize the groupId, artifactId and package. After the execution you’ll have a complete web project with a common good layout, configured authentication and authorization, some Parancoe examples. Starting from this skeleton you can personalize it for developing your own application.
The Parancoe web application archetype produces a Maven 2 project. Of course you can use it with your preferred IDE.
NetBeans: install the Mevenide2 plug-in and use the project as a native NetBeans project. You'll find this plugin already available in the NetBeans plugin link starting from NetBeans 6.0.
Eclipse:
run
mvn eclipse:eclipse
and open the project with Eclipse.
IntelliJ IDEA:
run
mvn idea:idea
and open the project with IDEA.
The easyest way to develop a project with Parancoe is to use Maven 2 as build tool.
Parancoe artifacts are distributed through the Maven Central Repository and its mirrors. You don’t have to configure anything for using this repository.
If you are behind a proxy, check the Maven guide to using proxies to configure maven 2 with your proxy.
In the following
$PRJ
indicates the directory in wich you created the project.
Add to the
$PRJ/src/main/java/com/mycompany/testapp/po
directory the
Person.java
file with the following content:
package com.mycompany.testapp.po; import java.util.Date; import javax.persistence.Entity; import javax.persistence.Temporal; import javax.persistence.TemporalType; import org.parancoe.persistence.po.hibernate.EntityBase; @Entity public class Person extends EntityBase { private String firstName; private String lastName; private Date birthDate; private String email; @Temporal(TemporalType.DATE) public Date getBirthDate() { return birthDate; } public void setBirthDate(Date birthDate) { this.birthDate = birthDate; } 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 String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
Add to the
$PRJ/src/main/java/com/mycompany/testapp/dao
directory the
PersonDao.java
file with the following content:
package com.mycompany.testapp.dao; import com.mycompany.testapp.po.Person; import org.parancoe.persistence.dao.generic.Dao; import org.parancoe.persistence.dao.generic.GenericDao; @Dao(entity=Person.class) public interface PersonDao extends GenericDao<Person, Long> { }
Add to the
$PRJ/src/main/java/com/mycompany/testapp/controllers
directory the
PersonController.java
file with the following content:
package com.mycompany.testapp.controllers; import com.mycompany.testapp.dao.PersonDao; import com.mycompany.testapp.po.Person; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.support.SessionStatus; @Controller @RequestMapping({"/person/*.form", "/person/*.html"}) @SessionAttributes(PersonController.PERSON_ATTR_NAME) public class PersonController { public static final String PERSON_ATTR_NAME = "person"; public static final String EDIT_VIEW = "person/edit"; public static final String LIST_VIEW = "person/list"; @Autowired private PersonDao personDao; @RequestMapping public String edit(@RequestParam("id") Long id, Model model) { Person person = personDao.get(id); if (person == null) { throw new RuntimeException("Person not found"); } model.addAttribute(PERSON_ATTR_NAME, person); return EDIT_VIEW; } @RequestMapping public String save(@ModelAttribute(PERSON_ATTR_NAME) Person person, BindingResult result, SessionStatus status) { personDao.store(person); status.setComplete(); return "redirect:list.html"; } @RequestMapping public String list(Model model) { List<Person> people = personDao.findAll(); model.addAttribute("people", people); return LIST_VIEW; } @RequestMapping public String create(Model model) { Person person = new Person(); model.addAttribute(PERSON_ATTR_NAME, person); return EDIT_VIEW; } @RequestMapping public String delete(@RequestParam("id") Long id, Model model) { Person person = personDao.get(id); if (person == null) { throw new RuntimeException("Person not found"); } personDao.delete(person); return "redirect:list.html"; } }
Create the
$PRJ/src/main/webapp/WEB-INF/jsp/person
directory.
Add to the
$PRJ/src/main/webapp/WEB-INF/jsp/person
directory the
list.jsp
file with the following content:
<%@ include file="../common.jspf" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <%@ include file="../head.jspf" %> </head> <body> <div id="nonFooter"> <jsp:include page="../header.jsp"/> <div id="content"> <div id="content_main"> <h1>People</h1> <table> <c:forEach var="person" items="${people}"> <tr> <td>${person.firstName}</td> <td>${person.lastName}</td> <td>${person.birthDate}</td> <td>${person.email}</td> <td> <a href="edit.form?id=${person.id}">Edit</a> <a href="delete.html?id=${person.id}">Delete</a> </td> </tr> </c:forEach> </table> <c:if test="${empty people}"> No people in the DB </c:if> <a href="create.html">New</a> </div> <jsp:include page="../menu.jsp"/> </div> </div> <jsp:include page="../footer.jsp"/> </body> </html>
Add to the
$PRJ/src/main/webapp/WEB-INF/jsp/person
directory the
edit.jsp
file with the following content:
<%@ include file="../common.jspf" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <%@ include file="../head.jspf" %> </head> <body> <div id="nonFooter"> <jsp:include page="../header.jsp"/> <div id="content"> <div id="content_main"> <h1>Edit person</h1> <form:form commandName="person" method="POST" action="${cp}/person/save.form"> <table> <tr> <td>First name:</td> <td><form:input path="firstName"/></td> </tr> <tr> <td>Last name:</td> <td><form:input path="lastName"/></td> </tr> <tr> <td>Birth date:</td> <td><form:input path="birthDate"/> (dd/MM/yyyy)</td> </tr> <tr> <td>E-mail:</td> <td><form:input path="email"/></td> </tr> <tr> <td> </td> <td><input type="submit" value="Submit"/><br/><br/></td> </tr> </table> <form:errors path="*" cssClass="errorBox"/> </form:form> </div> <jsp:include page="../menu.jsp"/> </div> </div> <jsp:include page="../footer.jsp"/> </body> </html>
Add an item to the page menu in the
$PRJ/src/main/webapp/WEB-INF/jsp/menu.jsp
file:
<%@ include file="common.jspf" %> <div id="content_menu"> <p class="menuTitle"><spring:message code="label_menu"/></p> <p class="menuLevel0"><a href="${cp}/"><spring:message code="menu_home"/></a></p> <p class="menuLevel0"><a href="${cp}/person/list.html">People</a></p> <p class="menuLevel0"> <a href="${cp}/admin/index.html"><spring:message code="menu_administration"/></a> </p> <authz:authorize ifAnyGranted="ROLE_ADMIN,ROLE_PARANCOE"> <p class="menuLevel0"><a href="${cp}/logout.secure">Logout</a></p> </authz:authorize> </div>
Add the validation rules to your form bean (in this example it's also
the persistence entity) in the
$PRJ/src/main/java/com/mycompany/testapp/po/Person.java
.
The rules are expressed through annotations.
package com.mycompany.testapp.po; import java.util.Date; import javax.persistence.Entity; import javax.persistence.Temporal; import javax.persistence.TemporalType; import org.parancoe.persistence.po.hibernate.EntityBase; import org.springmodules.validation.bean.conf.loader.annotation.handler.Email; import org.springmodules.validation.bean.conf.loader.annotation.handler.NotBlank; @Entity public class Person extends EntityBase { @NotBlank private String firstName; @NotBlank private String lastName; private Date birthDate; @Email private String email; @Temporal(TemporalType.DATE) public Date getBirthDate() { return birthDate; } public void setBirthDate(Date birthDate) { this.birthDate = birthDate; } 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 String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
Add the
@Validation
annotation to the
save
method of the
PersonController
class:
@RequestMapping @Validation(view=EDIT_VIEW) public String save(@ModelAttribute(PERSON_ATTR_NAME) Person person, BindingResult result, SessionStatus status) { personDao.store(person); status.setComplete(); return "redirect:list.html"; }
The application generated by the Parancoe Web Application has its database
configuration in the
$PRJ/src/main/webapp/WEB-INF/database.xml
file:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="java:comp/env/jdbc/testAppDS"/> </bean> <bean id="sessionFactory" parent="abstractSessionFactory"> <property name="hibernateProperties"> <props merge="true"> <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.show_sql">true</prop> </props> </property> <property name="eventListeners"> <map> <entry key="merge"> <bean class= "org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/> </entry> </map> </property> </bean> </beans>
As you see in the previous file, the database connection is configured
through a datasource, so you just need to define a datasource with that
name in your application server. If you are using Tomcat, you can define
the datasource in the
$PRJ/src/main/webapp/META-INF/context.xml
file:
<?xml version="1.0" encoding="UTF-8"?> <Context path="/testApp" reloadable="true"> <Resource name="jdbc/testAppDS" type="javax.sql.DataSource" auth="Container" driverClassName="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:mem:testApp" username="sa" password="" maxActive="5" /> </Context>
For ease of configuration, the default database is an HSQL in-memory database. Of course you need to change it to a database with real persistence.
When you change your database, you need to change your datasource and the Hibernate dialect (if you aren't using an HSQL database server).
A common case of every application is the initialization of the database with the data needed for putting the application itself in a proper initial state after its first deploy.
For example the application generated by the Parancoe Web Archetype populate
the database with the ROLE_PARANCOE
and ROLE_ADMIN
roles,
and the parancoe
and admin
users. This is achieved adding
the entities that must be initialized to the clazzToPopulate
list of the
PopulateInitialDataContextListener
class:
package com.mycompany.testapp; import com.mycompany.testapp.po.Person; import org.parancoe.plugins.security.Authority; import org.parancoe.plugins.security.User; public class PopulateInitialDataContextListener extends org.parancoe.web.PopulateInitialDataContextListener { public PopulateInitialDataContextListener() { // Add here to the clazzToPopulate collection // the entity classes you need to populate clazzToPopulate.add(Authority.class); clazzToPopulate.add(User.class); } }
The data to load are defined in the $PRJ/src/main/resources/initialData
directory by a set of "fixtures" in YAML format:
Example 1.1. Authority.yml
- &Authority-parancoe role: ROLE_PARANCOE - &Authority-admin role: ROLE_ADMIN
Example 1.2. User.yml
- &User-parancoe username: parancoe # password : parancoe password: d928b1a8468c96804da6fcc70bff826f enabled: true authorities: - *Authority-parancoe - &User-admin username: admin # password : admin password: ceb4f32325eda6142bd65215f4c0f371 enabled: true authorities: - *Authority-admin
As you can see, it's very easy to define data sets, even with references to other data. The main rules are:
<entity_name>.yml
&<entity_name>-<some-useful-identifier>
*<entity_name>-<some-useful-identifier>
for referencing that item;