สร้าง EJB project ชื่อว่า titan-ejb เลือก Target Runtime : Glassfish
คลิกขวาที่ Project
ติ๊ก JPA facet, และ configure JPA facet ให้ใช้ connection profile ที่สร้างไว้แล้ว
>>>>>>>>>>>>>>>>>>> วิธีสร้าง JPA Entity:
- คลิกขวาที่ Project Explorer- New->Class ชื่อ com.titan.domain.Cabin
implement java.io.Serializable
[ Serializable คือ สามารถ convert class to String แล้วส่งไปที่ network ได้ ]
วิธีสร้าง implement class บน eclipse
มันก็จะสร้างฟังก์ชั่นโบ๋ๆ มาให้
package com.titan.domain;
import java.io.Serializable;
public class Cabin implements Serializable {
}
- Add the fields
static final long serialVersionUID = 1L;
private int id;
private String name;
private int deckLevel;
private int shipId;
private int bedCount;
- สร้าง getters and setters สำหรับ id, name, deckLevel, shipId, and bedCount.
[ ใน eclipse ง่ายมาก ไปที่ Source > Generate setters and getters ( หรือ คลิกขวาตรงที่เขียนโค้ด Source > Generate setters and getters ได้เหมือนกัน ) แล้วติ๊กเอาเลย ]
ใส่ @Entity annotation ที่ class และ @Id annotation ที่ id ( ไม่ต้องใส่ @GeneratedValue ที่นี่ )
[ มันก็จะ Error อ่ะนะ ก็คลิกขวา แล้ว ก็ import javax.persistence.Entity กับ javax.persistence.Id ซะ ( หรือ คลิกขวาที่เขียนโค้ด Source > Organize Import ก็ได้ ) ]
NOTE :
- Entity ต้องมี constructor ที่ไม่ส่ง parameter เสมอ ไม่งั้น deploy ไม่ผ่าน
- ถ้า attribute เรา ไม่ใช่ primitive type ต้องใส่ @Temporal เช่น
@Temporal(TemporalType.TIME)
private Date deliveryDate;
- ตัวอย่าง enum
public enum BidStatus {
PENDING, ACCEPTED, REJECTED
}
@Enumerated
private BidStatus status;
เวลาใช้ก็ bid.setStatus(Bid.BidStatus.ACCEPTED);
ดูเพิ่มเติมได้ที่นี่
- สร้าง persistence.xml สำหรับ data source ไว้ใน META-INF
นี่บอกว่า ให้ drop table ทุกครั้งที่ redeploy
NOTE : name="titan" นี้จะต้องไปตรงกับ @PersistenceContext(unitName="titan") ใน TravelAgentRemote.java
<persistence-unit name="titan">
<jta-data-source>jdbc/__localDS</jta-data-source>
<properties>
<!-- Remove if you want to save the DB between redeploys -->
<property name="toplink.ddl-generation" value="drop-and-create-tables"/>
</properties>
</persistence-unit>
แล้วก็บอกให้มัน "Discover annotated classes automatically" มันจะได้หา class ที่เป็นโดเมนให้อัตโนมัติ
>>>>>>>>>>>>>>>>>>> วิธีสร้าง stateless "session bean" :
[ จริงๆ สร้างเป็น new > interface มาอันนึง แล้ว new > class มาอันนึงก็ได้ ]
ถ้ากด Next > มันจะใส่ MappedName ได้
มันจะสร้าง package com.titan.travelagent
ในนั้นจะมี
- Remote interface, Java interface class ชื่อ TravelAgentRemote.java
@Remote
public interface TravelAgentRemote {
public void createCabin( Cabin cabin ); //
public Cabin findCabin( int id ); //
}
- implementation, Java class ธรรมดา ชื่อ TravelAgent.java
NOTE : ejb/TravelAgentJNDI ต้องไปตรงกับ ใน client
@Stateless( mappedName="ejb/TravelAgentJNDI" )
public class TravelAgent implements TravelAgentRemote {
@PersistenceContext(unitName="titan") //
private EntityManager manager; //
public void createCabin( Cabin cabin ) { //
manager.persist( cabin ); //
} //
public Cabin findCabin( int pKey ) { //
return manager.find( Cabin.class, pKey );//
}//
}
ปล. บรรทัดที่ comment ไว้ก็พิมพ์เพิ่มเข้าไปนะ แล้วก็ import โน่นนี่ให้ครบด้วย อย่าให้มัน error
สร้าง new project สำหรับ client ======================================
สำหรับ test new stateless session bean:
- สร้าง "Java project" ชื่อ titan-client
- เพิ่ม class Client ไว้ใน package com.titan.clients และใส่ client code ตามนี้:
public class Client {
public static void main(String[] args) {
try {
Context jndiContext = new InitialContext();
System.out.println( "Looking up ejb/TravelAgentJNDI" );
Object object = jndiContext.lookup( "ejb/TravelAgentJNDI" );
TravelAgentRemote travelAgent = (TravelAgentRemote)object;
Cabin cabin_1 = new Cabin( );
cabin_1.setId(1);
cabin_1.setName("Master Suite");
cabin_1.setDeckLevel(1);
cabin_1.setShipId(1);
cabin_1.setBedCount(3);
travelAgent.createCabin(cabin_1);
Cabin cabin_2 = travelAgent.findCabin(1);
System.out.println(cabin_2.getName( ));
System.out.println(cabin_2.getDeckLevel( ));
System.out.println(cabin_2.getShipId( ));
System.out.println(cabin_2.getBedCount( ));
} catch (javax.naming.NamingException ne){
ne.printStackTrace( );
}
}
}
ยัง error อยู่ ช่างมัน
- เพิ่ม project titan-ejb เป็น required project บน build path
มันจะทำให้ import จาก titan-ejb ได้
ทำตามนี้
Project -> properties
- เพิ่ม ~/glassfish/lib/appserv-rt.jar และ ~/glassfish/lib/javaee.jar เป็น External JARs
( บอก Java ว่าแม้รันใน standalone mode ต้องใช้ Java EE functionality (mainly JNDI)
, set up necessary deployment descriptors (mainly jndi.properties) ทำให้เราคุยกับ server JNDI ถูกตัวเพื่อ reference ไปยัง TravelAgent object )
Deployment ==================================================
คลิกขวาที่ EJB project เลือก Export > EJB JAR file
destination : [your home]/glassfish/domains/domain1/autodeploy/titan.jar และติ๊ก "overwrite existing file"
NOTE : เลือก GlassFish v2 ด้วย ( รูปผิดๆ )
Error ของ Deployment จะอยู่ที่แท็บ Glassfish Log Viewer นะ ( ไม่ใช่ Console )
ถ้าได้อะไรประมาณ " This pool is not registered with the runtime environment "
กลับไปดู persistence.xml ว่า ไอ้เนี่ย
jdbc/__localDS
<jta-data-source>jdbc/__localDS</jta-data-source>
ที่มันชี้ไปที่ derby connection pool น่ะ มันชื่อตรงกันหรือเปล่า
Client execution
คลิกขวาที่ Client class ใน Project Explorer
Run As -> Java Application
TIPS : วิธี debug JNDI
เข้าไป browse JNDI ดู โดย Application Server > JNDI Browsing
จะต้องมีอะไรทำนองนี้อยู่ ejb/TravelAgentJNDI
จัดการ database
วิธีแรก ใช้ Database Development perspective ของ Eclipse
คลิกขวา เลือก Edit ที่ table
เราสามารถ CRUD ได้
วิธีสอง command-line SQL
ใช้ ij Client ที่มากับ Derby
$ export DERBY_HOME="/home/mdailey/glassfish/javadb"
$ sh ~/glassfish/javadb/bin/ij
ij version 10.4
ij> connect 'jdbc:derby://localhost:1527/localDB';
ij> show tables;
...
APP |CABIN |
...
ij> select * from cabin;
...
Association ==================================================
จำไว้ว่า unidirectional ต้องใส่ (cascade={CascadeType.ALL}) เสมอ
ลองเพิ่ม class Phone ลงไปดิ๊
package com.titan.domain;
@Entity
public class Phone implements java.io.Serializable {
static final long serialVersionUID = 1L;
@Id @GeneratedValue
private int id;
private String number;
...
แล้วก็ Class Customer
package com.titan.domain;
@Entity
public class Customer implements java.io.Serializable {
static final long serialVersionUID = 1L;
@Id @GeneratedValue
private int id;
private String lastName;
private String firstName;
@OneToMany(cascade={CascadeType.ALL})
private Collection<Phone&ht; phoneNumbers = new ArrayList<Phone>();
นี่คือ one-to-many unidirectional relationship ( Phone class doesn't know about the Customer class )
ต่อไปให้ Add the getters and setters สำหรับ entities
แล้ว couple method ลง stateless session bean ของคุณซะ:
...
public int createCustomer();
public Collection <Phone> phoneNumbersForCust( int id );
และ implementations ใน bean class
...
public int createCustomer(Customer customer) {
manager.persist( customer );
return customer.getId();
}
public Collection<Phone> phoneNumbersForCust(int id) {
Customer customer = manager.find( Customer.class, id );
Collection<Phone> phoneList = customer.getPhoneNumbers();
// Ensure that the lazy-initialized collection is fetched
phoneList.size();
return phoneList;
}
ตอนนี้ client ของเรา, ให้สร้าง a detached Customer instance, add a Phone instance to it, make it persistent using createCustomer(), then fetch the phone numbers using phoneNumbersForCust()
ถ้ามัน error ประมาณว่า
Could not load class oracle.toplink.essentials.indirection.IndirectList
ให้ add toplink-essentials-agent.jar เข้าไปที่ client
ref : mdailey
ความคิดเห็น