Spring Data,MongoDB和JSF集成教程

示例应用程序简介(MongoShop产品目录)

在学习完本教程之后,将构建具有以下功能要求的示例应用程序(MongoShop产品目录):

1.搜索具有不同条件的产品(例如,sku,产品类型,标题,stc)

2.创建具有不同类别的新产品。

3.编辑选定的产品详细信息

4.从查询屏幕删除选定的产品。

表示层:

JSF在此示例应用程序中用作表示层技术。 PrimeFaces是用于增强JSF UI的轻量级组件之一。 前端交互由该层中的JSF支持bean控制。

服务层:

使用Spring管理的单例服务对象。 业务服务和应用程序逻辑编写在此层中

数据层:

使用Spring数据MongoDB组件。 它提供了与MongoDB面向文档的数据库的集成。 它提供了MongoTemplate,以便可以轻松执行MongoDB操作。 而且,Spring存储库样式数据访问层可以使用Spring数据MongoDB轻松编写。

MongoDB模式设计和数据准备

MongoDB简介

MongoDB是一个开源可扩展的高性能NoSQL数据库。 它是一个面向文档的存储。 它可以存储具有动态模式的JSON样式的文档。 在此应用程序中,每个产品都以JSON样式的文档存储在MongoDB中。

MongoDB中的架构设计

目录中的每个产品均包含常规产品信息(例如,sku,标题和产品类型),价格详细信息(例如,零售价格和标价)和产品子详细信息(例如,音频CD的曲目/书籍的章节)。 在此应用程序中,使用MongoDB。 模式设计将更侧重于数据使用。 它与传统的RDBMS模式设计不同。 MongoDB中的架构设计应为:

样本数据:

x= {sku: '1000001',type: 'Audio Album',title: 'A Love Supreme',description: 'by John Coltrane',publisher: 'Sony Music',pricing: {list: 1200,retail: 1100},details: {title: 'A Love Supreme [Original Recording Reissued]',artist: 'John Coltrane',genre:  'Jazz' ,tracks: ['A Love Supreme Part I: Acknowledgement','A Love Supreme Part II - Resolution','A Love Supreme, Part III: Pursuance','A Love Supreme, Part IV-Psalm'],}
}y= {sku: '1000002',type: 'Audio Album',title: 'Love Song',description: 'by Khali Fong',publisher: 'Sony Music',pricing: {list: 1000,retail: 1200},details: {title: 'Long Song [Original Recording Reissued]',artist: 'Khali Fong',genre:  'R&B',tracks: ['Love Song','Spring Wind Blow','Red Bean','SingAlongSong'],}
}z= {sku: '1000003',type: 'Book',title: 'Node.js for PHP Developers',description: 'by Owen Peter',publisher: 'OReilly Media',pricing: {list: 2500,retail: 2100},details: {title: 'Node.js for PHP Developers',author: 'Mark Owen',genre:  'Technology',chapters: ['Introduction to Node','Server-side JS','PHP API','Example'],}
}

示例查询以添加数据:

db.product.save(x);
db.product.save(y);
db.product.save(z);

示例查询以测试示例数据:

db.product.find({'sku':'1000004'});
db.product.find({'type':'Audio Album'});
db.product.find({'type':'Audio Album', 'details.genre': 'Jazz'});

JSF(PrimeFaces)和Spring数据MongoDB集成

项目的pom.xml

