JPA(Java Persistence API)是JSR(Java Specification Requests)的一部分,定义了一系列对象持久化的标准,目前实现这一规范的产品有Hibernate、TopLink等。
下面的示例程序是在jboss quickStart的基础上修改而来的
1、实体Bean:Member类
package org.jboss.as.quickstart.hibernate4.model; import java.io.Serializable; import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty; @Entity
@XmlRootElement
@Table(name = "MemberHibernate4Demo")
public class Member implements Serializable { private static final long serialVersionUID = 3862416351900991824L; @Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MEMBER_ID_GENERATOR")
@SequenceGenerator(name = "MEMBER_ID_GENERATOR", sequenceName = "SEQ_MEMBER", allocationSize = 1)
private Long id; @NotNull
@Size(min = 1, max = 25)
@Pattern(regexp = "[A-Za-z ]*", message = "must contain only letters and spaces")
private String name; @NotNull
@NotEmpty
private String email; @NotNull
@Size(min = 9, max = 12)
@Digits(fraction = 0, integer = 12)
@Column(name = "phone_number")
private String phoneNumber; private String address; 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;
} public String getEmail() {
return email;
} public void setEmail(String email) {
this.email = email;
} public String getPhoneNumber() {
return phoneNumber;
} public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
} public String getAddress() {
return address;
} public void setAddress(String address) {
this.address = address;
} public String toString() { return "id:" + id + ",name:" + name + ",email:" + email
+ ",phoneNumber:" + phoneNumber + ",address:" + address;
}
}
Member
注意:私有成员id上的注解@SequenceGenerator、@GeneratedValue演示Oracle中序列(Sequence)的用法。
2、服务接口 MemberService
package org.jboss.as.quickstart.hibernate4.service; import java.util.List; import org.jboss.as.quickstart.hibernate4.model.Member; public interface MemberService { void addMember(Member member) throws Exception; void updateMember(Member member) throws Exception; void deleteMember(long id) throws Exception; Member findMember(long id) throws Exception; List<Member> getMembers() throws Exception; }
MemberService
3、服务实现 MemberServiceImpl
package org.jboss.as.quickstart.hibernate4.service; import java.util.logging.Logger;
import java.util.List;
import javax.ejb.Stateless;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.jboss.as.quickstart.hibernate4.model.Member; @Stateless
public class MemberServiceImpl implements MemberService { @PersistenceContext
private EntityManager em; @Inject
private Logger log; @Inject
private Event<Member> memberEventSrc; @Override
public void addMember(Member member) throws Exception {
log.info("addMember => " + member.toString());
member.setId(null);
em.persist(member);
memberEventSrc.fire(member);
} @Override
public void updateMember(Member member) throws Exception {
log.info("updateMember => " + member.getName());
if (member.getId() > 0) {
Member updateObj = findMember(member.getId());
updateObj.setAddress(member.getAddress());
updateObj.setEmail(member.getEmail());
updateObj.setName(member.getName());
updateObj.setPhoneNumber(member.getPhoneNumber());
em.merge(updateObj);
memberEventSrc.fire(updateObj);
} } @Override
public void deleteMember(long id) throws Exception {
log.info("deleteMember => " + id);
Member member = findMember(id);
em.remove(member);
memberEventSrc.fire(member); } @Override
public List<Member> getMembers() throws Exception {
@SuppressWarnings("unchecked")
List<Member> members = em.createQuery("from Member").getResultList();
return members; } @Override
public Member findMember(long id) throws Exception {
log.info("findMember => " + id);
return em.find(Member.class, id);
} }
MemberService
注意:此外大量使用了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
package org.jboss.as.quickstart.hibernate4.util; import java.util.Map;
import java.util.logging.Logger;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.faces.context.FacesContext; public class Resources { @Produces
public Logger produceLog(InjectionPoint injectionPoint) {
return Logger.getLogger(injectionPoint.getMember().getDeclaringClass()
.getName());
} @Produces
@RequestScoped
public FacesContext produceFacesContext() {
return FacesContext.getCurrentInstance();
} @Produces
@RequestScoped
public Map<String, String> getRequestParameterMap(){
return FacesContext.getCurrentInstance().getExternalContext()
.getRequestParameterMap();
} }
Resources
注:该类主要用@Produces提供了CDI注入对象的实例化方法。
5、web层的Controller:MemberController
package org.jboss.as.quickstart.hibernate4.controller; import java.util.List;
import java.util.Map; import javax.annotation.PostConstruct;
import javax.enterprise.inject.Model;
import javax.enterprise.inject.Produces;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named; import org.jboss.as.quickstart.hibernate4.model.Member;
import org.jboss.as.quickstart.hibernate4.service.MemberService; @Model
public class MemberController { @Inject
MemberService service; @Inject
private FacesContext facesContext; @Inject
private Map<String, String> requestMap; private Member newMember; @Produces
@Named
public Member getNewMember() {
return newMember;
} @Produces
@Named
public List<Member> getMembers() {
List<Member> members = null;
try {
members = service.getMembers(); } catch (Exception e) {
String errorMessage = getRootErrorMessage(e);
facesContext.addMessage(null, new FacesMessage(
FacesMessage.SEVERITY_ERROR, errorMessage,
"Delete unsuccessful"));
}
return members;
} public void deleteMemberById() {
try {
String id = requestMap.get("id");
service.deleteMember(Long.parseLong(id)); } catch (Exception e) {
String errorMessage = getRootErrorMessage(e);
facesContext.addMessage(null, new FacesMessage(
FacesMessage.SEVERITY_ERROR, errorMessage,
"Delete unsuccessful"));
} } public void findMemberById() {
try {
String id = requestMap.get("id");
newMember = service.findMember(Long.parseLong(id));
} catch (Exception e) {
String errorMessage = getRootErrorMessage(e);
facesContext.addMessage(null, new FacesMessage(
FacesMessage.SEVERITY_ERROR, errorMessage,
"Find Member unsuccessful"));
} } public void register() {
try {
if (newMember.getId() > 0) {
service.updateMember(newMember);
facesContext.addMessage(null, new FacesMessage(
FacesMessage.SEVERITY_INFO, "Updated!",
"Update successful"));
} else {
service.addMember(newMember);
facesContext.addMessage(null, new FacesMessage(
FacesMessage.SEVERITY_INFO, "Registered!",
"Registration successful"));
}
initNewMember();
} catch (Exception e) {
String errorMessage = getRootErrorMessage(e);
facesContext.addMessage(null, new FacesMessage(
FacesMessage.SEVERITY_ERROR, errorMessage,
"Save unsuccessful"));
}
} @PostConstruct
public void initNewMember() {
newMember = new Member();
} private String getRootErrorMessage(Exception e) {
String errorMessage = "Registration failed. See server log for more information";
if (e == null) {
return errorMessage;
} Throwable t = e;
while (t != null) { errorMessage = t.getLocalizedMessage();
t = t.getCause();
} return errorMessage;
} }
MemberController
6、UI界面index.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
template="/WEB-INF/templates/default.xhtml">
<ui:define name="content">
<h:form id="reg">
<h2>Member Registration</h2> <h:panelGrid columns="3" width="100%" columnClasses="titleCell">
<h:inputHidden value="#{newMember.id}" id="id" />
<h:outputLabel for="name" value="Name:" />
<h:inputText id="name" value="#{newMember.name}" />
<h:message for="name" errorClass="invalid" /> <h:outputLabel for="email" value="Email:" />
<h:inputText id="email" value="#{newMember.email}" />
<h:message for="email" errorClass="invalid" /> <h:outputLabel for="phoneNumber" value="Phone #:" />
<h:inputText id="phoneNumber" value="#{newMember.phoneNumber}" />
<h:message for="phoneNumber" errorClass="invalid" /> <h:outputLabel for="address" value="Address:" />
<h:inputText id="address" value="#{newMember.address}" />
<h:message for="address" errorClass="invalid" />
</h:panelGrid> <h:panelGrid columns="2">
<h:commandButton id="register" action="#{memberController.register}"
value="Register" styleClass="register" />
<h:messages styleClass="messages" errorClass="invalid"
infoClass="valid" warnClass="warning" globalOnly="true" />
</h:panelGrid> </h:form>
<h2>Members</h2>
<h:panelGroup rendered="#{empty members}">
<em>No registered members.</em>
</h:panelGroup>
<h:dataTable var="_member" value="#{members}"
rendered="#{not empty members}" styleClass="simpletablestyle">
<h:column>
<f:facet name="header">Id</f:facet>
#{_member.id}
</h:column>
<h:column>
<f:facet name="header">Name</f:facet>
#{_member.name}
</h:column>
<h:column>
<f:facet name="header">Email</f:facet>
#{_member.email}
</h:column>
<h:column>
<f:facet name="header">Phone #</f:facet>
#{_member.phoneNumber}
</h:column>
<h:column>
<f:facet name="header">Address</f:facet>
#{_member.address}
</h:column>
<h:column>
<f:facet name="header">Operation</f:facet>
<h:form style="border:none">
<h:commandLink action="#{memberController.deleteMemberById}"
value="delete">
<f:param name="id" value="#{_member.id}"></f:param>
</h:commandLink>|
<h:commandLink action="#{memberController.findMemberById}"
value="update">
<f:param name="id" value="#{_member.id}"></f:param>
</h:commandLink>
</h:form>
</h:column>
</h:dataTable>
</ui:define>
</ui:composition>
index.xhtml
7、persistence.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="primary">
<jta-data-source>java:/XE</jta-data-source>
<mapping-file>META-INF/orm.xml</mapping-file>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_sql_comments" value="true"/>
</properties>
</persistence-unit>
</persistence>
persistence.xml
注:该文件位于src/main/resources/META-INF/目录下。java:/XE 是Jboss上配置好的一个数据源JNDI字符串。hibernate.hbm2ddl.auto属性值为create-drop,表明webapp启动时,会自动在db中创建表、序列对象,webapp停止时这些对象会自动drop
8、db初始化脚本 import.sql (测试的时候十分有用)
insert into MemberHibernate4Demo (id, name, email, phone_number, address) values (SEQ_MEMBER.NEXTVAL, 'John Smith', 'john.smith@mailinator.com', '2125551212', 'Boston NY')
insert into MemberHibernate4Demo (id, name, email, phone_number, address) values (SEQ_MEMBER.NEXTVAL, 'Madhumita Sadhukhan', 'msadhukh@gmail.com', '2135551214', 'Brno CZ')
import.sql
注:该文件位于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
运行截图: