专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »Java教程 » 图片存入数据库:将XML结点转换成JAVABEAN并存入数据库 »正文

图片存入数据库:将XML结点转换成JAVABEAN并存入数据库

来源: 发布时间:星期四, 2009年1月8日 浏览:6次 评论:0
  1.概述

  我们要将外部系统给XML文件进行解析并存入到数据库

  但是我们并没有DTD或者Schema只有个WORD格式介绍说明文档;更离谱XML结点树结构(即XML结点和XML结点的间关系)和业务Bean树结构(即业务Bean和业务Bean关系)并不完全比如说从业务角度讲只猪有只猪头而在XML里却写成了 pig --content --pighead 3级关系无端端多了个content结点! 没有DTD/Schema结构又不规范标准我们就没法用自动化第 3方JAVA转换API进行解析而只能手动地、个地解析但在手动解析过程中我们仍然发现各个结点解析和入库中有很多东西是共同或者有共同规律这些东西可以抽出来作为个准框架然后再将结点中区别部分开放出来允许具体结点做具体实现并最终形成个半自动解析/入库框架

  为什么说它是半自动?它有哪些限制?

  自动:不必为每个结点编写XML 解析代码和入库代码

  “半”:需手动地编写每个JAVABEAN并手动地为每个BEAN建表

  限制:

  a.所有业务字段类型只能设为STRING/VARCHAR并且非业务字段类型在BEAN中不能为STRING

  b.BEAN名和表名必须相同或者可以进行映射

  c.BEAN成员变量名必须和XML结点属性名/元素名相同或者可以进行映射

  这 3种限制都是利用JAVA反射机制进行自动操作前提

  2.基本思想

  所谓XML解析就是将XML结点转换成JAVABEAN例子XML结点ATTRIBUTE值和ELEMENT值就是JAVABEAN例子成员变量值; 所谓持久化就是将JAVABEAN例子变成数据库对应表中条记录JAVABEAN例子成员变量值就是记录中某个字段或者其他表中某个参考了该记录条记录

  而在XML中JAVABEAN体系中数据据表关系结构中结点和结点的间关系都是树形关系整体解析和入库就是在遍历树时执行转换动作而我们知道遍历是可以用递归算法实现而递归就不用说了吧它是实现“自动化”主要途径的

  以下是对各“树”具体分析:

  假设两个业务实体A和B的间存在聚合关系(父子关系)那么具体可分 3种情况:

  a.B是个原子字段(即不可再分)并且是A个属性

  XML中B是AXML ATTRIBUTE或者A原子ELEMENT

  BEAN中B是A成员变量并且B是个JAVA内置数据类型

  数据库中B是A表个列

  b.B是个复合字段并且是A个属性而且和A是1:1关系

  XML中B是AELEMENT并且B有自己ELEMENT或者ATTRIBUTE

  BEAN中B是A成员变量并且中有个B类

  数据库中B表是A表子表(即B外键参考了A表)

  c.B是个复合字段并且是A个属性而且和A是N:1关系

  XML中B是AELEMENT并且B有自己ELEMENT或者ATTRIBUTE

  BEAN中B组成个类集(List,Set)共同作为A成员变量并且中有个B类

  数据库中B表是A表子表(即B外键参考了A表)

  了解了这 3种情况接下来就好办了每抓到个结点都要递归地进行以下处理:先处理它原子属性(情形a)接着处理它单个子结点(情形b)最后处理它类集子结点( 情形c)

  3.代码实现重点

  两个重点:

  a.如何让业务实体在 3棵树内对应好?

  b.如何发现树形关系比如A属性有哪些A子结点有哪些?

  问题a很简单就是让 3棵树里相同业务实体取相同名字

  a.解析XML时发现 结点X 属性Y 等于 值Z则执行PropertyUtils.Property(结点X , 属性Y , 值Z)即可在这里XY,Z是变量不用关心具体结点和属性是哪些个需要注意如果属性Y是原子字段则要求属性Y必须为String类型否则不知道将值Z转换成哪种类型(注:有关PropertyUtils 请见apache commons Beanutils )

  b.入库时发现x.getY=z如果属性y是原子字段则执行SQL insert o X(...,y,...) values (...,z,...)这里要求y字段必须为varchar/char类型 以免发生类型转换.

  有关问题b

  XML树:JDOM, dom4j等都可以直接找到父子关系

  BEAN体系:

  I.原子属性我们限定个BEAN中所有有业务意义原子字段类型都STRING所有String类型字段都是业务字段

  II.单个子结点我们让所有有业务意义非原子字段都实现个共同接口BusiNode这样个BEAN中所有BusiNode成员都是这个BEAN子结点

  III.类集子结点我们也可以限定所有且只有类集子结点可以使用List或Set类型这样可以利用过滤出所有类集子结点然而在JAVA1.4及以前版本里并不知道过滤出类集子结点是哪个Class例子(没有泛型)也就没办法例子化个类集子结点(见后文)因此只能手动注册类集子结点属性名和ClassJAVA1.5以上版本我没用过不知道可不可以解决这个问题

  数据库表关系: 这就不用多说了就是通过外键参考因此每类结点对应表中都必须有个外键以参考它父结点;还必须有个主键以供它子结点参考各表外键名必须相同并为常数否则生成INSERT SQL时才可以不用理会具体表具体外键名

  在解析时遍历是BEAN树;在持久化时也是比起XML树BEAN树代表真正业务结构;比起数据库表关系树BEAN树才能由父至子地进行先序遍历

  4.其他问题

  a.要让知道原子属性中哪些是XML结点属性哪些是XML结点原子ELEMENT代码中这是两个抽象思路方法必须让具体结点类实现

  b.回顾本文概述部分提到“pig --content --pighead 3级关系无端端多了个content结点”因此我们要让知道pighead,pigfoot等结点子结点究竟是pig还是pig下content处理不规范标准XML时要注意这个问题这也是个抽象思路方法必须让具体结点类实现

  c.和上条类似但更变态是类集结点不规范标准问题假设个pig有多个pighead那结构可能为 pig--pighead,pighead,...也可能为pig--pigheads--content,content.... 必须让知道某个具体结点用是哪种模式

  5.代码

  核心:多态 + 递归

  a.接口BusiNode