<project xmlns='http://maven.apache.org/POM/4.0.0' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'xsi:schemaLocation='http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd'><modelversion>4.0.0</modelVersion><groupid>com.borislam</groupId><artifactid>mongoShop</artifactId><packaging>war</packaging><version>1.0-SNAPSHOT</version><name>MongoShop Webapp</name><url>http://maven.apache.org</url><dependencies><dependency><groupid>org.jboss.el</groupId><artifactid>com.springsource.org.jboss.el</artifactId><version>2.0.0.GA</version></dependency><dependency>  <groupid>org.primefaces.themes</groupId>  <artifactid>all-themes</artifactId>  <version>1.0.9</version>  </dependency><dependency>  <groupid>org.primefaces</groupId>  <artifactid>primefaces</artifactId>  <version>3.4.2</version>  </dependency><dependency><groupid>commons-beanutils</groupId><artifactid>commons-beanutils</artifactId><version>1.8.3</version></dependency> <dependency><groupid>commons-codec</groupId><artifactid>commons-codec</artifactId><version>1.3</version></dependency> <dependency><groupid>org.apache.directory.studio</groupId><artifactid>org.apache.commons.lang</artifactId><version>2.6</version></dependency><dependency><groupid>commons-digester</groupId><artifactid>commons-digester</artifactId><version>1.8</version></dependency><dependency><groupid>commons-collections</groupId><artifactid>commons-collections</artifactId><version>3.2</version></dependency><dependency><groupid>org.apache.myfaces.core</groupId><artifactid>myfaces-api</artifactId><version>2.1.9</version></dependency><dependency><groupid>org.apache.myfaces.core</groupId><artifactid>myfaces-impl</artifactId><version>2.1.9</version></dependency><dependency><groupid>org.mongodb</groupId><artifactid>mongo-java-driver</artifactId><version>2.10.1</version></dependency><dependency><groupid>junit</groupId><artifactid>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><dependency><groupid>org.springframework.data</groupId><artifactid>spring-data-mongodb</artifactId><version>1.0.3.RELEASE</version></dependency> <dependency><groupid>org.springframework</groupId><artifactid>spring-context</artifactId><version>3.2.0.RELEASE</version></dependency> <dependency><groupid>org.springframework</groupId><artifactid>spring-web</artifactId><version>3.2.0.RELEASE</version></dependency></dependencies><repositories><repository><id>java.net</id><url>https://maven.java.net/content/repositories/public/</url></repository><repository>  <id>prime-repo</id>  <name>PrimeFaces Maven Repository</name>  <url>http://repository.primefaces.org</url>  <layout>default</layout>  </repository><repository><id>com.springsource.repository.bundles.release</id><name>SpringSource Enterprise Bundle Repository - SpringSource Releases</name><url>http://repository.springsource.com/maven/bundles/release</url></repository><repository><id>com.springsource.repository.bundles.external</id><name>SpringSource Enterprise Bundle Repository - External Releases</name><url>http://repository.springsource.com/maven/bundles/external</url></repository><repository><releases><enabled>false</enabled></releases><snapshots><enabled>true</enabled></snapshots><id>apache.snapshots</id><name>Apache Snapshot Repository</name><url>https://repository.apache.org/content/repositories/snapshots</url></repository> <repository><id>jboss-deprecated-repository</id><name>JBoss Deprecated Maven Repository</name><url>https://repository.jboss.org/nexus/content/repositories/deprecated/</url><layout>default</layout><releases><enabled>true</enabled><updatepolicy>never</updatePolicy></releases><snapshots><enabled>false</enabled><updatepolicy>never</updatePolicy></snapshots></repository></repositories><build><finalname>mongoShop</finalName></build>
</project>

我的脸

MyFaces用作此应用程序中的JSF实现。 以下详细信息应添加到web.xml中

PrimeFaces主题

如前所述,PrimeFaces库用于增强UI。 该库几乎不需要配置。 PrimeFaces为您的Web应用程序提供了许多预先设计的主题。 在本例中,我们使用“蓝天”主题。 我们只是在web.xml中添加以下设置

<context-param><param-name>primefaces.THEME</param-name><param-value>glass-x</param-value></context-param>

JSF和Spring集成:

要将JSF与Spring集成,必须在Faces-config.xml中指定SpringBeanFacesELResolver

Faces-config.xml

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version='2.0' xmlns='http://java.sun.com/xml/ns/javaee'xmlns:xi='http://www.w3.org/2001/XInclude'xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd'><application><el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver></application><factory><partial-view-context-factory>org.primefaces.context.PrimePartialViewContextFactory</partial-view-context-factory></factory> 
</faces-config>

完整的web.xml

