Google App Engine + JDO + Spring MVC, CRUD example

Note
This tutorial is more on practice guide, please refer to this official Using JDO in datastore for detail explanation.

See following code snippets to perform CRUD on GAE datastore, using Java Data Objects(JDO). Just annotate the Customer with JDO annotation and perform the CRUD via PersistenceManager.

Add

        Customer c = new Customer();
c.setName(name);
 
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(c);
} finally {
pm.close();
}

Search

Search “Customer” where name == “mkyong”.

	PersistenceManager pm = PMF.get().getPersistenceManager();
 
Query q = pm.newQuery(Customer.class);
q.setFilter("name == nameParameter");
q.setOrdering("date desc");
q.declareParameters("String nameParameter");
 
try {
List<Customer> results = (List<Customer>) q.execute("mkyong");
//...
} finally {
q.closeAll();
pm.close();
}

Search “Customer” where name == “mkyong” and email ==”[email protected]”.

	Query q = pm.newQuery(Customer.class);
q.setOrdering("date desc");
q.setFilter("name == nameParameter && email == emailParameter");
q.declareParameters("String nameParameter, String emailParameter");
 
try {
List<Customer> results = (List<Customer>) q.execute("mkyong", "[email protected]");
//...
} finally {
q.closeAll();
pm.close();
}

Return list of customer records.

	PersistenceManager pm = PMF.get().getPersistenceManager();
Query q = pm.newQuery(Customer.class);
q.setOrdering("date desc");
List<Customer> results = null;
 
try {
results = (List<Customer>) q.execute();
if (!results.isEmpty()) {
// good for listing
}
} finally {
q.closeAll();
pm.close();
}

Update

To update, get existing object and modify it.

	PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Customer c = pm.getObjectById(Customer.class, key);
c.setName(name);
c.setEmail(email);
c.setDate(new Date());
} finally {
pm.close();
}

Delete

        PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Customer c = pm.getObjectById(Customer.class, key);
pm.deletePersistent(c);
} finally {
pm.close();
}

GAE + Spring MVC + CRUD example

Ok, now we will show you a simple web application developed using Spring MVC in REST style, using JDO to store data in datastore.

  1. Google App Engine Java SDK 1.6.3.1, JDO 2.3
  2. Spring 3.1.1
  3. JDK 1.6
  4. Eclipse 3.7 + Google Plugin for Eclipse

P.S Use Google Plugin for Eclipse to create a web application project template, it will create and configure jdoconfig.xml for you automatically.

Note
This example is keep into as simple as possible, to show you how to use JDO to perform CRUD only, no layers like DAO or BO, no validation or message notification of the success or failed action.

1. Customer

Annotate Customer object with JDO annotation.

package com.mkyong.model;
 
import java.util.Date;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.api.datastore.Key;
 
@PersistenceCapable
public class Customer {
 
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
 
@Persistent
private String name;
 
@Persistent
private String email;
 
@Persistent
private Date date;
 
//getter and setter methods
}

2. PersistenceManager

Create a singleton PersistenceManager class.

package com.mkyong;
 
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;
 
public final class PMF {
private static final PersistenceManagerFactory pmfInstance = JDOHelper
.getPersistenceManagerFactory("transactions-optional");
 
private PMF() {
}
 
public static PersistenceManagerFactory get() {
return pmfInstance;
}
}

3. Spring Controller

Spring controller, REST style, perform the CRUD operation. The code should be self-explanatory.

File : CustomerController.java

package com.mkyong.controller;
 
import java.util.Date;
import java.util.List;
 
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.servlet.http.HttpServletRequest;
 
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.mkyong.PMF;
import com.mkyong.model.Customer;
 
@Controller
@RequestMapping("/customer")
public class CustomerController {
 
@RequestMapping(value = "/add", method = RequestMethod.GET)
public String getAddCustomerPage(ModelMap model) {
 
return "add";
 
}
 
@RequestMapping(value = "/add", method = RequestMethod.POST)
public ModelAndView add(HttpServletRequest request, ModelMap model) {
 
String name = request.getParameter("name");
String email = request.getParameter("email");
 
Customer c = new Customer();
c.setName(name);
c.setEmail(email);
c.setDate(new Date());
 
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(c);
} finally {
pm.close();
}
 
return new ModelAndView("redirect:list");
 
}
 
@RequestMapping(value = "/update/{name}", method = RequestMethod.GET)
public String getUpdateCustomerPage(@PathVariable String name,
HttpServletRequest request, ModelMap model) {
 
PersistenceManager pm = PMF.get().getPersistenceManager();
 
Query q = pm.newQuery(Customer.class);
q.setFilter("name == nameParameter");
q.setOrdering("date desc");
q.declareParameters("String nameParameter");
 
try {
List<Customer> results = (List<Customer>) q.execute(name);
 
if (results.isEmpty()) {
model.addAttribute("customer", null);
} else {
model.addAttribute("customer", results.get(0));
}
} finally {
q.closeAll();
pm.close();
}
 
return "update";
 
}
 
