站内搜索: 请输入搜索关键词

当前页面: 开发资料首页Eclipse 专题Eclipse快速上手EJB -- 3. 一对一的双向关系的CMR(3)

Eclipse快速上手EJB -- 3. 一对一的双向关系的CMR(3)

摘要: Eclipse快速上手EJB -- 3. 一对一的双向关系的CMR(3)
三、创建客户端

Eclipse快速上手EJB -- 3. 设计一对一的双向关系的CMR(1)

Eclipse快速上手EJB -- 3. 一对一的双向关系的CMR(2)

1. 右击 src 文件夹 ->新建 ->Lomboz EJB Test Client Wizard: 2. 修改生成的 CMPClient2.java,调用UserManagementBean中的方法。 2. 先在testBean()方法体外建立两个static方法,简化代码调用。
// 创建用户
public static void createUsers(UserManagement userMgmt)
throws RemoteException, CreateException {
System.out.println("向UserInfo表中添加数据");
userMgmt.addUser("wangyi@aaa.com", "密码1", "王一",
"Engineering", "111-1212", 22, 2000);
userMgmt.addUser("wanger@bbb.net", "密码2", "王二",
"Marketing", "222-1213",40, 4000);
userMgmt.addUser("zhangsan@bbb.ccc", "密码3", "张三",
"IT", "1688888", 32, 2800);
userMgmt.addUser("lisi@bbb.ccc", "密码4", "李四",
"Sales", "1288888", 28, 2700);
userMgmt.addUser("zhu@bbb.eee", "密码5", "朱王五",
"Sales", "1588888", 38, 4500);
userMgmt.addUser("javamxj@yahoo.com.cn", "分享Java快乐", "MXJ",
"IT", "1788888", 26, 2900);
}

// 输出ArrayList
private static void printList(ArrayList list) {
Iterator i = list.iterator();
while (i.hasNext()) {
Object details = (Object) i.next();
System.out.println(details.toString());
}
System.out.println("");
}

3. 然后,将testBean()方法体内的 myBean 改成 userMgmt,再向表中添加数据及显示数据。如下,斜体的即是改动部分。 public void testBean() {

try {
javamxj.ejb.cmp.UserManagement userMgmt = getHome().create();

createUsers(userMgmt);

System.out.println("显示所有用户");
printList(userMgmt.getUsers());
运行程序,则控制台输出如下: 4. 将“createUsers(userMgmt);”语句注释掉,调用密码验证及改变用户姓名的方法。 //createUsers(userMgmt);
System.out.println("显示所有用户");
printList(userMgmt.getUsers());


boolean login = false;
login = userMgmt.verifyPassword("javamxj@yahoo.com.cn", "分享Java快乐");
System.out.println("密码验证: " + login);

System.out.println("改变用户javamxj@yahoo.com.cn的名字");
userMgmt.changeName("javamxj@yahoo.com.cn","Hello");
运行程序,则会发现 javamxj 的姓名已被更改为 Hello: 5. 继续调用按年龄查询用户的方法: System.out.println("采用 ejb.finder 输出大于30的用户");
printList(userMgmt.getUserByAge1(30));

System.out.println("采用 ejb.select 输出年龄大于30的用户");
printList(userMgmt.getUserByAge2(30));
输出: 6.继续调用通过ValueObject输出用户的方法: System.out.println("通过 ValueObject 输出用户信息:");
UserInfoValue[] users = userMgmt.getUsersInfo();
for (int index = 0; index < users.length; index++) {
UserInfoValue user = users[index];
System.out.println("用户 " + user.getEmail() + " 的年龄:"+ user.getAge());
}
输出: 7. 继续调用通过姓名查询用户的方法: System.out.println("输出姓王的用户");
printList(userMgmt.getUsersByName("王%"));
System.out.println("输出姓名中含有王字的用户");
printList(userMgmt.getUsersByName("%王%"));
输出: 8. 删除一个用户,由于已经设置了级联删除的标记,所以虽然调用的方法是UserBean中的方法,但仍然会同时删除UserInfoBean中相关的数据。 // 删除一个用户
userMgmt.removeUser(zhu@bbb.eee);
查看数据表,会发现已经同时删除了usertable和userinfotable中关于的“zhu@bbb.eee”数据。 好了,这个算是讲完了。欲知后事如何,且听下回分解。 完整的源码

UserBean.java

/*

 * 创建日期 2005-1-14

 *

 * 作者:javamxj(分享java快乐)

 */

package javamxj.ejb.cmp;

/**

 *

 *

 <?xml version="1.0" encoding="UTF-8"?>

 

 

 

 User

 User

 javamxj.ejb.cmp.UserBean

 Container

 java.lang.String

 2.x

 userSchema

 eamil

 

 

 email

 java.lang.String

 电子邮件

 VARCHAR

 varchar

 false

 true

 

 

 password

 java.lang.String

 密码

 VARCHAR

 varchar

 false

 false

 

 userTable

 

 

 

 *

 *

 * @ejb.bean name="User"

 * jndi-name="User"

 * type="CMP"

 *  primkey-field="email"

 *  schema="userSchema"

 *  cmp-version="2.x"

 *  view-type = "local"

 *  data-source=""

 *

 *  @ejb.persistence

 *   table-name="userTable"

 *

 * @ejb.finder

 *    query="SELECT OBJECT(a) FROM userSchema as a" 

 *    signature="java.util.Collection findAll()" 

 *

 * @jboss.persistence create-table = "true"

 *                    remove-table = "false"

 *

 * @ejb.pk class="java.lang.String"

 *

 * @generated

 **/

public abstract class UserBean implements javax.ejb.EntityBean {

 /**

  * @ejb.create-method

  */

 public java.lang.String ejbCreate(String email, String password)

  throws javax.ejb.CreateException {

  // EJB 2.0 spec says return null for CMP ejbCreate methods.

  setEmail(email);

  setPassword(password);

  return null;

 }

 /**

  * The container invokes this method immediately after it calls ejbCreate.

  */

 public void ejbPostCreate(String email, String password)

  throws javax.ejb.CreateException {

 }

 /**

  * CMP Field email

  * @return the email

  * @ejb.persistent-field

  * @ejb.persistence

  *    column-name="电子邮件"

  *     jdbc-type="VARCHAR"

  *     sql-type="varchar(64)"

  *     read-only="false"

  * @ejb.pk-field

  *

  * @ejb.interface-method

  */

 public abstract java.lang.String getEmail();

 /**

  * @param java.lang.String the new email value

  * @ejb.interface-method

  */

 public abstract void setEmail(java.lang.String email);

 /**

  * CMP Field password

  * @return the password

  * @ejb.persistent-field

  * @ejb.persistence

  *    column-name="密码"

  *     jdbc-type="VARCHAR"

  *     sql-type="varchar(64)"

  *     read-only="false"

  *

  * @ejb.interface-method

  */

 public abstract java.lang.String getPassword();

 /**

  * @param java.lang.String the new password value

  * @ejb.interface-method

  */

 public abstract void setPassword(java.lang.String password);

 /**

  * Getter for CMR Relationship

  *

  * @ejb.interface-method   view-type="local"

  * @ejb.relation           name = "UserHasUserInfo"

  *                         role-name = "UserHasAUserInfo"

  *                         target-multiple = "no"

  *                         cascade-delete = "yes"

  *

  * @jboss.relation fk-column = "电子邮件"

  *                 related-pk-field = "email"

  */

 public abstract javamxj.ejb.cmp.UserInfoLocal getUserInfo();

 /**

  * Setter for CMR Relationship

  *

  * @ejb.interface-method   view-type="local"

  */

 public abstract void setUserInfo(javamxj.ejb.cmp.UserInfoLocal value);

}

UserInfoBean.java

/*

 * 创建日期 2005-1-24

 *

 * 作者:javamxj(分享java快乐)

 */

package javamxj.ejb.cmp;

import javax.ejb.FinderException;

/**

 *

 *

 <?xml version="1.0" encoding="UTF-8"?>

 

 

 

 UserInfo

 UserInfo

 javamxj.ejb.cmp.UserInfoBean

 Container

 java.lang.String

 2.x

 UserInfoSchema

 email

 

 

 email

 java.lang.String

 电子邮件

 VARCHAR

 varchar

 false

 true

 

 

 name

 java.lang.String

 姓名

 VARCHAR

 varchar

 false

 false

 

 

 dept

 java.lang.String

 组别

 VARCHAR

 varchar

 false

 false

 

 

 workPhone

 java.lang.String

 工作电话

 VARCHAR

 varchar

 false

 false

 

 

 age

 java.lang.Integer

 年龄

 VARCHAR

 Integer

 false

 false

 

 

 salary

 java.lang.Integer

 薪水

 VARCHAR

 Integer

 false

 false

 

 UserInfoTable

 

 

 

 *

 *

 * @ejb.bean name="UserInfo"

 * jndi-name="UserInfo"

 * type="CMP"

 *  primkey-field="email"

 *  schema="UserInfoSchema"

 *  cmp-version="2.x"

 *  view-type = "local"

 *  data-source=""

 *

 *  @ejb.persistence

 *    table-name="UserInfoTable"

 *

 * @ejb.value-object

 *

 * @ejb.finder

 *    query="SELECT OBJECT(a) FROM UserInfoSchema as a" 

 *    signature="java.util.Collection findAll()" 

 *

 * @ejb.finder

 *    query = "SELECT OBJECT(a) FROM UserInfoSchema as a WHERE a.age >?1"

 *    signature = "java.util.Collection findUserByAge(int age )"

 *

 * @ejb.finder

 *    query = "SELECT OBJECT(g) FROM UserInfoSchema AS g WHERE g.name LIKE ?1"

 *    signature = "java.util.Collection findUserByName(java.lang.String name)"

 *

 * @jboss.persistence

 *    create-table = "true"

 *    remove-table = "false"

 *

 *

 * @ejb.pk class="java.lang.String"

 *

 * @generated

 **/

public abstract class UserInfoBean implements javax.ejb.EntityBean {

 /**

  * @ejb.create-method

  */

 public java.lang.String ejbCreate(

  String email,

  String name,

  String dept,

  String workPhone,

  Integer age,

  Integer salary) throws javax.ejb.CreateException {

  // EJB 2.0 spec says return null for CMP ejbCreate methods.

  setEmail(email);

  setName(name);

  setDept(dept);

  setWorkPhone(workPhone);

  setAge(age);

  setSalary(salary);

  return null;

 }

 /**

  * The container invokes this method immediately after it calls ejbCreate.

  */

 public void ejbPostCreate(

  String name,

  String email,

  String dept,

  String workPhone,

  Integer age,

  Integer salary) throws javax.ejb.CreateException {

 }

 /**

  * CMP Field email

  * @return the email

  * @ejb.persistent-field

  * @ejb.persistence

  *    column-name="电子邮件"

  *     jdbc-type="VARCHAR"

  *     sql-type="varchar(32)"

  *     read-only="false"

  * @ejb.pk-field

  *

  * @ejb.interface-method

  */

 public abstract java.lang.String getEmail();

 /**

  * @param java.lang.String the new email value

  * @ejb.interface-method

  */

 public abstract void setEmail(java.lang.String email);

 /**

  * CMP Field name

  * @return the name

  * @ejb.persistent-field

  * @ejb.persistence

  *    column-name="姓名"

  *     jdbc-type="VARCHAR"

  *     sql-type="varchar(16)"

  *     read-only="false"

  * 

  *

  * @ejb.interface-method

  */

 public abstract java.lang.String getName();

 /**

  * @param java.lang.String the new name value

  * @ejb.interface-method

  */

 public abstract void setName(java.lang.String name);

 /**

  * CMP Field dept

  * @return the dept

  * @ejb.persistent-field

  * @ejb.persistence

  *    column-name="组别"

  *     jdbc-type="VARCHAR"

  *     sql-type="varchar(24)"

  *     read-only="false"

  * 

  *

  * @ejb.interface-method

  */

 public abstract java.lang.String getDept();

 /**

  * @param java.lang.String the new dept value

  * @ejb.interface-method

  */

 public abstract void setDept(java.lang.String dept);

 /**

  * CMP Field workPhone

  * @return the workPhone

  * @ejb.persistent-field

  * @ejb.persistence

  *    column-name="工作电话"

  *     jdbc-type="VARCHAR"

  *     sql-type="varchar(12)"

  *     read-only="false"

  * 

  *

  * @ejb.interface-method

  */

 public abstract java.lang.String getWorkPhone();

 /**

  * @param java.lang.String the new workPhone value

  * @ejb.interface-method

  */

 public abstract void setWorkPhone(java.lang.String workPhone);

 /**

  * CMP Field age

  * @return the age

  * @ejb.persistent-field

  * @ejb.persistence

  *    column-name="年龄"

  *     jdbc-type="VARCHAR"

  *     sql-type="Integer"

  *     read-only="false"

  * 

  *

  * @ejb.interface-method

  */

 public abstract java.lang.Integer getAge();

 /**

  * @param java.lang.Integer the new age value

  * @ejb.interface-method

  */

 public abstract void setAge(java.lang.Integer age);

 /**

  * CMP Field salary

  * @return the salary

  * @ejb.persistent-field

  * @ejb.persistence

  *    column-name="薪水"

  *     jdbc-type="VARCHAR"

  *     sql-type="Integer"

  *     read-only="false"

  * 

  *

  * @ejb.interface-method

  */

 public abstract java.lang.Integer getSalary();

 /**

  * @param java.lang.Integer the new salary value

  * @ejb.interface-method

  */

 public abstract void setSalary(java.lang.Integer salary);

 /**

  * @ejb.interface-method

  */

 public abstract UserInfoValue getUserInfoValue();

//###################   Select Method  ###################

 /**

  * Select method

  * @ejb.select  query = "select g.email From UserInfoSchema AS g WHERE g.age >?1"

  */

 public abstract java.util.Collection ejbSelectUserByAge(int i)

  throws javax.ejb.FinderException;

 /**

  * Home method

  * @throws FinderException

  * @ejb.home-method  view-type = "local"

  */

 public java.util.Collection ejbHomeQueryUserByAge(int age)

  throws FinderException {

  return ejbSelectUserByAge(age);

 }

// ###################   CMR Relationship  ################### 

 /**

  * Getter for CMR Relationship

  *

  * @ejb.interface-method view-type="local"

  * @ejb.relation

  *     name = "UserHasUserInfo"

  *     role-name = "UserInfoPartOfUser"

  *     target-multiple = "no"

  *     cascade-delete = "yes"

  */

 public abstract javamxj.ejb.cmp.UserLocal getUser();

 /**

  * Setter for CMR Relationship

  *

  * @ejb.interface-method view-type="local"

  */

 public abstract void setUser(javamxj.ejb.cmp.UserLocal value);

}

UserManagementBean.java

/*

 * 创建日期 2005-1-14

 *

 * 作者:javamxj(分享java快乐)

 */

package javamxj.ejb.cmp;

import java.util.ArrayList;

import java.util.Collection;

import java.util.Iterator;

import javax.ejb.CreateException;

import javax.ejb.FinderException;

/**

 *

 *

 <?xml version="1.0" encoding="UTF-8"?>

 

 

 

 UserManagement

 UserManagement

 javamxj.ejb.cmp.UserManagementBean

 Stateless

 Container

 

 

 

 *

 *

 * @ejb.bean name="UserManagement"

 *           jndi-name="UserManagement"

 *           type="Stateless"

 *           transaction-type="Container"

 *           view-type = "remote"

 *

 * @ejb.ejb-ref

 *    ejb-name = "User"

 *    view-type = "local"

 *    ref-name = "ejb/UserLocal"

 *

 * @jboss.ejb-local-ref

 *     ref-name = "UserLocal" 

 *     jndi-name = "UserLocal"

 *

 *

 * @generated

 */

public abstract class UserManagementBean implements javax.ejb.SessionBean {

 private UserLocalHome userHome = null;

 private UserInfoLocalHome infoHome = null;

 /**

  * Create method

  * @ejb.create-method  view-type = "remote"

  */

 public void ejbCreate() throws javax.ejb.CreateException, javax.naming.NamingException {

  userHome = UserUtil.getLocalHome();

  infoHome = UserInfoUtil.getLocalHome();

 }

 public void ejbPassivate() {

  userHome = null;

  infoHome = null;

 }

 /**

  * Business method

  * @ejb.interface-method  view-type = "remote"

  */

 public void addUser(String email, String password)

  throws javax.ejb.CreateException {

  UserLocal user = userHome.create(email, password);

 }

 /**

  * Business method

  * @ejb.interface-method  view-type = "remote"

  */

 public void removeUser(String email) throws javax.ejb.RemoveException {

  userHome.remove(email);

 }

 /**

  * Business method

  * @ejb.interface-method  view-type = "remote"

  */

 public boolean verifyPassword(String email, String password)

  throws javax.ejb.FinderException {

  UserLocal user = userHome.findByPrimaryKey(email);

  return user.getPassword().equals(password);

 }

 //**********************************************************************

 //                     一对一的双向关系

 //**********************************************************************

 /**

  * 创建用户,这次同时创建 User 和 UserInfo

  * @throws CreateException

  * @ejb.interface-method view-type="remote"

  */

 public void addUser(

  String email,

  String password,

  String name,

  String dept,

  String workPhone,

  int age,

  int salary) throws CreateException {

  UserLocal user = userHome.create(email, password);

  UserInfoLocal info = infoHome.create(email, name,dept,workPhone,

               new Integer(age),new Integer(salary));

  user.setUserInfo(info);

 }

 /**

  * 显示所有用户

  * @throws FinderException

  * @ejb.interface-method view-type="remote"

  */

 public ArrayList getUsers() throws FinderException {

  ArrayList userList = new ArrayList(50);

  Collection collection = userHome.findAll();

  Iterator iterator = collection.iterator();

  while (iterator.hasNext()) {

   UserLocal user = (UserLocal) iterator.next();

   userList.add(user.getEmail());

  }

  return userList;

 }

 /**

  * 改变用户姓名

  * Business method

  * @ejb.interface-method view-type = "remote"

  */

 public void changeName(String email, String name)

  throws javax.ejb.FinderException {

  UserLocal user = userHome.findByPrimaryKey(email);

  UserInfoLocal info = user.getUserInfo();

  info.setName(name);

 }

 /**

  * 利用ejb.finder 通过年龄来查询用户

  * Business method

  * @ejb.interface-method view-type = "remote"

  */

 public ArrayList getUserByAge1(int age) throws FinderException {

  ArrayList age1 = new ArrayList(30);

  Iterator iter = infoHome.findUserByAge(age).iterator();

  while (iter.hasNext()) {

   UserInfoLocal element = (UserInfoLocal) iter.next();

   age1.add(element.getEmail());

  }

  return age1;

 }

 /**

  * 利用ejb.select 通过年龄来查询用户

  * Business method

  * @ejb.interface-method view-type = "remote"

  */

 public ArrayList getUserByAge2(int age) throws FinderException {

  ArrayList age2 = new ArrayList(30);

  Iterator iter = infoHome.queryUserByAge(age).iterator();

  while (iter.hasNext()) {

   String element = (String) iter.next();

   age2.add(element);

  }

  return age2;

 }

 /**

  * 利用ejb.value-object 得到用户

  * Business method

  * @throws FinderException

  * @ejb.interface-method view-type = "remote"

  */

 public javamxj.ejb.cmp.UserInfoValue[] getUsersInfo()

  throws FinderException {

  ArrayList userList = new ArrayList(50);

  Iterator iter = userHome.findAll().iterator();

  while (iter.hasNext()) {

   UserLocal user = (UserLocal) iter.next();

   UserInfoLocal info = user.getUserInfo();

   UserInfoValue userInfoValue = info.getUserInfoValue();

   userList.add(userInfoValue);

  }

  return (UserInfoValue[]) userList.toArray(new UserInfoValue[userList

   .size()]);

 }

 /**

  * 利用ejb.finder 通过姓名来查询用户

  * Business method

  * @throws FinderException

  * @ejb.interface-method view-type = "remote"

  */

 public ArrayList getUsersByName(String name) throws FinderException{

  ArrayList nameList = new ArrayList(30); 

  Iterator iter = infoHome.findUserByName(name).iterator();

  while (iter.hasNext()) {

   UserInfoLocal element = (UserInfoLocal) iter.next();

   nameList.add(element.getEmail());

  }

  return nameList;

 }

}

CMPClient2.java

/*

 * 创建日期 2005-1-24

 *

 * 作者:javamxj(分享java快乐)

 */

package javamxj.ejb.client;

import java.rmi.RemoteException;

import java.util.ArrayList;

import java.util.Hashtable;

import java.util.Iterator;

import javamxj.ejb.cmp.UserInfoValue;

import javamxj.ejb.cmp.UserManagement;

import javax.ejb.CreateException;

import javax.ejb.FinderException;

import javax.ejb.RemoveException;

import javax.naming.InitialContext;

import javax.naming.NamingException;

/**

 * @author pc

 *

 * TODO 要更改此生成的类型注释的模板,请转至

 * 窗口 - 首选项 - Java - 代码样式 - 代码模板

 */

public class CMPClient2 {

 private javamxj.ejb.cmp.UserManagementHome getHome() throws NamingException {

  return (javamxj.ejb.cmp.UserManagementHome) getContext().lookup(

    javamxj.ejb.cmp.UserManagementHome.JNDI_NAME);

 }

 private InitialContext getContext() throws NamingException {

  Hashtable props = new Hashtable();

  props.put(InitialContext.INITIAL_CONTEXT_FACTORY,

    "org.jnp.interfaces.NamingContextFactory");

  props.put(InitialContext.PROVIDER_URL, "jnp://127.0.0.1:1099");

  // This establishes the security for authorization/authentication

  // props.put(InitialContext.SECURITY_PRINCIPAL,"username");

  // props.put(InitialContext.SECURITY_CREDENTIALS,"password");

  InitialContext initialContext = new InitialContext(props);

  return initialContext;

 }

 public void testBean() {

  try {

   javamxj.ejb.cmp.UserManagement userMgmt = getHome().create();

  

   //createUsers(userMgmt);

  

   System.out.println("显示所有用户");

   printList(userMgmt.getUsers());

  

   boolean login = false;

   login = userMgmt.verifyPassword("javamxj@yahoo.com.cn", "分享Java快乐");

   System.out.println("密码验证: " + login);  

   System.out.println("改变用户javamxj@yahoo.com.cn的名字");

   userMgmt.changeName("javamxj@yahoo.com.cn","Hello");

   System.out.println("采用 ejb.finder 输出大于30的用户");

   printList(userMgmt.getUserByAge1(30));

   System.out.println("采用 ejb.select 输出年龄大于30的用户");

   printList(userMgmt.getUserByAge2(30));  

   System.out.println("通过 ValueObject 输出用户信息:");

   UserInfoValue[] users = userMgmt.getUsersInfo();

   for (int index = 0; index < users.length; index++) {

    UserInfoValue user = users[index];

    System.out.println("用户 " + user.getEmail() + " 的年龄:"+ user.getAge());

   }

  

   System.out.println("输出姓王的用户");

   printList(userMgmt.getUsersByName("王%"));

   System.out.println("输出姓名中含有王字的用户");

   printList(userMgmt.getUsersByName("%王%"));

   //  删除一个用户

   userMgmt.removeUser("zhu@bbb.eee");

  } catch (RemoteException e) {

   e.printStackTrace();

  } catch (CreateException e) {

   e.printStackTrace();

  } catch (NamingException e) {

   e.printStackTrace();

  } catch (FinderException e) {

   e.printStackTrace();

  } catch (RemoveException e) {

   e.printStackTrace();

  }

 }

    // 创建用户

 public static void createUsers(UserManagement userMgmt)

   throws RemoteException, CreateException {

  System.out.println("向UserInfo表中添加数据");

  userMgmt.addUser("wangyi@aaa.com", "密码1", "王一",

    "Engineering", "111-1212", 22, 2000);

  userMgmt.addUser("wanger@bbb.net", "密码2", "王二",

    "Marketing", "222-1213",40, 4000);

  userMgmt.addUser("zhangsan@bbb.ccc", "密码3", "张三",

    "IT", "1688888", 32, 2800);

  userMgmt.addUser("lisi@bbb.ccc", "密码4", "李四",

    "Sales", "1288888", 28, 2700);

  userMgmt.addUser("zhu@bbb.eee", "密码5", "朱王五",

    "Sales", "1588888", 38, 4500);

  userMgmt.addUser("javamxj@yahoo.com.cn", "分享Java快乐", "MXJ",

    "IT", "1788888", 26, 2900);

 }

 //  输出ArrayList

 private static void printList(ArrayList list) {

  Iterator i = list.iterator();

  while (i.hasNext()) {

   Object details = (Object) i.next();

   System.out.println(details.toString());

  }

  System.out.println("");

 }

 public static void main(String[] args) {

  CMPClient2 test = new CMPClient2();

  test.testBean();

 }

}



↑返回目录
前一篇: Eclipse快速上手EJB -- 3. 设计一对一的双向关系的CMR(1)
后一篇: 在Eclipse插件开发中使用URLClassLoader加载JavaProject中的类