Create, Edit and Delete data with Spring data repository
In the last part of this tutorial, we will add create, edit and delete function to the MongoShop Product Catalog application.
The search page is modified. A modal confirm dialogue box is added before the product is physically deleted
updated search.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<ui:composition template="/template/common.xhtml">
<ui:define name="pageTitle">
<h:outputText value="Product Search" />
</ui:define>
<ui:define name="content">
<h:form id="searchForm">
<p:growl id="mainGrowl" sticky="true" />
<p:panelGrid style="width:1024px">
<f:facet name="header">
<p:row>
<p:column colspan="4">
Product Search
</p:column>
</p:row>
</f:facet>
<p:row>
<p:column>
<h:outputLabel for="sku" value="sku: " />
</p:column>
<p:column>
<p:inputText id="sku" value="#{productSearchBean.criteria.sku}" />
</p:column>
<p:column>
<h:outputLabel for="productType" value="Product Type: " />
</p:column>
<p:column>
<p:selectOneMenu id="productType" label="Type" value="#{productSearchBean.criteria.productType}" >
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItem itemLabel="Audio Album" itemValue="Audio Album" />
<f:selectItem itemLabel="Book" itemValue="Book" />
</p:selectOneMenu>
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputLabel for="title" value="Title: " />
</p:column>
<p:column>
<p:inputText id="title" value="#{productSearchBean.criteria.title}" />
</p:column>
<p:column>
<h:outputLabel for="description" value="Description: " />
</p:column>
<p:column>
<p:inputText id="description" value="#{productSearchBean.criteria.description}" />
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputLabel for="track" value="Track: " />
</p:column>
<p:column>
<p:inputText id="track" value="#{productSearchBean.criteria.track}" />
</p:column>
<p:column>
<h:outputLabel for="chapter" value="Chapter: " />
</p:column>
<p:column>
<p:inputText id="chapter" value="#{productSearchBean.criteria.chapter}" />
</p:column>
</p:row>
</p:panelGrid>
<p:commandButton value="search" icon="ui-icon-search" actionListener="#{productSearchBean.doSearch}" update="dataTable"/>
<hr/>
<p:dataTable id="dataTable" var="prod" value="#{productSearchBean.productList}"
paginator="true" rows="10">
<p:column>
<f:facet name="header">
<h:outputText value="Sku" />
</f:facet>
<h:outputText value="#{prod.sku}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Type" />
</f:facet>
<h:outputText value="#{prod.type}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Title" />
</f:facet>
<h:outputText value="#{prod.title}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Publisher" />
</f:facet>
<h:outputText value="#{prod.publisher}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Artist" />
</f:facet>
<h:outputText value="#{prod.details.artist}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Author" />
</f:facet>
<h:outputText value="#{prod.details.author}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Edit" />
</f:facet>
<p:commandButton value="Edit" action="#{productSearchBean.doEditDetail}" ajax="false">
<f:setPropertyActionListener target="#{productSearchBean.selectedProduct}" value="#{prod}" />
</p:commandButton>
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Delete" />
</f:facet>
<p:commandButton id="showDialogButton" value="Delete" oncomplete="confirmation.show()" ajax="true" update=":searchForm:confirmDialog">
<f:setPropertyActionListener target="#{productSearchBean.selectedProduct}" value="#{prod}" />
</p:commandButton>
</p:column>
</p:dataTable>
<p:confirmDialog id="confirmDialog" message="Are you sure to delete this product (#{productSearchBean.selectedProduct.sku})?"
header="Delete Product" severity="alert" widgetVar="confirmation">
<p:commandButton id="confirm" value="Yes" update="mainGrowl" oncomplete="confirmation.hide()"
actionListener="#{productSearchBean.doDelete}" />
<p:commandButton id="decline" value="No" onclick="confirmation.hide()" type="button" />
</p:confirmDialog>
</h:form>
</ui:define>
</ui:composition>
</html>
updated ProductSearchBean.java
package com.borislam.view;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;
import com.borislam.domain.Product;
import com.borislam.service.ProductService;
@Component
@Scope("session")
public class ProductSearchBean {
private Product selectedProduct;
private ProductSearchCriteria criteria = new ProductSearchCriteria();
private List<Product> productList;
public Product getSelectedProduct() {
return selectedProduct;
}
public void setSelectedProduct(Product selectedProduct) {
this.selectedProduct = selectedProduct;
}
public List<Product> getProductList() {
return productList;
}
public void setProductList(List<Product> productList) {
this.productList = productList;
}
public ProductSearchCriteria getCriteria() {
return criteria;
}
public void setCriteria(ProductSearchCriteria criteria) {
this.criteria = criteria;
}
@Autowired
private ProductService productService;
public void doSearch(ActionEvent event){
productList= productService.searchByCriteria(criteria);
}
public String doEditDetail() {
(FacesContext.getCurrentInstance().getExternalContext().getFlash()).put("selected", selectedProduct);
return "detail.xhtml";
}
public void doDelete(ActionEvent event){
try {
productService.deleteProduct(selectedProduct);
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, new FacesMessage("Delete Successfully!"));
}
catch (DataAccessException e ) {
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,"Error when deleting product!",null));
}
}
}
A product detail page is added to view the produc details. Creation and edition of product is done in the product detail page.
detail.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<ui:composition template="/template/common.xhtml">
<ui:define name="pageTitle">
<h:outputText value="Product Search" />
</ui:define>
<ui:define name="content">
<f:event listener="#{productDetailBean.initProduct}" type="preRenderView" />
<h:form id="mainForm">
<p:growl id="mainGrowl" sticky="true" />
<p:panelGrid style="width:1024px">
<f:facet name="header">
<p:row>
<p:column colspan="2">
Product Details
</p:column>
</p:row>
</f:facet>
<p:row>
<p:column>
<h:outputLabel for="sku" value="sku: *" />
</p:column>
<p:column>
<p:inputText id="sku" required="true" value="#{productDetailBean.product.sku}" label="Sku" rendered="#{productDetailBean.newProduct}"/>
<h:outputText value="#{productDetailBean.product.sku}" label="Sku" rendered="#{not productDetailBean.newProduct}"/>
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputLabel for="type" value="Type *" />
</p:column>
<p:column>
<p:selectOneMenu id="type" required="true" label="Type" valueChangeListener="#{productDetailBean.clearDetails}" value="#{productDetailBean.product.type}" >
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItem itemLabel="Audio Album" itemValue="Audio Album" />
<f:selectItem itemLabel="Book" itemValue="Book" />
<f:ajax render="buttonPanel trackPanel chapterPanel"/>
</p:selectOneMenu>
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputLabel for="title" value="Title: *" />
</p:column>
<p:column>
<p:inputText id="title" required="true" value="#{productDetailBean.product.title}" label="Title" />
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputLabel for="description" value="Description: *" />
</p:column>
<p:column>
<p:inputText id="description" required="true" value="#{productDetailBean.product.description}" label="Description" />
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputLabel for="publisher" value="Publisher: *" />
</p:column>
<p:column>
<p:inputText id="publisher" required="true" value="#{productDetailBean.product.publisher}" label="Publisher" />
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputLabel for="artist" value="Artist: " />
</p:column>
<p:column>
<p:inputText id="artist" value="#{productDetailBean.product.details.artist}" label="Artist" />
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputLabel for="listPrice" value="List Price: " />
</p:column>
<p:column>
<p:inputText id="listPrice" required="true" value="#{productDetailBean.product.pricing.list}" label="List Price" />
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputLabel for="retailPrice" value="Retail Price: " />
</p:column>
<p:column>
<p:inputText id="retailPrice" required="true" value="#{productDetailBean.product.pricing.retail}" label="REtail Price" />
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputLabel for="author" value="Author: " />
</p:column>
<p:column>
<p:inputText id="author" value="#{productDetailBean.product.details.author}" label="Author" />
</p:column>
</p:row>
<p:row>
<p:column>
<h:outputLabel for="genre" value="Genre: *" />
</p:column>
<p:column>
<p:inputText id="genre" required="true" value="#{productDetailBean.product.details.genre}" label="Genre" />
</p:column>
</p:row>
<p:row>
<p:column colspan="2" styleClass="ui-widget-header">
<p:outputPanel id="buttonPanel">
<p:commandButton value="Add Tracks" onclick="addTrackDlg.show();" type="button" rendered="#{productDetailBean.product.type == 'Audio Album'}"/>
<p:commandButton value="Add Chapters" onclick="addChapterDlg.show();" type="button" rendered="#{productDetailBean.product.type == 'Book'}"/>
</p:outputPanel>
</p:column>
</p:row>
<p:row>
<p:column colspan="2" >
<p:outputPanel id="trackPanel" >
<p:dataList value="#{productDetailBean.product.details.tracks}" var="track" type="ordered" rendered="#{productDetailBean.product.details.tracks.size() > 0}">
#{track}
</p:dataList>
</p:outputPanel>
<p:outputPanel id="chapterPanel" >
<p:dataList value="#{productDetailBean.product.details.chapters}" var="chapter" type="ordered" rendered="#{productDetailBean.product.details.chapters.size() > 0}">
#{chapter}
</p:dataList>
</p:outputPanel>
</p:column>
</p:row>
<f:facet name="footer">
<p:row>
<p:column colspan="2">
<p:commandButton value="Save" icon="ui-icon-disk" actionListener="#{productDetailBean.doSave}" update="mainGrowl" />
<p:button value="Back to Search" icon="ui-icon-back" outcome="search.xhtml" />
</p:column>
</p:row>
</f:facet>
</p:panelGrid>
</h:form>
<h:form>
<p:growl id="trackGrowl" sticky="true" />
<p:dialog id="addTrackDlg" header="Adding Tracks for the product" widgetVar="addTrackDlg" modal="true" height="100" width="450" resizable="false">
<h:outputLabel for="track" value="Track: " />
<p:inputText id="track" required="true" value="#{productDetailBean.newTrack}" label="Track" />
<p:commandButton value="Add" actionListener="#{productDetailBean.doAddTracks}" icon="ui-icon-check" update="trackGrowl, :mainForm:trackPanel" oncomplete="addTrackDlg.hide()"/>
</p:dialog>
</h:form>
<h:form>
<p:growl id="chapterGrowl" sticky="true" />
<p:dialog id="addChapterDlg" header="Adding Chapters for the product" widgetVar="addChapterDlg" modal="true" height="100" width="450" resizable="false">
<h:outputLabel for="chapter" value="Chapter: " />
<p:inputText id="chapter" required="true" value="#{productDetailBean.newChapter}" label="Chapter" />
<p:commandButton value="Add" actionListener="#{productDetailBean.doAddChapters}" icon="ui-icon-check" update="chapterGrowl, :mainForm:chapterPanel" oncomplete="addChapterDlg.hide()"/>
</p:dialog>
</h:form>
</ui:define>
</ui:composition>
</html>
ProductDetailsBean.java
package com.borislam.view;
import java.util.ArrayList;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.dao.DataAccessException;
import com.borislam.domain.Detail;
import com.borislam.domain.Pricing;
import com.borislam.domain.Product;
import com.borislam.service.ProductService;
@Component
@Scope("session")
public class ProductDetailBean {
@Autowired
private ProductService productService;
private boolean newProduct;
private Product product;
private String newTrack;
private String newChapter;
public boolean isNewProduct() {
return newProduct;
}
public void setNewProduct(boolean newProduct) {
this.newProduct = newProduct;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public String getNewTrack() {
return newTrack;
}
public void setNewTrack(String newTrack) {
this.newTrack = newTrack;
}
public String getNewChapter() {
return newChapter;
}
public void setNewChapter(String newChapter) {
this.newChapter = newChapter;
}
public void initProduct(){
Object selectedProduct = (FacesContext.getCurrentInstance().getExternalContext().getFlash()).get("selected");
if (selectedProduct==null && !FacesContext.getCurrentInstance().isPostback()) {
product = new Product();
product.setDetails(new Detail());
product.setPricing(new Pricing(0,0));
setNewProduct(true);
}
if (selectedProduct!=null) {
product = (Product)selectedProduct;
setNewProduct(false);
}
}
public void doSave(ActionEvent event) {
try {
productService.saveProduct(product);
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, new FacesMessage("Save Successfully!"));
}
catch (DataAccessException e)
{
e.printStackTrace();
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,"Error when saving product!",null));
}
}
public void doAddTracks(ActionEvent event) {
List<String> tracks = product.getDetails().getTracks();
if (CollectionUtils.isEmpty(tracks)) {
product.getDetails().setTracks(new ArrayList<String>());
}
product.getDetails().getTracks().add(this.newTrack);
}
public void doAddChapters(ActionEvent event) {
List<String> tracks = product.getDetails().getChapters();
if (CollectionUtils.isEmpty(tracks)) {
product.getDetails().setChapters(new ArrayList<String>() );
}
product.getDetails().getChapters().add(this.newChapter);
}
public void clearDetails(ValueChangeEvent event) {
if ("Audio Album".equalsIgnoreCase(event.getNewValue().toString()) ) {
product.getDetails().setChapters(null);
}
if ("Book".equalsIgnoreCase( event.getNewValue().toString())) {
product.getDetails().setTracks(null);
}
}
}
updated ProductService.java
package com.borislam.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.borislam.domain.Product;
import com.borislam.repository.ProductRepository;
import com.borislam.view.ProductSearchCriteria;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public List<Product> searchByCriteria(ProductSearchCriteria criteria){
return productRepository.searchByCriteria(criteria);
}
public Product getProduct(String sku) {
return productRepository.findBySku(sku);
}
public void saveProduct(Product p){
productRepository.save(p);
}
public void deleteProduct(Product p){
productRepository.delete(p);
}
}
Conclusion:
1. Spring Data Mongo DB provides MongoTemplate which allow you to perform MongoDB operation easily.
2. MongoDB JSON-style document could mapped to POJO easily with the help of Spring Data MongoDB
3. Repository abstraction of spring data reduces the boilerplate code write for accessing MongoDB.
4. You add custom behaviour to spring data repository.
Get the source code
Comments
Any ideas?
I have corrected the pom.xml and commited to GitHub. You could get the latest one in GitHub
ServletContext sc = (ServletContext)fc.getExternalContext().getContext();
ConfigurableApplicationContext context =
(ConfigurableApplicationContext)WebApplicationContextUtils.getWebApplicationContext(sc);
Thanks....