@RequestMapping(value = "/update", method = RequestMethod.POST)
public ModelAndView update(HttpServletRequest request, ModelMap model) {
 
String name = request.getParameter("name");
String email = request.getParameter("email");
String key = request.getParameter("key");
 
PersistenceManager pm = PMF.get().getPersistenceManager();
 
try {
 
Customer c = pm.getObjectById(Customer.class, key);
 
c.setName(name);
c.setEmail(email);
c.setDate(new Date());
 
} finally {
 
pm.close();
}
 
// return to list
return new ModelAndView("redirect:list");
 
}
 
@RequestMapping(value = "/delete/{key}", method = RequestMethod.GET)
public ModelAndView delete(@PathVariable String key,
HttpServletRequest request, ModelMap model) {
 
PersistenceManager pm = PMF.get().getPersistenceManager();
 
try {
 
Customer c = pm.getObjectById(Customer.class, key);
pm.deletePersistent(c);
 
} finally {
pm.close();
}
 
// return to list
return new ModelAndView("redirect:../list");
 
}
 
// get all customers
@RequestMapping(value = "/list", method = RequestMethod.GET)
public String listCustomer(ModelMap model) {
 
PersistenceManager pm = PMF.get().getPersistenceManager();
Query q = pm.newQuery(Customer.class);
q.setOrdering("date desc");
 
List<Customer> results = null;
 
try {
results = (List<Customer>) q.execute();
 
if (results.isEmpty()) {
model.addAttribute("customerList", null);
} else {
model.addAttribute("customerList", results);
}
 
} finally {
q.closeAll();
pm.close();
}
 
return "list";
 
}
 
}

4. JSP Pages

JSP pages to display customer and perform add, update and delete.

File : list.jsp

<%@ page import="java.util.List" %>
<%@ page import="com.mkyong.model.Customer" %>
<%@ page import="com.google.appengine.api.datastore.KeyFactory" %>
<html>
<body>
<h1>GAE + Spring 3 MVC REST + CRUD Example with JDO</h1>
 
Function : <a href="add">Add Customer</a>
<hr />
 
<h2>All Customers</h2>
<table border="1">
<thead>
<tr>
<td>Name</td>
<td>Email</td>
<td>Created Date</td>
<td>Action</td>
</tr>
</thead>
 
<%
 
if(request.getAttribute("customerList")!=null){
 
List<Customer> customers =
(List<Customer>)request.getAttribute("customerList");
 
if(!customers.isEmpty()){
for(Customer c : customers){
 
%>
<tr>
<td><%=c.getName() %></td>
<td><%=c.getEmail() %></td>
<td><%=c.getDate() %></td>
<td><a href="update/<%=c.getName()%>">Update</a> |
<a href="delete/<%=KeyFactory.keyToString(c.getKey()) %>">
Delete</a>
</td>
</tr>
<%
 
}
 
}
 
}
%>
 
</tr>
 
</table>
 
</body>
</html>

File : add.jsp

<html>
<body>
<h1>Add Customer</h1>
 
<form method="post" action="add">
<table>
<tr>
<td>UserName :</td>
<td><input type="text" style="width: 185px;" maxlength="30"
name="name" id="name" /></span></td>
</tr>
<tr>
<td>Email :</td>
<td><input type="text" style="width: 185px;" maxlength="30"
name="email" id="email" /></span></td>
</tr>
</table>
<input type="submit" class="save" title="Save" value="Save" />
</form>
 
</body>
</html>

File : update.jsp

<%@ page import="com.mkyong.model.Customer" %>
<%@ page import="com.google.appengine.api.datastore.KeyFactory" %>
<html>
<body>
<h1>Update Customer</h1>
 
<%
Customer customer = new Customer();
 
if(request.getAttribute("customer")!=null){
 
customer = (Customer)request.getAttribute("customer");
 
}
 
%>
 
<form method="post" action="../update" >
<input type="hidden" name="key" id="key"
value="<%=KeyFactory.keyToString(customer.getKey()) %>" />
 
<table>
<tr>
<td>
UserName :
</td>
<td>
<input type="text" style="width: 185px;"
maxlength="30" name="name" id="name"
value="<%=customer.getName() %>" />
</td>
</tr>
<tr>
<td>
Email :
</td>
<td>
<input type="text" style="width: 185px;"
maxlength="30" name="email" id="email"
value="<%=customer.getEmail() %>" />
</td>
</tr>
</table>
<input type="submit" class="update" title="Update" value="Update" />
</form>
 
</body>
</html>

5. Demo

Done, see demo to show you the workflow of the web application.

1. A listing page, to display list of existing customers.

URL : http://localhost:8888/customer/list

gar jdo example gar jdo example

2. In listing page, click on the “Add Customer” link to display the add customer page, fill in a new customer, name = “mkyong“, email = “[email protected]” and click on the “Add” button.

URL : http://localhost:8888/customer/add

gar jdo example gar jdo example

3. Saved the customer, it will return back to the listing page.

URL : http://localhost:8888/customer/list

gar jdo example gar jdo example

4. Try update link, it will display the selected customer’s data, update email to “[email protected]“, and click on the update button.

URL : http://localhost:8888/customer/update/mkyong

gar jdo example gar jdo example

5. The email is updated, and redirect back to listing page.

URL : http://localhost:8888/customer/list

gar jdo example gar jdo example

6. To delete the customer, just click on the “delete” link.

Download Source Code

Due to large file size, all Spring MVC and GAE jars are excluded.

Download – GAE-SpringMVC-JDO-example.zip (22 KB)
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s