2011년 5월 23일 월요일

EJB3.0 CMP With JBoss 4 - Chap 2 Sample Programming

Chap 2 Sample Programming
ejb30.UserSessionInfStateless SessionBean Remote Interface
ejb30.UserSessionBeanStateless SessionBean
ejb30.PersonPerson Entity
ejb30.DepartDepart Entity
ejb30.PhonePhone Entity

Code
ejb30.Person
package ejb30;
import java.io.Serializable;
import java.util.Collection;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity(access = AccessType.FIELD)
@Table(name="CMP_Person")
@NamedQuery(
name="findPersonByName",
queryString="SELECT OBJECT(o) FROM Person o WHERE o.name = :name"
)
public class Person implements Serializable {
private static final long serialVersionUID = 8611965730879313671L;
@Column(name="person_id", length=10)
@Id(generate = GeneratorType.SEQUENCE)
private String id;
@Column(length=20)
private String name;
@Column(length=2)
private int age;
private double account;
private float pay;
@OneToMany(cascade= {CascadeType.ALL})
@JoinColumn(name="person_id", referencedColumnName="person_id")
private Collection<Phone> phones;
@ManyToMany(cascade=CascadeType.PERSIST)
private Collection<Depart> depart;
public double getAccount() {
return account;
}
public void setAccount(double account) {
this.account = account;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPay() {
return pay;
}
public void setPay(float pay) {
this.pay = pay;
}
public Collection<Phone> getPhones() {
return phones;
}
public void setPhones(Collection<Phone> phones) {
this.phones = phones;
}
public void addPhone(Phone phone) {
phone.setPerson(this);
getPhones().add(phone);
}
public void removePhone(Phone phone) {
getPhones().remove(phone);
}
public Collection<Depart> getDepart() {
return depart;
}
public void setDepart(Collection<Depart> depart) {
this.depart = depart;
}
public void addDepart(Depart depart) {
getDepart().add(depart);
}
public void removeDepart(Depart depart) {
getDepart().remove(depart);
}
}

@Entity(access = AccessType.FIELD)

Entity 접근 타입을 지정한다. FIELD,PROPERTY 두 가지 타입을 사용한다.
@Table(name="CMP_Person")

Entity와 매핑될 RDB의 Table을 지정한다. 지정하지 않으면 Entity 명과 같은 Table에 매핑된다. 여기서는 Person이 된다.
@NamedQuery(
name="findPersonByName",
queryString="SELECT OBJECT(o) FROM Person o WHERE o.name = :name"
)


추가 Finder Method와 EJB Query을 지정한다. “:name” Finder Method에서 인수로 받을 부분이다.
@Column(name="person_id", length=10)
@Id(generate = GeneratorType.SEQUENCE)


Person Entity의 필드와 매핑될 Table의 컬럼 명, 길이을 지정한다.
@Id인 경우는 해당 필드가 “PK”로 사용됨을 명시하고 Id의 생성방식을 “generate”로 지정한다. 여기서는 자동 Sequence번호를 부여하는 방식이다.
@OneToMany(cascade= {CascadeType.ALL})
@JoinColumn(name="person_id", referencedColumnName="person_id")
private Collection<Phone> phones

다른 Entity와 일대다 관계를 표현한다. 여기서 Person과 Phone은 일대다 관계로 한 사람이 여러 개의 전화번호를 가질 수 있음을 표현한다. Person Entity에서 “OneToMany”을 지정하게 되면 Phone Entity에서는 “ManyToOne”관계를 지정해 줘야 한다.
CascadeType은 ALL, PERSIST, MERGE, REMOVE, REFLESH 값을 가질 수 있으며 이는 연관 Entity의 영속성에 관련된다.
JoinColumn은 Phone Entity 측 “FK”로 사용된다.
@ManyToMany(cascade=CascadeType.PERSIST)
private Collection<Depart> depart;

다른 Entity와 “다대다” 관계를 표현한다. 여기서는 Person과 Depart가 “다대다” 관계이다. Depart Entity에서도 “ManyToMany” 관계를 지정해줘야 하며 “ManyToMany”관계는 Person, Depart 관계를 표현하기 위해 관계 Table을 생성한다. 관계 Table 이름은 Person Table명+_+Depart Table명이다.
자동 생성된 Table
SQL> desc cmp_person
이름 널? 유형
----------------------------------------- -------- ------------------------ PERSON_ID NOT NULL VARCHAR2(10 CHAR)
NAME VARCHAR2(20 CHAR)
AGE NUMBER(10)
ACCOUNT NOT NULL FLOAT(126)
PAY NOT NULL FLOAT(126)

ejb30.Phone
package ejb30;
import java.io.Serializable;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity(access = AccessType.FIELD)
@Table(name="CMP_Phone")
public class Phone implements Serializable {
public final static String HOME = "HOME";
public final static String OFFICE = "OFFICE";
public final static String CELL = "CELL";
private static final long serialVersionUID = -7418220268802851391L;
@Column(name="phone_id", length=10)
@Id(generate = GeneratorType.SEQUENCE)
private String id;
@ManyToOne(fetch= FetchType.LAZY)
@JoinColumn(name="person_id", referencedColumnName="person_id")
private Person person;
@Column(name="phone_type", length=10)
private String type;
@Column(name="phone_number", length=20)
private String number;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}

@ManyToOne(fetch= FetchType.LAZY)
@JoinColumn(name="person_id", referencedColumnName="person_id")

“다대일”관계를 표현한다. 여기서 Phone Entity와 Person Entity의 관계이며 한 사람이 여러 개의 전화번호를 가지고 있음을 표현한다. Person Entity 에서 “OneToMany” 관계로 표현되어 있어야 한다.
FetchType은 “일대다” 관계에서 “일”에 해당되는 Entity을 가져올 때 “다”에 해당하는 Entity을 함께 가져올 것인지 여부를 결정하는 것이다. EAGER는 포함하는 것이며, LAZY는 포함하지 않는 것이다.
자동 생성된 Table
SQL> desc cmp_phone
이름 널? 유형
----------------------------------------- -------- -----------------------
PHONE_ID NOT NULL VARCHAR2(10 CHAR)
PHONE_TYPE VARCHAR2(10 CHAR)
PHONE_NUMBER VARCHAR2(20 CHAR)
PERSON_ID VARCHAR2(10 CHAR)

ejb30.Depart
package ejb30;
import java.io.Serializable;
import java.util.Collection;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratorType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity(access = AccessType.FIELD)
@Table(name="CMP_Depart")
@NamedQuery(
name="findDepartByName",
queryString="SELECT OBJECT(o) FROM Depart o WHERE o.name = :name"
)
public class Depart implements Serializable {
private static final long serialVersionUID = -8498992115996619134L;
@Column(name="depart_id", length=10)
@Id(generate = GeneratorType.SEQUENCE)
private String id;
private String name;
@ManyToMany(mappedBy="depart")
private Collection<Person> persons;
@OneToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
@JoinColumn(name="phone_id")
private Phone phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Collection<Person> getPersons() {
return persons;
}
public void setPersons(Collection<Person> persons) {
this.persons = persons;
}
public void addPerson(Person person) {
getPersons().add(person);
}
public void removePerson(Person person) {
getPersons().remove(person);
}
public Phone getPhone() {
return phone;
}
public void setPhone(Phone phone) {
this.phone = phone;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}

@ManyToMany(mappedBy="depart")
private Collection<Person> persons;

mappedBy는 Person Entity에서 지정된 Depart Entity의 필드 명을 명시해 준다.
@OneToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
@JoinColumn(name="phone_id")
private Phone phone;

“일대일”관계를 표현한다.
자동 생성된 Table
SQL> desc cmp_depart
이름 널? 유형
----------------------------------------- -------- ----------------------------
DEPART_ID NOT NULL VARCHAR2(10 CHAR)
NAME VARCHAR2(255 CHAR)
PHONE_ID VARCHAR2(10 CHAR)
SQL> desc CMP_PERSON_CMP_DEPART
이름 널? 유형
----------------------------------------- -------- -----------------------
PERSONS_PERSON_ID NOT NULL VARCHAR2(10 CHAR)
DEPART_DEPART_ID NOT NULL VARCHAR2(10 CHAR)

Stateless Session Bean : UserSessionBean
remote Interface
package ejb30;
import java.util.Collection;
import javax.ejb.Remote;
@Remote
public interface UserSessionInf {
// Business Method
public Depart createDepart(String name);
public void createPerson(double account, int age, String name, float pay);
public Phone createPhone(String type, String number);
public void addPhoneNumberTo(String type, String number, String personID);
public Collection findAllPersonByName(String name);
public Collection findPersonByAgeOver(int age);
public Collection findPersonByPhone(String number);
public Person findPerson(String id);
public Collection findAllPerson();
}


Bean Class
package ejb30;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless
public class UserSessionBean implements UserSessionInf {
@PersistenceContext
protected EntityManager em;
public void setEntityManager(EntityManager em) {
this.em = em;
}
public EntityManager getEntityManager() {
return em;
}
public Depart createDepart(String name) {
Depart depart = new Depart();
depart.setName(name);
em.persist(depart);
return depart;
}
public void createPerson(double account, int age, String name, float pay) {
Person person = new Person();
person.setAccount(account);
person.setAge(age);
person.setName(name);
person.setPay(pay);
em.persist(person);
}
public Phone createPhone(String type, String number) {
Phone phone = new Phone();
phone.setType(type);
phone.setNumber(number);
em.persist(phone);
return phone;
}
public void addPhoneNumberTo(String type, String number, String personID) {
Phone phone = createPhone(type, number);
Person person = findPerson(personID);
person.addPhone(phone);
}
public List findAllPersonByName(String name) {
List persons =
em.createNamedQuery("findPersonByName")
.setParameter("name", name)
.getResultList();
return persons;
}
public List findPersonByAgeOver(int age) {
List persons = em.createQuery("SELECT OBJECT(o) FROM Person o WHERE o.age > :age")
.setParameter("age", age).getResultList();
return persons;
}
public List findPersonByPhone(String number) {
List persons = em.createQuery("SELECT OBJECT(o) FROM Person o WHERE o.phone.number = :number")
.setParameter("number", number).getResultList();
return persons;
}
public Person findPerson(String id){
return (Person) em.find(Person.class, id);
}
public List findAllPerson() {
ArrayList list = new ArrayList();
List<Person> persons = em.createQuery("SELECT OBJECT(o) FROM Person o").getResultList();
for(Person o : persons) {
list.add(o.getName());
}
return list;
}
}

@PersistenceContext
protected EntityManager em;
em.persist(depart);

Entity Bean의 영속성을 관리할 때 사용한다. persisit() 생성, merge() 수정, remove() 삭제 등의 메서드를 가지고 있다.
em.createNamedQuery("findPersonByName")
.setParameter("name", name)

Person Entity의 “@NamedQuery” 로 작성한 Finder 메서드를 호출한다.
List persons = em.createQuery("SELECT OBJECT(o) FROM Person o WHERE o.age > :age")
.setParameter("age", age).getResultList();

EJBQuery 작성하여 Entity Bean 조회한다.
Client Program
<%@ page language="java" import="java.util.*, java.sql.*, javax.sql.*, javax.naming.*, ejb30.*" pageEncoding="UTF-8"%>
<%@ page import="ejb30.Person" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
String name = request.getParameter("name");
double account = new Double(request.getParameter("account")).doubleValue();
float pay = new Float(request.getParameter("pay")).floatValue();
int age = new Integer(request.getParameter("age")).intValue();
Context ctx = new InitialContext();
UserSessionInf service = (UserSessionInf)ctx.lookup(UserSessionInf.class.getName());
service.createPerson(account,age,name,pay);
Collection persons = service.findAllPerson();
Iterator it = persons.iterator();
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>EJB 30 List.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<P><STRONG><FONT size="5">EJB 3.0 List.jsp</FONT></STRONG>&nbsp;</P>
<P>
<HR>
</P>
<TABLE border="1" width="800px">
<TR>
<TD>Name</TD>
</TR>
<%
while(it.hasNext()) {
%>
<TR>
<TD><%=it.next()%></TD>
</TR>
<%
}
%>
</TABLE>
</body>
</html>

EJB 3.0을 클라이언트 측에서 사용할 때는 기존 버전과 다른 점이 없다. EJB SessionBean을 배포할 때 특별히 JNDI Name을 지정하지 않으면 Remote나, Local Interface명칭(package포함) JNDI Name이 된다.

댓글 없음:

댓글 쓰기

블록체인 개요 및 오픈소스 동향

블록체인(block chain) 블록체인은 공공 거래장부이며 가상 화폐로 거래할때 발생할때 발생할 수 있는 해킹을 막는 기술. 분산 데이터베이스의 한 형태로, 지속적으로 성장하는 데이터 기록 리스트로서 분산 노드의 운영자에 의한 임의 조작이 불가...