<?xml version='1.0' encoding='UTF-8'?>
<web-app id='WebApp_ID' version='3.0'xmlns='http://java.sun.com/xml/ns/javaee'xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd'><context-param><param-name>contextConfigLocation</param-name><param-value>WEB-INF/spring-application-context.xml</param-value></context-param><context-param><param-name>errorPageUrl</param-name><param-value>/pages/systemError.do</param-value></context-param><context-param><param-name>facelets.DEVELOPMENT</param-name><param-value>false</param-value></context-param><context-param><param-name>facelets.REFRESH_PERIOD</param-name><param-value>2</param-value></context-param><context-param><param-name>javax.faces.STATE_SAVING_METHOD</param-name><param-value>client</param-value></context-param><context-param><param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name><param-value>resources.application</param-value></context-param><context-param><param-name>org.apache.myfaces.ALLOW_JAVASCRIPT</param-name><param-value>true</param-value></context-param><context-param><param-name>org.apache.myfaces.AUTO_SCROLL</param-name><param-value>false</param-value></context-param><context-param><param-name>org.apache.myfaces.DETECT_JAVASCRIPT</param-name><param-value>false</param-value></context-param><context-param><param-name>org.apache.myfaces.ERROR_HANDLING</param-name><param-value>false</param-value></context-param><context-param><param-name>org.apache.myfaces.EXPRESSION_FACTORY</param-name><param-value>org.jboss.el.ExpressionFactoryImpl</param-value></context-param><context-param><param-name>org.apache.myfaces.PRETTY_HTML</param-name><param-value>false</param-value></context-param><context-param><param-name>primefaces.THEME</param-name><param-value>glass-x</param-value></context-param>  <servlet><servlet-name>Faces Servlet</servlet-name><servlet-class>org.apache.myfaces.webapp.MyFacesServlet</servlet-class><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>Faces Servlet</servlet-name><url-pattern>*.jsf</url-pattern></servlet-mapping><listener><listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class></listener><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
</web-app>

MongoDB连接详细信息

为了连接到MongoDB,您必须以XML注册MongoDbFactory实例。 连接详细信息在spring-application-context.xml中指定

spring-application-context.xml

<?xml version='1.0' encoding='UTF-8'?>
<beans xmlns='http://www.springframework.org/schema/beans'
xmlns:context='http://www.springframework.org/schema/context'xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'xmlns:util='http://www.springframework.org/schema/util'xmlns:mongo='http://www.springframework.org/schema/data/mongo'xsi:schemaLocation='http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/data/mongohttp://www.springframework.org/schema/data/mongo/spring-mongo.xsd            http://www.springframework.org/schema/data/repositoryhttp://www.springframework.org/schema/data/repository/spring-repository.xsd http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.2.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd'><context:annotation-config/><context:component-scan base-package='com.borislam'/><mongo:mongo host='localhost' port='27017'> <mongo:optionsconnections-per-host='5'       connect-timeout='30000'max-wait-time='10000'       write-number='1'write-timeout='0'write-fsync='true'/></mongo:mongo><mongo:db-factory dbname='test' mongo-ref='mongo'/><mongo:repositories base-package='com.borislam.repository' /><bean id='mongoTemplate' class='org.springframework.data.mongodb.core.MongoTemplate'><constructor-arg ref='mongo'/><constructor-arg name='databaseName' value='test'/></bean>
</beans>

使用Spring Data Repository和MongoTemplate来查询数据

Spring资料储存库:

Spring数据存储库抽象减少了用于编写应用程序数据访问层的样板代码。 Repository接口的自动实现提供了对mongoDB的简单操作。 它有助于我们的产品保存和删除功能,使

MongoTemplate:

MongoTemplate提供了方便的操作来创建,更新,删除和查询MongoDB文档,并提供了域对象和MongoDB文档之间的映射。 在我们的应用程序中,由于spring数据存储库无法满足搜索功能的要求,因此我们使用MongoTemplate来归档搜索功能。

自定义Spring数据存储库:

由于无法通过Spring数据存储库抽象轻松地实现产品搜索,因此我们想使用MongoDBTemplate实现多级Criteira产品搜索。 为了使用MongoTemplate丰富Spring数据存储库,我们可以执行以下操作来定制存储库:

ProductRepository.java

package com.borislam.repository;import java.util.List;
import org.springframework.data.repository.PagingAndSortingRepository;
import com.borislam.domain.Product;public interface ProductRepository  extends PagingAndSortingRepository<Product, String> , ProductRepostitoryCustom{List<product> findByType(String type);List<product> findByTypeAndTitle(String type, String title); Product findBySku(String sku);
}

ProductRepositoryCustom.java

package com.borislam.repository;import java.util.List;
import com.borislam.domain.Product;
import com.borislam.view.ProductSearchCriteria;public interface ProductRepostitoryCustom {public List<product> searchByCriteria(ProductSearchCriteria criteria);}

ProductRepositoryImpl.java

