Basic CRUD with Tapestry 5

Introduction

This tutorials aims to present how to make a simple Crud cycle in tapestry 5.

Before reading this tutorial, you should read the Howard Lewis Ship's tutorials as we're going to reuse parts of it without re-explaining all the concepts they introduce.

In order to stay focused on designing the CRUD, we're not going to deal with a database or worry about transactions. If you want to work on a tutorial that deals with this question in great details you should read this one carefully.

It's good to understand how one would go about implementing a basic CRUD but there's no reason every Tapestry user would have to rewrite the same code for CRUD functionality. For a pre-packaged open-source Tapestry 5 solution, see tapestry-model from Tynamo project.

Create the project

To create the project and set up all the dependencies we use maven :

mvn archetype:create  
   -DarchetypeGroupId=org.apache.tapestry 
   -DarchetypeArtifactId=quickstart 
   -DarchetypeVersion=5.0.5 
   -DgroupId=org.apache.tapestry  
   -DartifactId=basicCrud 
   -DpackageName=org.apache.tapestry.tutorial.basiccrud 

Now let's move in the project and and make it available in Eclipse

 cd basicCrud
 mvn eclipse:eclipse

Import the project in Eclipse : File -> Import -> General -> Existing Project Into Workspace Browse to the folder basicCrud and click finish.

Now we are ready to work!

Create the model

Create in the package org.apache.tapestry.tutorial.basiccrud.model our model class, as you can see I made it simple :

package org.apache.tapestry.tutorial.basiccrud.model;

public class MyBean {
        
        
        private Long id;
        private String name;

        public MyBean(){
                //nothing to do 
        }
        
        public MyBean(String name){
                this.name = name;
        }
        
        public MyBean(String name, Long id){
                this.name = name;
                this.id = id;
        }
        
        public Long getId() {
                return id;
        }
        
        public void setId(Long id) {
                this.id = id;
        }
        public String getName() {
                return name;
        }
        public void setName(String name) {
                this.name = name;
        }
        
        @Override
        public String toString() {
                return id + " : " + name;
        }

}

Create the Service

As explained earlier, we're only going to focus on the CRUD process, thus we're going to make a very simple BeanManager that will hold a list of MyBean in memory. This service is going to be injected (more on this later) as a Singleton. Thus, as long a your application is deployed the list is still in memory, but every time you restart the server the list is reinitialized. For this tutorial we're not going to implement persistence between server reboots.

To make a service we need an interface and an implementation. If you wonder why we can't just use an implementation, you should read this. Additionally, this is a good habit when used judiciously.

In org.apache.tapestry.tutorial.basiccrud.services.manager create the interface BeanManager

package org.apache.tapestry.tutorial.basiccrud.services.manager;

import java.util.List;

import org.apache.tapestry.tutorial.basiccrud.model.MyBean;

public interface BeanManager {

        public abstract List<MyBean> getMyBeans();

        public abstract void setMyBeans(List<MyBean> myBeans);
        
        public void delete(Long id);
        
        public abstract void save(MyBean myBean);
        
        public MyBean getMyBean(Long id);       

}

In the same package make the implementation

package org.apache.tapestry.tutorial.basiccrud.services.manager;

import java.util.ArrayList;
import java.util.List;

import org.apache.tapestry.tutorial.basiccrud.model.MyBean;

public class BeanManagerImpl implements BeanManager {
        
        private List<MyBean> myBeans = new ArrayList<MyBean>();

        
        public List<MyBean> getMyBeans() {              
                return myBeans;  
        }

        
        public void setMyBeans(List<MyBean> myBeans) {
                this.myBeans = myBeans;
        }
        
        
        public void delete(Long id){
                MyBean myBean = getMyBean(id);
                getMyBeans().remove(myBean);
        }
        
        
        public void save(MyBean myBean){
                if(myBean.getId()!=null){
                        //update
                        myBeans.set(myBeans.indexOf(myBean), myBean);
                }else{
                        myBean.setId(new Long(myBeans.size()));
                        myBeans.add(myBean);
                }
        }
        
        public MyBean getMyBean(Long id){
                for(MyBean myBean : myBeans){
                        if (myBean.getId().equals(id)){
                                return myBean;
                        }
                }
                return null;
        }
        
        @Override
        public String toString() {
                return myBeans.toString();
        }
        
        

}

Inject the service

Injecting a service in Tapestry is really easy, just add a bind method to your AppModule.java

in org.apache.tapestry.tutorial.basiccrud.services.AppModule.java add this method:

public static void bind(ServiceBinder binder)
{
     
      binder.bind(BeanManager.class, BeanManagerImpl.class);
      
}

Now the BeanManager is available in any tapestry component through the @Inject annotation.

More explaination on binding service interfaces to service implementations

Display a list of beans in the Start page

Change Start.java to display a list of beans and handle the delete action.

package org.apache.tapestry.tutorial.basiccrud.pages;


import java.util.List;

import org.apache.tapestry.annotations.Inject;
import org.apache.tapestry.annotations.InjectPage;
import org.apache.tapestry.tutorial.basiccrud.model.MyBean;
import org.apache.tapestry.tutorial.basiccrud.services.manager.BeanManager;

/**
 * Start page of application basicCrud.
 */
public class Start{     
        
        @Inject 
        private BeanManager beanManager;
        
        private MyBean myBean;
        
        public MyBean getMyBean() {
                return myBean;
        }

        public void setMyBean(MyBean myBean) {
                this.myBean = myBean;
        }

        public List<MyBean> getMyBeans(){
                return beanManager.getMyBeans();
        }

        public boolean isEmptyList() {
                return beanManager.getMyBeans().isEmpty();
        }       
                
        
        public void onActionFromDelete(Long id){
                beanManager.delete(id);
        }       
        
}

Edit or create a bean

To create or edit a bean we'll use Save.java :

package org.apache.tapestry.tutorial.basiccrud.pages;

import org.apache.tapestry.annotations.Inject;
import org.apache.tapestry.annotations.InjectPage;
import org.apache.tapestry.annotations.Persist;
import org.apache.tapestry.tutorial.basiccrud.model.MyBean;
import org.apache.tapestry.tutorial.basiccrud.services.manager.BeanManager;

public class Save {     
        
        private MyBean myBean;  
        
        private Long id;
        
        @Inject
        private BeanManager beanManager;

        @InjectPage
        private Start start;
        
        public void onActivate(Long id){                
                if(id.equals(0L)){
                        myBean = new MyBean();                  
                }else{
                        myBean = beanManager.getMyBean(id);
                }
                this.id = id;
        }               
        
        public Long  onPassivate(){
                return id;
        }
        
        public Object onSubmit(){
                beanManager.save(myBean);
                return start;
        }       
        
        public MyBean getMyBean() {
                return myBean;
        }

        public void setMyBean(MyBean myBean) {
                this.myBean = myBean;
        }

}

And Save.html

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<head>
<title>basicCrud edit Page</title>
</head>
<body>

        <t:form>
      <t:errors/>
      <t:label t:for="name"/> 
          <input t:type="textfield" t:id="name" t:value="myBean.name"/><br/>
      <br/>
      <input type="submit"/>
    </t:form>

</body>
</html>

Try it

now try it :

mvn clean compile jetty:run 

And just navigate to http://localhost:8080 you'll find your way ;-).

Conclusion

I made this tutorial because I needed one and thought that I probably was not the only one. Thanks to the users of the mailing list that point on weakness and help me to make it better.

Credit to Michael Courcy for taking the time to write this tutorial.

Tapestry5How_to_make_a_basic_crud (last edited 2010-02-07 04:36:05 by Kalle Korhonen)