当自己的系统需要向别的数据平台系统上传数据时,可能规则是由数据平台定的。
下面就是一个WEB Service业务接口的典型定义。
班级信息上传接口
标识名 | 名称 | 类型 | 长度 | 是否必填 | 说明 |
CLASS_INFO | |||||
CODE | 班级编码 | String | 20 | 是 | 班级编码 |
NAME | 班级名称 | String | 20 | 是 | 班级名称 |
GRADE | 年级信息 | String | 20 | 是 | 1、2、3 |
COUNT | 班级人数 | Number | 8 | 是 | 班级人数 |
CONTENT | 简要介绍 | String | 120 | 否 | 班级简要介绍 |
STUDENT_INFO | |||||
CODE | 学号 | String | 20 | 是 | 学生编码 |
NAME | 姓名 | String | 20 | 是 | 学生姓名 |
SEX | 性别 | String | 1 | 否 | 1:男 0:女 |
BIRTHDAY | 生日 | String | 20 | 否 | yyyy-mm-dd |
示例XML
自己系统的业务表设计(关系型数据库):
年级信息
年级ID | varchar(20) | 主键 |
年级编码 | varchar(20) | 必填 |
年级名称 | varchar(20) | 必填 |
年级描述 | varchar(120) |
班级信息
班级ID | varchar(20) | 主键 |
班级编码 | varchar(20) | 必填 |
班级名称 | varchar(20) | 必填 |
班级描述 | varchar(120) | |
年级ID | varchar(20) | 外键 |
学生信息
学生ID | varchar(20) | 主键 |
学生编码 | varchar(20) | 必填 |
学生名称 | varchar(20) | 必填 |
学生描述 | varchar(120) | |
年级ID | varchar(20) | 外键 |
班级ID | varchar(20) | 外键 |
自己系统业务对象建模
年级
package com.zas.data.xml; /** * 年级信息 * @author zas * */ public class Grade { //年级ID String gradeID; //年级编码 String gradeCode; //年级名称 String gradeName; //年级描述 String gradeDes; public Grade() { super(); } public Grade(String gradeID, String gradeCode, String gradeName, String gradeDes) { super(); this.gradeID = gradeID; this.gradeCode = gradeCode; this.gradeName = gradeName; this.gradeDes = gradeDes; } public String getGradeID() { return gradeID; } public void setGradeID(String gradeID) { this.gradeID = gradeID; } public String getGradeName() { return gradeName; } public void setGradeName(String gradeName) { this.gradeName = gradeName; } public String getGradeDes() { return gradeDes; } public void setGradeDes(String gradeDes) { this.gradeDes = gradeDes; } public String getGradeCode() { return gradeCode; } public void setGradeCode(String gradeCode) { this.gradeCode = gradeCode; } @Override public String toString() { return "Grade [gradeID=" + gradeID + ", gradeCode=" + gradeCode + ", gradeName=" + gradeName + ", gradeDes=" + gradeDes + "]"; } /** * @param args */ public static void main(String[] args) { } }
班级
package com.zas.data.xml; /** * 班级信息 * @author zas * */ public class ClassInformation{ //班级ID String classID; //班级编号 String classCode; //班级名称 String className; //年级ID String gradeID; //班级描述 String classDes; public ClassInformation() { super(); } public ClassInformation(String classID, String classCode, String className, String gradeID, String classDes) { super(); this.classID = classID; this.classCode = classCode; this.className = className; this.gradeID = gradeID; this.classDes = classDes; } public String getClassID() { return classID; } public void setClassID(String classID) { this.classID = classID; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public String getGradeID() { return gradeID; } public void setGradeID(String gradeID) { this.gradeID = gradeID; } public String getClassDes() { return classDes; } public void setClassDes(String classDes) { this.classDes = classDes; } public String getClassCode() { return classCode; } public void setClassCode(String classCode) { this.classCode = classCode; } @Override public String toString() { return "ClassInformation [classID=" + classID + ", classCode=" + classCode + ", className=" + className + ", gradeID=" + gradeID + ", classDes=" + classDes + "]"; } }
学生
package com.zas.data.xml; import java.util.Date; /** * 学生数据对象 * @author zas * */ public class Student { //学生ID String id; //学号 String code; //年级 String gradeid; //班级 String classid; //姓名 String name; //性别 String sexCode; //生日 Date birthDay; public Student() { super(); } public Student(String id, String code, String gradeid, String classid, String name, String sexCode, Date birthDay) { super(); this.id = id; this.code = code; this.gradeid = gradeid; this.classid = classid; this.name = name; this.sexCode = sexCode; this.birthDay = birthDay; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getGradeid() { return gradeid; } public void setGradeid(String gradeid) { this.gradeid = gradeid; } public String getClassid() { return classid; } public void setClassid(String classid) { this.classid = classid; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSexCode() { return sexCode; } public void setSexCode(String sexCode) { this.sexCode = sexCode; } public Date getBirthDay() { return birthDay; } public void setBirthDay(Date birthDay) { this.birthDay = birthDay; } @Override public String toString() { return "Student [id=" + id + ", code=" + code + ", gradeid=" + gradeid + ", classid=" + classid + ", name=" + name + ", sexCode=" + sexCode + ", birthDay=" + birthDay + "]"; } /** * @param args */ public static void main(String[] args) { } }
在这篇文章中不做系统业务扩展,只讨论按照班级上传学生信息这一个业务逻辑。但是可以预测到当涉及课程,普通课程,公选课,教师,绩点,教室,校区,学费,健康状况等的业务信息上传时可以扩展出很多个上传交易。
如果针对每一个上传接口,都要结合自己系统的业务对象模型抓取数据,那就太费劲了。比如一个接口涉及学校,年级,班级,教室,教师,课程六个业务对象模型,可以想象这个接口的XML生成工作量不会小。
把数据抓取的工作放到关系数据库通过SQL语句来抓取来做是非常有吸引力。这样所有的复杂业务数据抓取逻辑都放到了SQL语句中,维护起来也会方便许多。
下面就介绍一种在Java世界里通过SQL抓取上传接口业务数据,再自动生成XML的一个程序设计。
程序设计的目标就是,当来了一个新接口时,只要添加一个接口业务数据模型类,一段SQL语句就可以搞定。这是典型的针对扩展开放的设计。
针对关系型数据库的阻抗失衡问题,JAVA世界有许多解决方案。但是我接触过的对SQL支持最融洽的当属myBatis。这里就采用MyBatis了。对于如何应用myBatis这篇文章就不介绍了,这不是文章的重点。
为了能够自动生成XML,程序需要添加一个接口,一个元数据描述类:
接口定义:
package com.zas.data.xml; import java.util.List; import java.util.Map; /** * xml结构图 * @author zas * */ public interface DataMapForXml { /** * 参数元数据map * 主要存储当前层信息 * @return */ Map<String, List<ParameterMetaData>> getParameterMap(); /** * 当有一对多关系时填入其中 * @return */ Map<String, List<DataMapForXml>> getOneToManyList(); }
这个接口时为了描述列表类型的数据,如:对于一个班级,学生信息就是一个列表。
元数据描述类
package com.zas.data.xml; /** * 元数据类 * @author zas * */ public class ParameterMetaData { //标识 String parameterIdentifier = null; //名称 String parameterName = null; //Java类型 String parameterType = null; //值 Object parameterValue = null; //描述 String parameterDescription = null; //前缀 String elementPrefix = null; //类型 String parameterClientType = null; //是否必填 Boolean isRequired = false; //规格 String parameterSpecification = null; public ParameterMetaData(String parameterIdentifier, String parameterName, String parameterType, Object parameterValue, String parameterDescription, String elementPrefix, String parameterPhilipsType, Boolean isRequired, String parameterSpecification) { super(); this.parameterIdentifier = parameterIdentifier; this.parameterName = parameterName; this.parameterType = parameterType; this.parameterValue = parameterValue; this.parameterDescription = parameterDescription; this.elementPrefix = elementPrefix; this.parameterClientType = parameterPhilipsType; this.isRequired = isRequired; this.parameterSpecification = parameterSpecification; } public String getParameterName() { return parameterName; } public void setParameterName(String parameterName) { this.parameterName = parameterName; } public String getParameterType() { return parameterType; } public void setParameterType(String parameterType) { this.parameterType = parameterType; } public Object getParameterValue() { return parameterValue; } public void setParameterValue(Object parameterValue) { this.parameterValue = parameterValue; } public String getParameterDescription() { return parameterDescription; } public void setParameterDescription(String parameterDescription) { this.parameterDescription = parameterDescription; } public String getElementPrefix() { return elementPrefix; } public void setElementPrefix(String elementPrefix) { this.elementPrefix = elementPrefix; } public String getParameterClientType() { return parameterClientType; } public void setParameterClientType(String parameterClientType) { this.parameterClientType = parameterClientType; } public String getParameterSpecification() { return parameterSpecification; } public void setParameterSpecification(String parameterSpecification) { this.parameterSpecification = parameterSpecification; } public String getParameterIdentifier() { return parameterIdentifier; } public void setParameterIdentifier(String parameterIdentifier) { this.parameterIdentifier = parameterIdentifier; } public Boolean getIsRequired() { return isRequired; } public void setIsRequired(Boolean isRequired) { this.isRequired = isRequired; } }
元数据是用来生成XML文件的。
对于文章开头的那个上传接口的数据模型做出如下的设计:
package com.zas.data.xml; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * 班级信息上传 * @author zas * */ public class CLASS_INFO implements DataMapForXml { /** 标识名 名称 类型 长度 是否必填 说明 CLASS_INFO CODE 班级编码 String 20 是 班级编码 NAME 班级名称 String 20 是 班级名称 GRADE 年级信息 String 20 是 1、2、3 COUNT 班级人数 Number 8 是 班级人数 CONTENT 简要介绍 String 120 否 班级简要介绍 STUDENT_INFO CODE 学号 String 20 是 学生编码 NAME 姓名 String 20 是 学生姓名 SEX 性别 String 1 否 1:男 0:女 BIRTHDAY 生日 String 20 否 yyyy-mm-dd */ //班级编码 String CLASS_INFO_CODE; //班级名称 String CLASS_INFO_NAME; //年级信息 String CLASS_INFO_GRADE; //班级人数 Integer CLASS_INFO_COUNT; //班级介绍 String CLASS_INFO_CONTENT; List<DataMapForXml> studentList; @Override public Map<String, List<ParameterMetaData>> getParameterMap() { //先后顺序很重要 Map<String, List<ParameterMetaData>> elementMap = new LinkedHashMap<String, List<ParameterMetaData>>(); List<ParameterMetaData> listCLASS_INFO = new ArrayList<ParameterMetaData>(); listCLASS_INFO.add(new ParameterMetaData("CODE","班级编码", "String", this.CLASS_INFO_CODE, "班级编码", "CLASS_INFO", "String", true, "")); listCLASS_INFO.add(new ParameterMetaData("NAME","班级名称", "String", this.CLASS_INFO_NAME, "班级名称", "CLASS_INFO", "String", true, "")); listCLASS_INFO.add(new ParameterMetaData("GRADE","年级信息", "String", this.CLASS_INFO_GRADE, "年级信息", "CLASS_INFO", "String", true, "")); listCLASS_INFO.add(new ParameterMetaData("COUNT","班级人数", "Integer", this.CLASS_INFO_COUNT, "班级人数", "CLASS_INFO", "Number", true, "")); listCLASS_INFO.add(new ParameterMetaData("CONTENT","班级介绍", "String", this.CLASS_INFO_CONTENT, "班级介绍", "CLASS_INFO", "String", false, "")); elementMap.put("CLASS_INFO", listCLASS_INFO); return elementMap; } @Override public Map<String, List<DataMapForXml>> getOneToManyList() { //先后顺序很重要 Map<String, List<DataMapForXml>> elementMap = new LinkedHashMap<String, List<DataMapForXml>>(); elementMap.put("STUDENT_INFOS", studentList); return elementMap; } public String getCLASS_INFO_CODE() { return CLASS_INFO_CODE; } public void setCLASS_INFO_CODE(String cLASS_INFO_CODE) { CLASS_INFO_CODE = cLASS_INFO_CODE; } public String getCLASS_INFO_NAME() { return CLASS_INFO_NAME; } public void setCLASS_INFO_NAME(String cLASS_INFO_NAME) { CLASS_INFO_NAME = cLASS_INFO_NAME; } public String getCLASS_INFO_GRADE() { return CLASS_INFO_GRADE; } public void setCLASS_INFO_GRADE(String cLASS_INFO_GRADE) { CLASS_INFO_GRADE = cLASS_INFO_GRADE; } public Integer getCLASS_INFO_COUNT() { return CLASS_INFO_COUNT; } public void setCLASS_INFO_COUNT(Integer cLASS_INFO_COUNT) { CLASS_INFO_COUNT = cLASS_INFO_COUNT; } public String getCLASS_INFO_CONTENT() { return CLASS_INFO_CONTENT; } public void setCLASS_INFO_CONTENT(String cLASS_INFO_CONTENT) { CLASS_INFO_CONTENT = cLASS_INFO_CONTENT; } public List<DataMapForXml> getStudentList() { return studentList; } public void setStudentList(List<DataMapForXml> studentList) { this.studentList = studentList; } static class STUDENT_INFO implements DataMapForXml { //学号 String STUDENT_INFO_CODE; //姓名 String STUDENT_INFO_NAME; //性别 String STUDENT_INFO_SEX; //生日 String STUDENT_INFO_BIRTHDAY; @Override public Map<String, List<ParameterMetaData>> getParameterMap() { Map<String, List<ParameterMetaData>> elementMap = new LinkedHashMap<String, List<ParameterMetaData>>(); List<ParameterMetaData> listSTUDENT_INFO = new ArrayList<ParameterMetaData>(); listSTUDENT_INFO.add(new ParameterMetaData("CODE","学号", "String", this.STUDENT_INFO_CODE, "", "STUDENT_INFO", "String", true, "")); listSTUDENT_INFO.add(new ParameterMetaData("NAME","姓名", "String", this.STUDENT_INFO_NAME, "", "STUDENT_INFO", "String", true, "")); listSTUDENT_INFO.add(new ParameterMetaData("SEX","性别", "String", this.STUDENT_INFO_SEX, "", "STUDENT_INFO", "String", false, "")); listSTUDENT_INFO.add(new ParameterMetaData("BIRTHDAY","生日", "Integer", this.STUDENT_INFO_BIRTHDAY, "", "STUDENT_INFO", "String", false, "")); elementMap.put("STUDENT_INFO", listSTUDENT_INFO); return elementMap; } @Override public Map<String, List<DataMapForXml>> getOneToManyList() { return null; } public String getSTUDENT_INFO_CODE() { return STUDENT_INFO_CODE; } public void setSTUDENT_INFO_CODE(String sTUDENT_INFO_CODE) { STUDENT_INFO_CODE = sTUDENT_INFO_CODE; } public String getSTUDENT_INFO_NAME() { return STUDENT_INFO_NAME; } public void setSTUDENT_INFO_NAME(String sTUDENT_INFO_NAME) { STUDENT_INFO_NAME = sTUDENT_INFO_NAME; } public String getSTUDENT_INFO_SEX() { return STUDENT_INFO_SEX; } public void setSTUDENT_INFO_SEX(String sTUDENT_INFO_SEX) { STUDENT_INFO_SEX = sTUDENT_INFO_SEX; } public String getSTUDENT_INFO_BIRTHDAY() { return STUDENT_INFO_BIRTHDAY; } public void setSTUDENT_INFO_BIRTHDAY(String sTUDENT_INFO_BIRTHDAY) { STUDENT_INFO_BIRTHDAY = sTUDENT_INFO_BIRTHDAY; } } }
用来自动生成XML的程序
package com.zas.data.xml; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.io.XMLWriter; public class BuildXML { /** * 根据数据xml结构图生成xml文件 * @param elementList * @param rootName 暂定为交易号的根名称 * @return */ public static String buildXML(List<DataMapForXml> elementList, String rootName) { Document document = DocumentHelper.createDocument(); Element root = document.addElement(rootName); createRootElement(elementList, root); try { XMLWriter output = new XMLWriter(new FileWriter(new File("F:/catalog/catalog.xml"))); output.write(document); output.close(); } catch (IOException e) { System.out.println(e.getMessage()); } return "F:/catalog/catalog.xml"; } /** * 创建xml文件内容 * @param elementList * @param e */ private static void createRootElement(List<DataMapForXml> elementList, Element e) { if(null == elementList || elementList.size() < 1){ return; } for (DataMapForXml dataMapForXml : elementList) { //首先处理当前层信息 Map<String, List<ParameterMetaData>> elementMap = dataMapForXml.getParameterMap(); if(null != elementMap && elementMap.size() > 0){ for (String str : elementMap.keySet()) { Element element = e.addElement(str); for (ParameterMetaData pmd : elementMap.get(str)) { if(pmd.getParameterValue() != null){ Element elementInner = element.addElement(pmd.getParameterIdentifier()); elementInner.setText(pmd.getParameterValue().toString()); } } } } //再处理一对多信息 Map<String, List<DataMapForXml>> mapList = dataMapForXml.getOneToManyList(); if(null != mapList && mapList.size() > 0){ for (String str : mapList.keySet()) { Element element = e.addElement(str); //递归处理一对多关系所有的内容 createRootElement(mapList.get(str), element); } } } } /** * @param args */ public static void main(String[] args) { List<DataMapForXml> elementList = new ArrayList<DataMapForXml>(); CLASS_INFO classInfo = new CLASS_INFO(); classInfo.setCLASS_INFO_CODE("10001"); classInfo.setCLASS_INFO_NAME("一班"); classInfo.setCLASS_INFO_GRADE("一年级"); classInfo.setCLASS_INFO_CONTENT("一年级一班"); classInfo.setCLASS_INFO_COUNT(8); List<DataMapForXml> list = new ArrayList<DataMapForXml>(); for (int i = 0; i < 8; i++) { CLASS_INFO.STUDENT_INFO student = new CLASS_INFO.STUDENT_INFO(); student.setSTUDENT_INFO_CODE("10001_"+i); student.setSTUDENT_INFO_NAME("学生_" + i); if(i % 2 == 0){ student.setSTUDENT_INFO_SEX("男"); }else{ student.setSTUDENT_INFO_BIRTHDAY("1998-0" + i + "-0" + i); } list.add(student); } classInfo.setStudentList(list); elementList.add(classInfo); BuildXML.buildXML(elementList, "root"); } }
这段代码应用了dom4j来处理xml。
以后每加一个接口,就只需要设计接口业务数据模型类,它要实现DataMapForXml接口;再处理从数据库或别的数据源向该数据模型类塞数据的任务即可。
整个程序设计以分离数据抓取与xml生成为目标,为了实现自动生成xml方便以后接口的增加,程序引入了接口入参元数据概念以及一个描述接口数据概念图的接口类。
程序需要改进的地方还很多,以后再扩展实现吧!