package com.borislam.repository.impl;import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.util.StringUtils;
import com.borislam.domain.Product;
import com.borislam.repository.ProductRepostitoryCustom;
import com.borislam.view.ProductSearchCriteria;public class ProductRepositoryImpl implements ProductRepostitoryCustom{@Autowiredprivate MongoTemplate mongoTemplate;@Overridepublic List<product> searchByCriteria(ProductSearchCriteria criteria) {Query query = new Query();if ( StringUtils.hasText(criteria.getSku())) { Criteria c = Criteria.where('sku').is(criteria.getSku());query.addCriteria(c);}if (StringUtils.hasText(criteria.getTitle())) {Criteria c = Criteria.where('title').regex('.*' + criteria.getTitle() + '.*', 'i');query.addCriteria(c);}if (StringUtils.hasText(criteria.getDescription())) {Criteria c = Criteria.where('description').regex('.*' + criteria.getDescription() + '.*', 'i');query.addCriteria(c);}if (StringUtils.hasText(criteria.getProductType())) {Criteria c = Criteria.where('type').is(criteria.getProductType());query.addCriteria(c);}  if (StringUtils.hasText(criteria.getTrack())) {Criteria c = Criteria.where('details.tracks').regex('.*' + criteria.getTrack() + '.*', 'i');query.addCriteria(c);}if (StringUtils.hasText(criteria.getChapter())) {Criteria c = Criteria.where('details.chapters').regex('.*' + criteria.getChapter() + '.*', 'i');query.addCriteria(c);}return mongoTemplate.find(query, Product.class);}}

数据模型:Product.java

package com.borislam.domain;public class Product {private String id;private String sku ;private String  type;private String title;private String description;private String publisher;private Pricing pricing;private Detail details;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getSku() {return sku;}public void setSku(String sku) {this.sku = sku;}public String getType() {return type;}public void setType(String type) {this.type = type;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public String getPublisher() {return publisher;}public void setPublisher(String publisher) {this.publisher = publisher;}public Pricing getPricing() {return pricing;}public void setPricing(Pricing pricing) {this.pricing = pricing;}public Detail getDetails() {return details;}public void setDetails(Detail details) {this.details = details;}    
}

Pricing.java

package com.borislam.domain;public class Pricing {private String id;private double list;private double retail;public String getId() {return id;}public void setId(String id) {this.id = id;}public double getList() {return list;}public void setList(double list) {this.list = list;}public double getRetail() {return retail;}public void setRetail(double retail) {this.retail = retail;}public Pricing(double list, double retail) {super();this.list = list;this.retail = retail;}}

Detail.java

package com.borislam.domain;import java.util.List;public class Detail {private String id;private String title;private String author;private String artist;private String genre;private List<string> pic;private List<string> chapters;private List<string> tracks;public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public String getGenre() {return genre;}public void setGenre(String genre) {this.genre = genre;}public List<string> getPic() {return pic;}public void setPic(List<string> pic) {this.pic = pic;}public List<string> getChapters() {return chapters;}public void setChapters(List<string> chapters) {this.chapters = chapters;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getArtist() {return artist;}public void setArtist(String artist) {this.artist = artist;}public List<string> getTracks() {return tracks;}public void setTracks(List<string> tracks) {this.tracks = tracks;}}

JSF部分:common.xhtml

<html xmlns='http://www.w3.org/1999/xhtml'xmlns:h='http://java.sun.com/jsf/html'xmlns:f='http://java.sun.com/jsf/core'xmlns:ui='http://java.sun.com/jsf/facelets'xmlns:p='http://primefaces.org/ui'><f:view contentType='text/html'><h:head><f:facet name='first'><meta http-equiv='Content-Type' content='text/html; charset=utf-8'/><title><ui:insert name='pageTitle'>Page Title</ui:insert></title><ui:insert name='head' /></f:facet></h:head><h:body><div style='margin:auto;width:1024px;'>
<div id='header' class='ui-widget' >
<div id='logo' style='border:1px  solid #acbece; border-bottom: none; '>
<p:graphicImage   value='/resources/image/mongoshopheader.jpg'/></div>
<div id='logo' style='border:1px solid #acbece;'>
<p:menubar style='border:none'><p:menuitem value='Search' url='/search.jsf' icon='ui-icon-search' /><p:menuitem value='New Product' url='/detail.jsf' icon='ui-icon-document' /></p:menubar></div>
</div>
<div id='page' class='ui-widget' style='overflow:hidden;'>
<div id='content'  style='display:block'>
<ui:insert name='content'>...</ui:insert>     </div>
</div>
</div>
</h:body></f:view>
</html>

Search.xhml

<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:dataTable></h:form></ui:define></ui:composition>
</html>

ProductSearchCriteria.java

package com.borislam.view;public class ProductSearchCriteria {private String sku;private String description;private String productType;private String track;private String chapter;private String title;public String getSku() {return sku;}public void setSku(String sku) {this.sku = sku;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public String getProductType() {return productType;}public void setProductType(String productType) {this.productType = productType;}public String getTrack() {return track;}public void setTrack(String track) {this.track = track;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getChapter() {return chapter;}public void setChapter(String chapter) {this.chapter = chapter;}}

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;}@Autowiredprivate ProductService productService;public void doSearch(ActionEvent event){productList= productService.searchByCriteria(criteria);}
}

服务层: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 {@Autowiredprivate ProductRepository productRepository;public List<product> searchByCriteria(ProductSearchCriteria criteria){return productRepository.searchByCriteria(criteria);}public Product getProduct(String sku) {return productRepository.findBySku(sku);}
}

使用Spring数据存储库创建,编辑和删除数据

在本教程的最后一部分,我们将向MongoShop产品目录应用程序添加创建,编辑和删除功能。 搜索页面已修改。 在实际删除产品之前,已添加模式确认对话框

更新了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>

更新了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;}@Autowiredprivate 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));}}
}

添加了产品详细信息页面以查看产品详细信息。 产品的创建和版本在产品详细信息页面中完成。

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 {@Autowiredprivate 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);}}
}

更新了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 {@Autowiredprivate 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);}}

结论:

1. Spring Data Mongo DB提供了MongoTemplate,可让您轻松执行MongoDB操作。

2.借助Spring Data MongoDB,可以轻松将MongoDB JSON样式的文档映射到POJO

3. Spring数据的存储库抽象减少了访问MongoDB的样板代码。

4.您将自定义行为添加到spring数据存储库。

  • 获取源代码

参考: 示例应用程序简介(MongoShop产品目录) , MongoDB模式设计和数据准备 , JSF(PrimeFaces)和Spring数据MongoDB集成 , 带有Spring数据存储库和mongotemplate的Enquriy数据 , 创建,编辑和删除数据 (来自我们的JCG合作伙伴 Boris)在“ Programming Peaceally和平”博客上,Lam表示。

翻译自: https://www.javacodegeeks.com/2013/02/spring-data-mongodb-and-jsf-integration-tutorial.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/369176.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

本人用python刷题时的错误总结

本人新手&#xff0c;在leetcode刷题过程中出现过很多问题&#xff0c;也发现了很多方法&#xff0c;故在此总结&#xff0c;不定时更新。 1、在创建一个二维列表的时候&#xff0c;我之前会用 a [[0] * 5] * 5, 但是这样输出的结果往往会跟期待的不一样&#xff0c;我一直以为…

增加 jQueryValidate的手机号验证功能

1、通过addMethod增加手机号的验证方法 &#xff08;位置&#xff1a;和$(form).validate({}) 同级别&#xff09; //增加手机号验证规则$.validator.addMethod("isMobile", function(value, element) {var length value.length;var mobile /^(13[0-9]{9})|(18[0-9…

Hibernate继承:每个类层次结构的表

在本教程中&#xff0c;我们将看到如何在hibernate中实现继承。有3种方法可以在hibernate中实现继承。在本文中&#xff0c;我们将看到其中一种&#xff0c;即每个类层次结构一个表。 休眠中的继承&#xff1a; Java是面向对象的语言&#xff0c;继承是Java的主要功能之一。关…

爬取新闻

import requests from bs4 import BeautifulSoup urlhttp://news.gzcc.cn/html/xiaoyuanxinwen/ resrequests.get(url) res.encodingutf-8 soupBeautifulSoup(res.text,html.parser) 1. 用requests库和BeautifulSoup库&#xff0c;爬取校园新闻首页新闻的标题、链接、正文。 fo…

平衡二叉树的自顶向下递归和自底向上递归

没太搞懂自顶向下和自底向上的递归区别

NI Multisim元件库:在Multisim中创建自定义元器件

转载于&#xff1a; http://www.ni.com/tutorial/3173/zhs/ 概览 「在Multisim中创建自定义元器件」与「在 NI Ultiboard中创建自定义元器件」为您提供了关于如何直观、快速地学习如何创建您自己的自定义元器件的信息资源。目录 引言步骤一&#xff1a;输入初始元器件信息步骤二…

字符串的预处理

C isalpha、isalnum、islower、isupper用法 https://blog.csdn.net/weixin_41162823/article/details/80172379 C/C库函数&#xff08;tolower/toupper&#xff09;实现字母的大小写转换 https://blog.csdn.net/laozhuxinlu/article/details/51539737 字符串的逆序 https:…

