用Hibernate解决Parent/Child问题
前 两周做电子商务的实习项目的时候遇到一个很棘手的问题:首页要做一个商品目录,每个商品大类下面还分几个小类。大类和小类之间的关系也就是 Parent/Child 的关系。当时也是初学 Struts ,被这个问题搅了两天也没搞定,最后用了个特别笨的方法给凑合过去了:jsp页面里调用一个 JavaBean ,这个 JavaBean 在初始化的时候从数据库中读出所有大类,并把这些大类放到一个 ArrayList 中,在jsp中用 logic:iterator 输出所有大类,logic:iterator内部先调用另一个 JavaBean 得到该大类下所有小类,然后嵌套了另一个 logic:iterator 输出小类。我不准备把代码贴出来了,实在是因为代码写的太烂了。
看了几天Hibernate的书,今天就拿这个问题开刀,算是巩固一下这几天的学习成果吧。OK,我们开始!
先建数据库和数据表:表结构如下:
name varchar(20) (类别名)
parentid int (父类的编号)
再在eclipse中新建一个名为 pc 的 web 项目(偶用的是myeclipse做 web 项目)。下面是 Hibernate 的配置方法和 Struts、JSP的代码
Hibernate配置文件:hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
" http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<!-- Generated by MyEclipse Hibernate Tools. -->
<hibernate-configuration>
<session-factory>
<property name="connection.username">study</property>
<property name="connection.url">jdbc:sqlserver://localhost:1433</property>
<property name="dialect">org.hibernate.dialect.SQLServerDialect</property>
<property name="myeclipse.connection.profile">news</property>
<property name="connection.password">study</property>
<property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="show_sql">true</property>
<mapping resource="name/yinqiang/pc/hibernate/Pc.hbm.xml" />
</session-factory>
</hibernate-configuration>
Hibernate映射文件:Pc.hbm.xml
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
" http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
<class name="name.yinqiang.pc.hibernate.Pc" table="pc" schema="dbo" catalog="news">
<id name="id" type="integer">
<column name="id" />
<generator class="native"></generator>
</id>
<property name="name" type="string">
<column name="name" length="50" not-null="true" />
</property>
<property name="parentid" type="integer">
<column name="parentid" not-null="true" />
</property>
<set
inverse="true"
lazy="true"
name="child">
<key column="parentid" />
<one-to-many class="name.yinqiang.pc.hibernate.Pc" />
</set>
</class>
</hibernate-mapping>
这里面的红字部分是配置文件的核心内容,它定义了parentid和id之间的关系
Hibernate持久化类:Pc.java
import java.util.HashSet;
import java.util.Set;
public class Pc implements java.io.Serializable {
private static final long serialVersionUID = 2764441994073705343L;
private Integer id;
private String name;
private Integer parentid;
private Set child = new HashSet(0);
// Constructors
/** default constructor */
public Pc() {
}
/** minimal constructor */
public Pc(String name, Integer parentid) {
this.name = name;
this.parentid = parentid;
}
/** full constructor */
public Pc(String name, Integer parentid, Set child) {
this.name = name;
this.parentid = parentid;
this.child = child;
}
// Property accessors
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Integer getParentid() {
return this.parentid;
}
public void setParentid(Integer parentid) {
this.parentid = parentid;
}
public Set getChild() {
return this.child;
}
public void setChild(Set child) {
this.child = child;
}
}
Hibernate的部分基本都配置完成了,下面新建一个Struts的Action:
Struts配置文件:struts-config.xml(action-mappings部分)
<action
input="/index.jsp"
path="/showtree"
type="name.yinqiang.pc.action.ShowtreeAction"
validate="false">
<forward name="success" path="/showtree.jsp" />
</action>
</action-mappings>
ShowtreeAction.java(execute方法的代码)
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
Session session = HibernateSessionFactory.currentSession();
Transaction tx = session.beginTransaction();
List list = session.createQuery("from Pc pc where pc.parentid=0").list();
tx.commit();
Iterator it = list.iterator();
while(it.hasNext()){
Pc pc = (Pc)it.next();
pc.getChild().iterator();
}
HibernateSessionFactory.closeSession();
request.setAttribute("list",list);
return mapping.findForward("success");
}
红字的部分如果不写话在打开jsp页面的时候就会出错,至于为什么要这样写、是不是应该这样写我也不太清楚(刚开始学Hibernate,还很菜,好多问题都还没弄明白)
OK,最后一步,用于显示数据的JSP文件:showtree.jsp
<c:forEach items="${list}" var="element">
<p>大类:<html:link page="/classinfo.do?id=${element.id}">${element.name}</html:link><br />
<c:forEach items="${element.child}" var="child">
小类:<html:link page="/classinfo.do?id=${child.id}">${child.name}</html:link>
</c:forEach>
</p>
</c:forEach>
</logic:present>
这里用的是JSTL标签循环遍历集合。内层的循环输出一个父类下的所有子类,外层循环输出所有的父类。
完工了,deploy一下这个项目,打开浏览器,输入地址:http://localhost:8080/pc/showtree.do 可不要直接输入jsp文件的地址哦!
HaHa,成功了!!
注:写的比较多也比较乱,其实核心内容就在于Hibernate映射文件的配置和Struts Action部分的代码。如果有朋友不明白的话欢迎和我交流。
评论
最好的做法应该是“迫切左外连接”查询了, 呵