JPA(Java Persistence API)是JSR(Java Specification Requests)的一部分,定義了一系列對象持久化的標準,目前實現這一規范的產品有Hibernate、TopLink等。
下面的示例程序是在jboss quickStart的基礎上修改而來的
1、實體Bean:Member類
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package org.jboss.as.quickstart.hibernate4.model; 2 3 import java.io.Serializable; 4 5 import javax.persistence.Column; 6 import javax.persistence.Entity; 7 import javax.persistence.GeneratedValue; 8 import javax.persistence.GenerationType; 9 import javax.persistence.Id; 10 import javax.persistence.SequenceGenerator; 11 import javax.persistence.Table; 12 import javax.validation.constraints.Digits; 13 import javax.validation.constraints.NotNull; 14 import javax.validation.constraints.Pattern; 15 import javax.validation.constraints.Size; 16 import javax.xml.bind.annotation.XmlRootElement; 17 import org.hibernate.validator.constraints.Email; 18 import org.hibernate.validator.constraints.NotEmpty; 19 20 @Entity 21 @XmlRootElement 22 @Table(name = "MemberHibernate4Demo") 23 public class Member implements Serializable { 24 25 private static final long serialVersionUID = 3862416351900991824L; 26 27 @Id 28 @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MEMBER_ID_GENERATOR") 29 @SequenceGenerator(name = "MEMBER_ID_GENERATOR", sequenceName = "SEQ_MEMBER", allocationSize = 1) 30 private Long id; 31 32 @NotNull 33 @Size(min = 1, max = 25) 34 @Pattern(regexp = "[A-Za-z ]*", message = "must contain only letters and spaces") 35 private String name; 36 37 @NotNull 38 @NotEmpty 39 @Email 40 private String email; 41 42 @NotNull 43 @Size(min = 9, max = 12) 44 @Digits(fraction = 0, integer = 12) 45 @Column(name = "phone_number") 46 private String phoneNumber; 47 48 private String address; 49 50 public Long getId() { 51 return id; 52 } 53 54 public void setId(Long id) { 55 this.id = id; 56 } 57 58 public String getName() { 59 return name; 60 } 61 62 public void setName(String name) { 63 this.name = name; 64 } 65 66 public String getEmail() { 67 return email; 68 } 69 70 public void setEmail(String email) { 71 this.email = email; 72 } 73 74 public String getPhoneNumber() { 75 return phoneNumber; 76 } 77 78 public void setPhoneNumber(String phoneNumber) { 79 this.phoneNumber = phoneNumber; 80 } 81 82 public String getAddress() { 83 return address; 84 } 85 86 public void setAddress(String address) { 87 this.address = address; 88 } 89 90 public String toString() { 91 92 return "id:" + id + ",name:" + name + ",email:" + email 93 + ",phoneNumber:" + phoneNumber + ",address:" + address; 94 } 95 }
注意:私有成員id上的注解@SequenceGenerator、@GeneratedValue演示Oracle中序列(Sequence)的用法。
2、服務接口 MemberService
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package org.jboss.as.quickstart.hibernate4.service; 2 3 import java.util.List; 4 5 import org.jboss.as.quickstart.hibernate4.model.Member; 6 7 public interface MemberService { 8 9 void addMember(Member member) throws Exception; 10 11 void updateMember(Member member) throws Exception; 12 13 void deleteMember(long id) throws Exception; 14 15 Member findMember(long id) throws Exception; 16 17 List<Member> getMembers() throws Exception; 18 19 }
3、服務實現 MemberServiceImpl
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package org.jboss.as.quickstart.hibernate4.service; 2 3 import java.util.logging.Logger; 4 import java.util.List; 5 import javax.ejb.Stateless; 6 import javax.enterprise.event.Event; 7 import javax.inject.Inject; 8 import javax.persistence.EntityManager; 9 import javax.persistence.PersistenceContext; 10 import org.jboss.as.quickstart.hibernate4.model.Member; 11 12 @Stateless 13 public class MemberServiceImpl implements MemberService { 14 15 @PersistenceContext 16 private EntityManager em; 17 18 @Inject 19 private Logger log; 20 21 @Inject 22 private Event<Member> memberEventSrc; 23 24 @Override 25 public void addMember(Member member) throws Exception { 26 log.info("addMember => " + member.toString()); 27 member.setId(null); 28 em.persist(member); 29 memberEventSrc.fire(member); 30 } 31 32 @Override 33 public void updateMember(Member member) throws Exception { 34 log.info("updateMember => " + member.getName()); 35 if (member.getId() > 0) { 36 Member updateObj = findMember(member.getId()); 37 updateObj.setAddress(member.getAddress()); 38 updateObj.setEmail(member.getEmail()); 39 updateObj.setName(member.getName()); 40 updateObj.setPhoneNumber(member.getPhoneNumber()); 41 em.merge(updateObj); 42 memberEventSrc.fire(updateObj); 43 } 44 45 } 46 47 @Override 48 public void deleteMember(long id) throws Exception { 49 log.info("deleteMember => " + id); 50 Member member = findMember(id); 51 em.remove(member); 52 memberEventSrc.fire(member); 53 54 } 55 56 @Override 57 public List<Member> getMembers() throws Exception { 58 @SuppressWarnings("unchecked") 59 List<Member> members = em.createQuery("from Member").getResultList(); 60 return members; 61 62 } 63 64 @Override 65 public Member findMember(long id) throws Exception { 66 log.info("findMember => " + id); 67 return em.find(Member.class, id); 68 } 69 70 }
注意:此外大量使用了CDI來實現對象的依賴注入,@PersistenceContext 用于在EJB容器中自動注入"實體管理器"(所以類上要使用@Stateless表示,這是一個無狀態的EJB),上面這段代碼演示了數據的基礎CRUD(Create、Retrieve、Update、Delete)操作,另外為了配合CDI的@Inject注入,還需要一些@Produces的輔助工具類。(對CDI不熟悉的,可以先看看這里 http://www.cnblogs.com/yjmyzz/p/j2ee-cdi-inject.html )
4、輔助類 Resouces
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package org.jboss.as.quickstart.hibernate4.util; 2 3 import java.util.Map; 4 import java.util.logging.Logger; 5 import javax.enterprise.context.RequestScoped; 6 import javax.enterprise.inject.Produces; 7 import javax.enterprise.inject.spi.InjectionPoint; 8 import javax.faces.context.FacesContext; 9 10 public class Resources { 11 12 @Produces 13 public Logger produceLog(InjectionPoint injectionPoint) { 14 return Logger.getLogger(injectionPoint.getMember().getDeclaringClass() 15 .getName()); 16 } 17 18 @Produces 19 @RequestScoped 20 public FacesContext produceFacesContext() { 21 return FacesContext.getCurrentInstance(); 22 } 23 24 @Produces 25 @RequestScoped 26 public Map<String, String> getRequestParameterMap(){ 27 return FacesContext.getCurrentInstance().getExternalContext() 28 .getRequestParameterMap(); 29 } 30 31 32 }
注:該類主要用@Produces提供了CDI注入對象的實例化方法。
5、web層的Controller:MemberController
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 package org.jboss.as.quickstart.hibernate4.controller; 2 3 import java.util.List; 4 import java.util.Map; 5 6 import javax.annotation.PostConstruct; 7 import javax.enterprise.inject.Model; 8 import javax.enterprise.inject.Produces; 9 import javax.faces.application.FacesMessage; 10 import javax.faces.context.FacesContext; 11 import javax.inject.Inject; 12 import javax.inject.Named; 13 14 import org.jboss.as.quickstart.hibernate4.model.Member; 15 import org.jboss.as.quickstart.hibernate4.service.MemberService; 16 17 @Model 18 public class MemberController { 19 20 @Inject 21 MemberService service; 22 23 @Inject 24 private FacesContext facesContext; 25 26 @Inject 27 private Map<String, String> requestMap; 28 29 private Member newMember; 30 31 @Produces 32 @Named 33 public Member getNewMember() { 34 return newMember; 35 } 36 37 @Produces 38 @Named 39 public List<Member> getMembers() { 40 List<Member> members = null; 41 try { 42 members = service.getMembers(); 43 44 } catch (Exception e) { 45 String errorMessage = getRootErrorMessage(e); 46 facesContext.addMessage(null, new FacesMessage( 47 FacesMessage.SEVERITY_ERROR, errorMessage, 48 "Delete unsuccessful")); 49 } 50 return members; 51 } 52 53 public void deleteMemberById() { 54 try { 55 String id = requestMap.get("id"); 56 service.deleteMember(Long.parseLong(id)); 57 58 } catch (Exception e) { 59 String errorMessage = getRootErrorMessage(e); 60 facesContext.addMessage(null, new FacesMessage( 61 FacesMessage.SEVERITY_ERROR, errorMessage, 62 "Delete unsuccessful")); 63 } 64 65 } 66 67 public void findMemberById() { 68 try { 69 String id = requestMap.get("id"); 70 newMember = service.findMember(Long.parseLong(id)); 71 } catch (Exception e) { 72 String errorMessage = getRootErrorMessage(e); 73 facesContext.addMessage(null, new FacesMessage( 74 FacesMessage.SEVERITY_ERROR, errorMessage, 75 "Find Member unsuccessful")); 76 } 77 78 } 79 80 public void register() { 81 try { 82 if (newMember.getId() > 0) { 83 service.updateMember(newMember); 84 facesContext.addMessage(null, new FacesMessage( 85 FacesMessage.SEVERITY_INFO, "Updated!", 86 "Update successful")); 87 } else { 88 service.addMember(newMember); 89 facesContext.addMessage(null, new FacesMessage( 90 FacesMessage.SEVERITY_INFO, "Registered!", 91 "Registration successful")); 92 } 93 initNewMember(); 94 } catch (Exception e) { 95 String errorMessage = getRootErrorMessage(e); 96 facesContext.addMessage(null, new FacesMessage( 97 FacesMessage.SEVERITY_ERROR, errorMessage, 98 "Save unsuccessful")); 99 } 100 } 101 102 @PostConstruct 103 public void initNewMember() { 104 newMember = new Member(); 105 } 106 107 private String getRootErrorMessage(Exception e) { 108 String errorMessage = "Registration failed. See server log for more information"; 109 if (e == null) { 110 return errorMessage; 111 } 112 113 Throwable t = e; 114 while (t != null) { 115 116 errorMessage = t.getLocalizedMessage(); 117 t = t.getCause(); 118 } 119 120 return errorMessage; 121 } 122 123 }
6、UI界面index.xhtml
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?xml version="1.0" encoding="UTF-8"?> 2 <ui:composition xmlns="http://www.w3.org/1999/xhtml" 3 xmlns:ui="http://java.sun.com/jsf/facelets" 4 xmlns:f="http://java.sun.com/jsf/core" 5 xmlns:h="http://java.sun.com/jsf/html" 6 template="/WEB-INF/templates/default.xhtml"> 7 <ui:define name="content"> 8 <h:form id="reg"> 9 <h2>Member Registration</h2> 10 11 <h:panelGrid columns="3" width="100%" columnClasses="titleCell"> 12 <h:inputHidden value="#{newMember.id}" id="id" /> 13 <h:outputLabel for="name" value="Name:" /> 14 <h:inputText id="name" value="#{newMember.name}" /> 15 <h:message for="name" errorClass="invalid" /> 16 17 <h:outputLabel for="email" value="Email:" /> 18 <h:inputText id="email" value="#{newMember.email}" /> 19 <h:message for="email" errorClass="invalid" /> 20 21 <h:outputLabel for="phoneNumber" value="Phone #:" /> 22 <h:inputText id="phoneNumber" value="#{newMember.phoneNumber}" /> 23 <h:message for="phoneNumber" errorClass="invalid" /> 24 25 <h:outputLabel for="address" value="Address:" /> 26 <h:inputText id="address" value="#{newMember.address}" /> 27 <h:message for="address" errorClass="invalid" /> 28 </h:panelGrid> 29 30 31 <h:panelGrid columns="2"> 32 <h:commandButton id="register" action="#{memberController.register}" 33 value="Register" styleClass="register" /> 34 <h:messages styleClass="messages" errorClass="invalid" 35 infoClass="valid" warnClass="warning" globalOnly="true" /> 36 </h:panelGrid> 37 38 </h:form> 39 <h2>Members</h2> 40 <h:panelGroup rendered="#{empty members}"> 41 <em>No registered members.</em> 42 </h:panelGroup> 43 <h:dataTable var="_member" value="#{members}" 44 rendered="#{not empty members}" styleClass="simpletablestyle"> 45 <h:column> 46 <f:facet name="header">Id</f:facet> 47 #{_member.id} 48 </h:column> 49 <h:column> 50 <f:facet name="header">Name</f:facet> 51 #{_member.name} 52 </h:column> 53 <h:column> 54 <f:facet name="header">Email</f:facet> 55 #{_member.email} 56 </h:column> 57 <h:column> 58 <f:facet name="header">Phone #</f:facet> 59 #{_member.phoneNumber} 60 </h:column> 61 <h:column> 62 <f:facet name="header">Address</f:facet> 63 #{_member.address} 64 </h:column> 65 <h:column> 66 <f:facet name="header">Operation</f:facet> 67 <h:form style="border:none"> 68 <h:commandLink action="#{memberController.deleteMemberById}" 69 value="delete"> 70 <f:param name="id" value="#{_member.id}"></f:param> 71 </h:commandLink>| 72 <h:commandLink action="#{memberController.findMemberById}" 73 value="update"> 74 <f:param name="id" value="#{_member.id}"></f:param> 75 </h:commandLink> 76 </h:form> 77 </h:column> 78 </h:dataTable> 79 </ui:define> 80 </ui:composition>
7、persistence.xml 配置文件
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <persistence version="2.0" 4 xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation=" 6 http://java.sun.com/xml/ns/persistence 7 http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> 8 <persistence-unit name="primary"> 9 <jta-data-source>java:/XE</jta-data-source> 10 <mapping-file>META-INF/orm.xml</mapping-file> 11 <properties> 12 <property name="hibernate.hbm2ddl.auto" value="create-drop" /> 13 <property name="hibernate.show_sql" value="true" /> 14 <property name="hibernate.format_sql" value="true" /> 15 <property name="hibernate.use_sql_comments" value="true"/> 16 </properties> 17 </persistence-unit> 18 </persistence>
注:該文件位于src/main/resources/META-INF/目錄下。java:/XE 是Jboss上配置好的一個數據源JNDI字符串。hibernate.hbm2ddl.auto屬性值為create-drop,表明webapp啟動時,會自動在db中創建表、序列對象,webapp停止時這些對象會自動drop
8、db初始化腳本 import.sql (測試的時候十分有用)
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 insert into MemberHibernate4Demo (id, name, email, phone_number, address) values (SEQ_MEMBER.NEXTVAL, 'John Smith', 'john.smith@mailinator.com', '2125551212', 'Boston NY') 2 insert into MemberHibernate4Demo (id, name, email, phone_number, address) values (SEQ_MEMBER.NEXTVAL, 'Madhumita Sadhukhan', 'msadhukh@gmail.com', '2135551214', 'Brno CZ')
注:該文件位于src/main/resources目錄下,webapp啟用時將自動執行該文件中的db 腳本
9、其它運行準備:
9.1 要有Oracle Database環境,比如本機可以安裝一個Express版本
9.2 Jboss中要配置一個java:/XE的數據源,步驟:
a) 先部署ojdbc6.jar (這是oracle驅動,安裝oracle XE或client后,本機安裝目錄下就能找到)
b) 添加oracle 數據源,數據庫驅動選擇ojdbc6.jar,連接串參考 jdbc:oracle:thin:@localhost:1521:XE
示例程序下載:http://files.cnblogs.com/yjmyzz/jboss-jpa-sample.zip
運行截圖:
文章列表