2017年最新基于Bootstrap 4 的专业、多用途响应式布局的系统模板

本文分享一款2017年最新的2017年最新基于Bootstrap 4 的专业、多用途响应式布局的系统模板&#xff0c;该模板是一款强大并且非常灵活的后台管理系统模板&#xff1a;能适应绝大多数的web应用程序开发&#xff0c;比如&#xff1a;APP的管理后台&#xff0c;电商网站&#xff0…

您的日志就是您的数据:logstash + elasticsearch

今天的帖子的主题与日常的编码和开发无关&#xff0c;但是涵盖了一个非常重要的主题&#xff1a;我们的应用程序日志文件。 我们的应用程序确实会生成大量日志&#xff0c;如果处理正确&#xff0c;则非常有助于解决问题。 如果您启动并运行一个应用程序并没什么大不了&#xf…

关于C++中二维vector使用

https://blog.csdn.net/u014453443/article/details/98057251

面向对象设计与构造第一次总结作业

第一次作业——多项式计算 ---结构分析 第一次作业我只使用了两个类&#xff0c;正像下面的类图所表示的那样&#xff0c;分别是Poly和ComputePoly。Poly类是不可变的&#xff0c;能保存一个多项式&#xff0c;可以进行加、减运算。ComputePoly是程序的主类&#xff0c;能够读取…

python字符串常见操作

字符串常见操作 如有字符串mystr hello world itcast and itcastcpp&#xff0c;以下是常见的操作 <1>find 检测 str 是否包含在 mystr中&#xff0c;如果是返回开始的索引值&#xff0c;否则返回-1 mystr.find(str, start0, endlen(mystr))<2>index 跟find()方法…

调整图像的灰度级数C++实现

图像灰度级数我们见得最多的就是256了&#xff0c;如果想调整它的灰度级数&#xff0c;我们可以使用图像库的imadjust函数来作出调整&#xff0c;比如讲256个灰度级变成2个灰度级&#xff08;也就是二值图了&#xff09;。再举一个例子&#xff0c;原来一幅256个灰度级的图像&a…

[BZOJ2095][Poi2010]Bridges 最大流(混合图欧拉回路)

2095: [Poi2010]Bridges Time Limit: 10 Sec Memory Limit: 259 MBDescription YYD为了减肥&#xff0c;他来到了瘦海&#xff0c;这是一个巨大的海&#xff0c;海中有n个小岛&#xff0c;小岛之间有m座桥连接&#xff0c;两个小岛之间不会有两座桥&#xff0c;并且从一个小岛…

excel和python建模_利用Excel学习Python:准备篇

写在前面这个系列我们要利用Excel的知识&#xff0c;学会用python进行数据分析&#xff0c;如果你精通Excel想要用python提高数据分析效率&#xff0c;那么这个系列你来对了&#xff0c;如果你已经是python大神&#xff0c;想要建模/算法等高级技巧的&#xff0c;这个系列可能不…

方法内联在JVM中有多积极?

IntelliJ IDEA中使用Ctrl Alt M 提取方法 。 Ctrl Alt M。 这就像选择一段代码并按此组合一样简单。 Eclipse也有它 。 我讨厌冗长的方法。 对于我来说&#xff0c;闻起来太久了&#xff1a; public void processOnEndOfDay(Contract c) {if (DateUtils.addDays(c.getCrea…

Python正则表达式基础

1. 正则表达式基础 1.1. 简单介绍 正则表达式并不是Python的一部分。正则表达式是用于处理字符串的强大工具&#xff0c;拥有自己独特的语法以及一个独立的处理引擎&#xff0c;效率上可能不如str自带的方法&#xff0c;但功能十分强大。得益于这一点&#xff0c;在提供了正则表…

Java并发:隐藏线程死锁

大多数Java程序员熟悉Java线程死锁概念。 它本质上涉及2个线程&#xff0c;它们彼此永远等待。 这种情况通常是平面&#xff08;同步&#xff09;或ReentrantLock&#xff08;读或写&#xff09;锁排序问题的结果。 Found one Java-level deadlock:"pool-1-thread-2"…

vue中使用axios发送请求

我们知道&#xff0c;vue2.0以后&#xff0c;vue就不再对vue-resource进行更新&#xff0c;而是推荐axios&#xff0c;而大型项目都会使用 Vuex 来管理数据&#xff0c;所以这篇博客将结合两者来发送请求 1.安装axios cnpm i axios -S 2.方案一&#xff1a;修改原型链 首先&…