CRUD application in 5 minutes

This article follows Jspresso in 10 minutes where you have set-up a yet simple but complete Jspresso powered application project. We will reuse the placeholders already defined there (like ${ROOT_PACKAGE} for the application root package). Due to formatting restrictions, lines of code may be cut in pieces. In that case, the end of line is escaped by the "\" character.

The goal is rather simple : develop a CRUD module on a City entity. A city entity has a name (max 64, mandatory) and a zip code (max 10).

The domain model

Download the following PNG icon image City icon image and save it under :

${WORKSPACE}/${ARTIFACTID}/core/src/main/resources/${ROOT_PACKAGE_AS_PATH}/images/city-48x48.png

Edit the spring configuration file for the model located here:

${WORKSPACE}/${ARTIFACTID}/core/src/main/resources/${ROOT_PACKAGE_AS_PATH}/model/model.xml

Inside the <beans></beans> tags, copy and paste the following XML fragment (don't forget to replace the ${ROOT_PACKAGE} and ${ROOT_PACKAGE_AS_PATH} by the value you've chosen when generating the project) :

<bean
  id="City"
  class="org.jspresso.framework.model.descriptor.entity.basic.BasicEntityDescriptor">
  <constructor-arg value="${ROOT_PACKAGE}.model.City" />
  <property name="propertyDescriptors">
    <list>
      <bean class="org.jspresso.framework.model.descriptor.basic.BasicStringPropertyDescriptor">
        <property
          name="name"
          value="name" />
        <property
          name="maxLength"
          value="64" />
        <property
          name="mandatory"
          value="true" />
      </bean>
      <bean class="org.jspresso.framework.model.descriptor.basic.BasicStringPropertyDescriptor">
        <property
          name="name"
          value="zip" />
        <property
          name="maxLength"
          value="10" />
      </bean>
    </list>
  </property>
  <property
    name="iconImageURL"
    value="classpath:${ROOT_PACKAGE_AS_PATH}/images/city-48x48.png" />
</bean>

That's all you need to do to describe your entity; Jspresso will do the rest.

Move to the root directory of your project (${WORKSPACE}/${ARTIFACTID}) and type :

mvn compile
ant generate-entities, xdoclet-hibernate

The two commands above have generated and compiled the City entity. If you wish, you might take a look at the following source directories where you will find its java source file and hibernate mapping file.

${WORKSPACE}/${ARTIFACTID}/core/src/main/java/${ROOT_PACKAGE_AS_PATH}/model/City.java
${WORKSPACE}/${ARTIFACTID}/core/src/main/resources/${ROOT_PACKAGE_AS_PATH}/model/City.hbm.xml

The front-end

Download the following PNG icon image Masterdata icon image and save it under :

${WORKSPACE}/${ARTIFACTID}/core/src/main/resources/${ROOT_PACKAGE_AS_PATH}/images/masterdata-48x48.png

Edit the spring configuration file for the front-end located here:

${WORKSPACE}/${ARTIFACTID}/core/src/main/resources/${ROOT_PACKAGE_AS_PATH}/frontend/frontend.xml

Before the controller definition, insert the following XML fragment (don't forget to replace the ${ROOT_PACKAGE} and ${ROOT_PACKAGE_AS_PATH} by the value you've chosen when generating the project) :

<bean
id="Masterdata.workspace"
parent="abstractWorkspace"
scope="prototype">
<property
name="name"
value="masterdata.workspace" />
<property
name="description"
value="masterdata.workspace.description" />
<property
name="iconImageURL"
value="classpath:${ROOT_PACKAGE_AS_PATH}/images/masterdata-48x48.png" />
<property
name="modules">
<list>
<bean
parent="abstractFilterableBeanCollectionModule">
<property
name="name"
value="masterdata.cities.module" />
<property
name="description"
value="masterdata.cities.module.description" />
<property
name="elementComponentDescriptor"
ref="City" />
</bean>
</list>
</property>
</bean>

Look for the xml comment "<!-- Reference your workspaces here. -->" and insert the following line just below :

<ref bean="Masterdata.workspace" />

This final line installs the new workspace in the application.

Congratulations! You've just defined your first Jspresso module and workspace.

The last thing we need to achieve now is to internationalize the application (at least give an english translation). We have used several translation keys even without knowing it... So open the resource bundle property file for english located here :

${WORKSPACE}/${ARTIFACTID}/core/src/main/resources/${ROOT_PACKAGE_AS_PATH}/i18n/Messages_en.properties

Copy and paste the following key/value pairs (you can easily locate them from the spring configuration files above) :

masterdata.workspace=Master Data
masterdata.workspace.description=Master data management workspace
masterdata.cities.module=Cities
masterdata.cities.module.description=Cities management module
zip=Zip Code
${ROOT_PACKAGE}.model.City=City

You can of course translate also in french in the Messages_fr.properties

masterdata.workspace=R\u00E9f\u00E9rentiel
masterdata.workspace.description=Espace de gestion du r\u00E9f\u00E9rentiel
masterdata.cities.module=Villes
masterdata.cities.module.description=Module de gestion des villes
zip=C.P.
${ROOT_PACKAGE}.model.City=Ville

and afterward play with the demo user language in the jaas.config file in ${TOMCAT_HOME}/conf.

We are now ready to re-package the webapp :

mvn package

And re-deploy the webapp in Tomcat.

This is a fairly basic application but don't hesitate to play with it to see how easy it is to change things; for instance, add a property to the city entity, re-generate the persistence code (mvn compile; ant generate-entities, xdoclet-hibernate) re-package (mvn package) and see how the application gets impacted.

Jspresso philosophy is to use sensible defaults everywhere it is possible. That's the reason why in such a few lines of XML you can get things up and running. But Jspresso allows you to overload everything at every place when needed along time. This makes the development cycles really short yet robusts.

The last thing to note is that Jspresso is far from being only a CRUD framework. It's open, extensible and provides a massive amount of built-in features to virtually cover any business needs.