import java.util.*;
import org.dom4j.Element;
/**
* 每个结点都要实现接口
* 它提供了些思路方法以方便实现递归XML解析和持久化
*
*/
public erface BusiNode {
  
  /**
   * 所有类型为不可分类型属性
   * @ 属性名集合
   */
  public List getAtomicPropNames;
  
  /**
   * 些成员变量这些成员变量是XML结点属性
   * @
   */
  public List getXmlAttributes;
  
  /**
   * 些成员变量这些成员变量是XML结点子元素并且类型为不可分
   * @
   */
  public List getXmlAtomicElements;
  
  
  /**
   * 所有类型为类集属性并且这些类集中每个元素类型都是BusiNode
   * @ key = 属性名, value = 属性类Class对象
   * 如果为空不返回NULL而是空MAP
   */
  public Map getCollectionPropsMap;
  
  /**
   * 所有类型为BusiNode属性
   * @ 属性名集合
   */
  public List getBusiNodePropNames;
  
  
  /**
   * 从XML中解析出来
   * @param element
   * @
   */
  public void parseFromXML(Element element);  
  }


  b.默认实现

import java.lang.reflect.Field;
import java.util.*;
import org.apache.commons.beanutils.PropertyUtils;
import org.dom4j.Attribute;
import org.dom4j.Element;
/**
* 默认BUSI NODE 继承此类BUSI NODE 需满足 所有不可分属性集=String类型属性集
* MyUtils类代码欠奉
*
*/
public abstract DefaultBusiNode implements BusiNode {
  public List getAtomicPropNames {
     MyUtils.getFieldNamesOfClass(this.getClass, String.);
  }
  public List getBusiNodePropNames {
     MyUtils.getFieldNamesOfClass(this.getClass, BusiNode.);
  }
  /*
   * 所有子元素父元素有时是本结点有时是本结点下元素变态
   */
  public abstract Element getXmlElementParent(Element rootElement);
  /*
   * 类集子结点根元素Iterator 假设个pig有多个pighead
   * 那结构可能为 pig--pighead,pighead,...
   * 也可能为pig--pigheads--content,content....
   * 必须让知道某个具体结点用是哪种模式
   *
 
   * 如果为空则返回个空类集Iterator 不要返回NULL
   */
  public abstract Iterator getCollectionElementIterator(
      Element xmlElementParent, String attName);
  /**
   * 解析XML属性
   *
   * @param rootElement
   */
  protected void parseAttributesFromXml(Element rootElement) {
    List xmlAttributes = this.getXmlAttributes;
    for ( i = 0; i < this.getXmlAttributes.size; i) {
      String attName = (String) xmlAttributes.get(i);
      Attribute att = rootElement.attribute(attName);
       (att != null) {
        try {
          PropertyUtils.Property(this, attName, att.getValue);
        } catch (Exception e) {
          throw RuntimeException(e);
        }
      }
    }
  }
  /**
   * 解析不可分Element
   *
   * @param rootElement
   */
  protected void parseAtomicElementFromXml(Element rootElement) {
    Element xmlElementParent = getXmlElementParent(rootElement);
     (xmlElementParent null) {
      ;
    }
    List xmlElements = this.getXmlAtomicElements;
    for ( i = 0; i < xmlElements.size; i) {
      String attName = (String) xmlElements.get(i);
      Element elmt = xmlElementParent.element(attName);
       (elmt != null) {
        try {
          PropertyUtils.Property(this, attName, elmt.getText);
        } catch (Exception e) {
          throw RuntimeException(e);
        }
      }
    }
  }
  /**
   * 解析BusiNode属性
   *
   * @param rootElement
   */
  protected void parseBusiNodeElementFromXml(Element rootElement) {
    Element xmlElementParent = getXmlElementParent(rootElement);
     (xmlElementParent null) {
      ;
    }
    // 再解析BusiNode属性
    List busiNodePropNames = this.getBusiNodePropNames;
    for ( i = 0; i < busiNodePropNames.size; i) {
      try {
        String attName = (String) busiNodePropNames.get(i);
        Element elmt = xmlElementParent.element(attName);
         (elmt != null) {
          Field field = this.getClass.getDeclaredField(attName);
          BusiNode att = (BusiNode) field.getType.Instance;
          att.parseFromXML(elmt);
          PropertyUtils.Property(this, attName, att);
        }
      } catch (Exception e) {
        throw RuntimeException(e);
      }
    }
  }
  /**
   * 解析类集属性
   *
   * @param rootElement
   */
  protected void parseCollectionPropsFromXml(Element rootElement) {
    // 先解析XML属性
    Element xmlElementParent = getXmlElementParent(rootElement);
     (xmlElementParent null) {
      ;
    }
    // 最后解析类集属性
    Map collectionPropsMap = this.getCollectionPropsMap;
    for (Iterator it = collectionPropsMap.keySet.iterator; it.hasNext;) {
      try {
        String attName = (String) it.next;
        Collection coll = (Collection) PropertyUtils.getProperty(this,
            attName);
        Class attType = (Class) collectionPropsMap.get(attName);
        Iterator collElementsIt = this.getCollectionElementIterator(
            xmlElementParent, attName);
        // xmlElementParent.elementIterator(attName);
        while (collElementsIt.hasNext) {
          Element collElmt = (Element) collElementsIt.next;
          BusiNode sinlgeAtt = (BusiNode) attType.Instance;
          sinlgeAtt.parseFromXML(collElmt);
          coll.add(sinlgeAtt);
        }
      } catch (Exception e) {
        throw RuntimeException(e);
      }
    }
  }
  /**
   * 从XML中解析出结点此思路方法可能抛出RumtimeException
   */
  public void parseFromXML(Element rootElement) {
    
    this.parseAttributesFromXml(rootElement);
    this.parseAtomicElementFromXml(rootElement);
    this.parseBusiNodeElementFromXml(rootElement);
    this.parseCollectionPropsFromXml(rootElement);
  }
}
/**
* 入库
* JdbcUtil,MyUtils代码欠奉
*
*/
public BusiNodeDAO {
  
  private Long saveBusiNode(BusiNode node, Long parentNodeId) {
    // 先存储原子属性
    Long id = saveBareBusiNode(node, parentNodeId);
    // 再存储类集属性
    Map collectionPropsMap = node.getCollectionPropsMap;
    for (Iterator it = collectionPropsMap.keySet.iterator; it.hasNext;) {
      String attName = (String) it.next;
      Collection coll = null;
      try {
        coll = (Collection) PropertyUtils.getProperty(node, attName);
      } catch (Exception e) {        
        throw RuntimeException("编码");
      }
      for (Iterator iitt = coll.iterator; iitt.hasNext;) {
        BusiNode subNode = (BusiNode) iitt.next;
        saveBusiNode(subNode, id);
      }
    }
    // 最后存储所有BusiNode属性
    Iterator iitt = node.getBusiNodePropNames.iterator;
    while (iitt.hasNext) {
      BusiNode subNode = null;
      try {
        subNode = (BusiNode) PropertyUtils.getProperty(node,
            (String) iitt.next);
      } catch (Exception e) {        
        throw RuntimeException("编码");
      }
       (subNode != null) {
        saveBusiNode(subNode, id);
      }
    }
     id;
  }
  /**
   * 插入某个BusiNode根结点此思路方法可能抛出RuntimeException
   *
   * @param node
   * @
   */
  private Long saveBareBusiNode(BusiNode node, Long parentNodeId) {
    StringBuffer sbForSql = StringBuffer;
    List paramValues = ArrayList;
    genInsertSqlAndParam(node, parentNodeId, node.getAtomicPropNames,
        sbForSql, paramValues);
     Long(JdbcUtil.queryForLong(
        sbForSql.toString, paramValues.toArray));
  }
  /**
   * 生成某个结点插入语句和paramValues此思路方法可能抛出RuntimeException
   *
   * @param node
   * @param columnNames
   * @param sbForSql
   * @param paramValues
   */
  private void genInsertSqlAndParam(BusiNode node, Long parentNodeId,
      List columnNames, StringBuffer sbForSql, List paramValues) {
    sbForSql.append(" insert o ");
    sbForSql.append(MyUtils.getClassBareName(node.getClass));
    List cns = ArrayList;
    cns.addAll(columnNames);
    cns.add("parentNodeId");
    sbForSql.append(MyUtils.encloseWithCurve(MyUtils
        .joinCollectionStrings(cns, ",")));
    sbForSql.append(" values ");
    List qms = ArrayList; // 问号
    for (Iterator it = columnNames.iterator; it.hasNext;) {
      qms.add("?");
      String cn = (String) it.next;
      try {
        paramValues.add(PropertyUtils.getProperty(node, cn));
      } catch (Exception e) {
        throw RuntimeException(e);
      }
    }
    qms.add("?"); // parentNodeId
    paramValues.add(parentNodeId);
    sbForSql.append(MyUtils.encloseWithCurve(MyUtil
        .joinCollectionStrings(qms, ",")));
    sbForSql.append(";select @@identity");
  }
}


0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: