前情提要

这篇文章主要是解决标题是 MVC模式初体验 properties解析工具 与 Dao层的结合 在最后留的问题,就是怎样去优化下面这部分的代码:

public List<nativeModel> getNativeList() {sql = "SELECT id,name FROM sys_native_cnst";List<nativeModel> nativeList = new ArrayList<>();database db = new database();ResultSet rs = db.executeQuery(sql);try {while(rs.next()) {String id = rs.getString("id");String name = rs.getString("name");nativeList.add(new nativeInfo(id,name));}} catch (SQLException e) {e.printStackTrace();}return nativeList;
}

优化结果预期(自我觉得 优化就是做工具,把这一大堆搞成个工具,也适用于其他的model类)

public List<NativeModel> getNatives() {return  list(NativeModel.class);//相当于这个工具直接可以通过类 类型直接返回这个类的对象的List,
}

优化思路

对于上边的代码,我们是采用nativeModel来作为一个例子说明,我们所需要做的优化就是根据需要获得的ModelList的model类,对应到数据库中相应的model类的表,再根据表中拥有的字段来生成sql语句,并且产生一个关于这个类的对象的列表,其重点在于model类和表和其他信息的对应。

细化部分

那其实对于我们要完成的这个工具,在用的时候我们可以直接在这个关于获得各种 getXXXList 的函数中直接调用,而在调用时只需要一个参数就是model类,而我们的这个工具便可以通过这个类而找到对应的表,并且还可以获知表中存在哪些字段,这样我们便可以先产生一个sql语句,并且根据sql语句我们能从表中获取一个ResultSet(结果集),那么这个结果集就是表中每一条记录的集合,那之前说过,其实表中的一条记录对应的是每一个model类的一个对象,此时我们可以根据这个结果集来每一条记录来给model类的对象赋值,便可以产生一个model类对象的集合,则是我们想要的modelList。
【 有了这个工具之后的,那我们就可以肆无忌惮的变换参数,我换成nationModel.class我们便可以得到一系列籍贯,换成majorModel.class就可以得到一系列的专业,然后就是我上篇文章说的就可以采用这些list去初始化你界面的控件部分的内容了,但问题是你想要初始化的控件所需要的内容(内容就是model类的对象的list)所对应的字段在你的表存在。】
听完这个思路你可能觉得简单,事实上其中有很多值得推敲,研究的地方,废话不多说,听我娓娓道来。

firstStep:

(第一步,我们完成Model类与表的对应,还有表中的字段,类中的成员,将表得信息,model类的信息还有表中的字段与model类中的成员对应的信息都保存在classAndTable类中。在后期将通过hashmap将model类和与它相关的classAndTable类的对象作为键值进行存储,以便之后进行访问。
因为我们实例化一个model类的对象的时候,是通过表中的每一条记录来实例化的)

classAndTable类 (随便起的名字,意思是类与表的对应,先确定主要的成员

public class classAndTable {private Class<?> klass;private String table;private List<PropertyColumn> fieldList;
}

PropertyColumn类(model类中的一个成员对应表中的一个字段)

public class PropertyColumn {private Field field;private String column;
}

解释说明:
这个classAndTable是一个可以让model类和表对应起来的一个类 。

  1. Class<?> klass 表示不同的类;
  2. String table 类对应数据库中的某一个表
  3. List < propertyColumn> fieldList 一个model类中有多个成员与表中的多个字段对应形成以一个list,一个字段对应一个成员就形成了一个propertyColumn。
  4. 这里的PropertyColumn中的对于这个filed的解释为,它是model类的中的一个成员,采用Field来修饰是因为我们并不知道每一个成员的类型,所以我们采用field来定义一是更合理,二是因为我们可以采用反射机制通过成员的名称来初始化PropertyColumn类中filed。

【小结】 上面这两个类的结合将model类和表互相联系的信息已经封装在classAndTable类中,因为界面上有不同的控件,所以也对应的不同的model类,那自然而然也会有不同的表,那我们就得事先通过 配置文件 的方式,产生多个classAndTable类的对象,我们可以对每一个classAndTable类的对象进行初始化,初始化的内容就是model类和它对应的表以及表中的字段和model类中的成员的list列表。初始化完成后就形成一个classAndTable类的对象的list。
然后将个list和对应的model类名称形成键值对存入hashmap中。以后便可以通过model类的名字类在hashmap中找到对应的model类的classAndTable的的信息。

 Map<String, ClassTable> classTableMap;////string 就是对应的model类的名称//classAndTable 就是这个model类与它所对应的表的一系列的信息

SecondStep:( 包含xml解析,xml文件)

这一步我们需要实现初始化model类和表的对应的内容)方便以后我们直接可以构造sql语句
xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<mappings>   <mapping class="com.mec.mis.model.NativeModel" table="sys_native_info"    <column property="id" name="id"></column>  <column property="name" name="name"></column></mapping><mapping class="com.mec.mis.model.NationModel" table="sys_nation_info"><column property="id" name="id"></column><column property="name" name="name"></column>      </mapping>
</mappings>

我们来通过解析这个配置文件中的每一个mapping的方式来将model类和表的对应关系存储起来,(一个mapping事实上就是一个classAndTAble类的内容),为了解释的更清楚,我采用画图的方式来说明存储的方式(以第一个mapping为例子)

xml解析文件(相当于将xml解析后将每一个mapping的内容化作一个classAndTable类的对象进行存储在hashmap中,以后便可以通过hashmap进行键值匹配(根据model类的名称找到对应的classAndTable的对象)

public class ClassTableFactory {private static final Map<String, ClassTable> classTableMap;static {classTableMap = new HashMap<>();}public ClassTableFactory() {  }public void loadMapping(String path) {try {new XMLParser() {@Overridepublic void dealElement(Element element, int index) {String className = element.getAttribute("class");String tableName = element.getAttribute("table");ClassAndTable ct = new ClassAndTable();try {Class<?> klass = Class.forName(className);ct.setKlass(klass);ct.setTable(tableName);new XMLParser() {@Overridepublic void dealElement(Element element, int index) {String id = element.getAttribute("id");String property = element.getAttribute("property");String column = element.getAttribute("name");PropertyColumn pc = new PropertyColumn();try {pc.setField(klass.getDeclaredField(property));pc.setColumn(column);if (id.length() > 0) {ct.setId(pc);}ct.addProperty(pc);} catch (NoSuchFieldException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();}}}.parse(element, "column");} catch (ClassNotFoundException e) {e.printStackTrace();}classTableMap.put(className, ct);}}.parse(XMLParser.loadXml(path), "mapping");} catch (SAXException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} }public static ClassAndTable getClassTable(Class<?> klass) {return classTableMap.get(klass.getName());}public static ClassAndTable getClassTable(String className) {return classTableMap.get(className);}

xml解析工具

public abstract class XMLParser {private static DocumentBuilder db;public XMLParser() {}public static Document loadXml(String xmlPath) throws SAXException, IOException {InputStream is = XMLParser.class.getResourceAsStream(xmlPath);return loadXml(is);}static {try {db = DocumentBuilderFactory.newInstance().newDocumentBuilder();} catch (ParserConfigurationException e) {e.printStackTrace();}}public static Document loadXml(InputStream is) throws SAXException, IOException {return db.parse(is);}public abstract void dealElement(Element element, int index);public void parse(Document document, String tagname) {NodeList nodeList = document.getElementsByTagName(tagname);for (int index = 0; index < nodeList.getLength(); index++) {Element element = (Element) nodeList.item(index);dealElement(element, index);}}public void parse(Element element, String tagname) {NodeList nodeList = element.getElementsByTagName(tagname);for (int index = 0; index < nodeList.getLength(); index++) {Element ele = (Element) nodeList.item(index);dealElement(ele, index);}}}

这两步操作已经将完成了model类与对应表信息的存储,存储在hashMap中,相当于map中的键就是某一个model类的名称,值就是与model类对应的表及其字段信息,为之后可以通过classTableFactory类中的方法getClassTable(Class<?> klass),通过将model类作为参数可以获取到对应的键值classAndTable类的一个对象,并且根据这个对象的内容进行构造sql语句,进行从数据库获取数据。

ThirdStep:(反射机制的应用)

classAndTable类方法的完善和propertyColumn类方法的完善。

propertyColumn类

在这里插入代码片
public class PropertyColumn {    private Field field;private String column;public PropertyColumn() {}public void setProperty(ResultSet resultSet, Object object) {try {// 从表的当前一条记录中,获取以column的值为字段名的字段的值Object value = resultSet.getObject(column);// 设置field(成员)的可访问性为真,即,private成员都可以被访问field.setAccessible(true);// 更改对象object的field成员的值为valuefield.set(object, value);} catch (SQLException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}//后边还有成员的getter和setter的程序就不在此多说了

classAndTable类

public class ClassAndTable {private Class<?> klass;private String table;private List<PropertyColumn> fieldList;private PropertyColumn id;public ClassTable() {fieldList = new ArrayList<>();}public void setFieldFromResultSet(ResultSet resultSet, Object object) {for (PropertyColumn field : fieldList) {field.setProperty(resultSet, object);}}public void addProperty(PropertyColumn property) {fieldList.add(property);}public String getIdString() {return table + "." + id.getColumn();}public String getColumnString() {StringBuffer res = new StringBuffer();boolean first = true;for (PropertyColumn field : fieldList) {res.append(first ? "" : ", ").append(table).append('.').append(field.getColumn());first = false;}return res.toString();}//后边的成员getter和setter方法不再说明
}

上述的两段代码,采用了反射机制。

  1. 因为classAndTable类主要是存储model类所对应的表的数据和字段与model类中的成员的一一对应关系,那自然可以采用这些信息构造出来sql语句主要部分,例如从哪个表获取数据,获取表中哪个字段的数据。
  2. propertyColumn类中有一个重要的方法就是setProperty(ResultSet resultSet, Object object) ,因为propertyColumn类的对象组成一个list做为classAndtable的一个成员。

我们本身的目的就是根据已知的model类,获知其对应的表,产生一个sql语句从表中获取需要的字段的信息,采用这些信息反过来初始化model类的对象,并形成一个model类对象的list去初始化控件。

所以看下面这段代码,采用 注释解释propertyColumn类中的setProperty( ) 方法和classAndTable类中的setFieldFromResultSet()方法

database类中的一个方法

public <T> List<T> list(Class<?> klass) {//事实上这个方法就是我们上篇文章所说的优化部分,把很多相同的代码归纳写为一个工具,只需要给不同的model类就可以。ClassAndTable ct = ClassTableFactory.getClassTable(klass);//在进行调用这个方法的时候,只需给出参数model类,这一句代码的意思就是根据这个model类,可以在 ClassTableFactory中的haspMap中根据键值对的得到model类对应的一个classAndTable类的对象,这个对象里边包含的是与这个model有关的表和字段相关信息。if (ct == null) {return null;}String sql = "SELECT " + ct.getColumnString() + " FROM " + ct.getTable();//这条语句是产生sql语句。// ct.getColumnString()是因为ClassAndTable这个类中有这个方法,将classAndtable中的表信息与字段信息组成一个字符串.// ct.getTable()也是classAndTable类中的一个方法,返回表名称字符串。// 这条sql语句说明了从哪个表中获取这个表中的哪些字段的信息。List<T> result = new ArrayList<>();try {PreparedStatement state = getConnection().prepareStatement(sql);ResultSet rs = state.executeQuery();//rs是一个结果集,就是通过sql语句从数据库获取到的字段信息。相当于多条记录的一个列表。while(rs.next()) {Object object = klass.newInstance();// 产生一个model类的对象.ct.setFieldFromResultSet(rs, object);//就是根据这个结果集对产生的每一个model类的对象进行赋值操作,此时下面的赋值操作就是用到了反射机制。// 之前说过一个表对应一个类,而表中的一条记录对应一个这个类的对象。// 此时的rs表示类结果集的第一条记录//ct.setFieldFromResultSet(rs, object)这个方法是classAndFactory中的,因为要通过一条记录对model类的对象进行赋值.//若一条记录汇总包含两个不同的字段编号和名称,那classAndFactory中有一个List<PropertyColumn> fieldList,那么这个list有两个PropertyColumn元素,一个元素中是编号成员和编号字段对应,另一个元素是名称成员和名称字段对应。//setFieldFromResultSet(rs, object)方法循环classAndFactory中的List<PropertyColumn> ,//setProperty(ResultSet resultSet, Object object)方法对利用List<PropertyColumn> 每一个元素中的成员和字段关系进行对model类的一个对象的每个成员进行赋值。result.add((T) object}} catch (SQLException e) {e.printStackTrace();} return result;}

小结:

上边函数中while循环中的三步操作可以根据 classAndFactory类 中的 setFieldFromResultSet() 方法和 propertyColumn类 中的 setProperty( ) 方法进行结合分析。这个函数用来获取对应的modelList,也正是上一篇文章中所要优化部分的代码,在这里只需这一个函数便可以获取不同的modelList,只需在需要产生不同种类的modelList的函数中去调用上边这个函数即可。

那么在这篇文章开头的代码优化结果便是如下了,优化过程虽复杂,但确实做成工具非常的实用。
现在只需要根据传入不同的类就可以获得modelList,再也不需要重复的写类似的代码了。

public List<NativeModel> getNatives() {return database.list(NativeModel.class);
}

ps: 开开开山怪【原创文章】

【反射机制】与 【xml解析 】之 巧夺天工 —————— 开开开山怪相关推荐

  1. python反射实例化_Python类反射机制使用实例解析

    这篇文章主要介绍了Python类反射机制使用实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 反射就是通过字符串的形式,导入模块:通过字符串的 ...

  2. 解析Spring IOC原理——工厂模式与反射机制的综合应用

    (一)工厂模式 从一个例子开始讲起: 首先我们建立一个Chinese.java类,该类的sayHelloWorld(String name)方法,用中文对名为name的人问好,其内容如下: [java ...

  3. 深入理解Java中的反射机制和使用原理!详细解析invoke方法的执行和使用

    反射的概念 反射:Refelection,反射是Java的特征之一,允许运行中的Java程序获取自身信息,并可以操作类或者对象的内部属性 通过反射,可以在运行时获得程序或者程序中的每一个类型的成员活成 ...

  4. java xml 反射_Java 读取XML文件以及Java 的反射机制实现

    Java 读取XML文件以及Java 的反射机制实现 代码部分 import java.io.File; import javax.xml.parsers.DocumentBuilder; impor ...

  5. java 反射机制_基础篇:深入解析JAVA反射机制

    反射的概念 java 的放射机制:在程序运行时,程序有能力获取一个类的所有方法和属性:并且对于任意一个对象,可以调用它的任意方法或者获取其属性 通俗解析:java 文件需要编译成. class 文件才 ...

  6. 使用Java泛型和反射机制编写Excel文件生成和解析的通用工具类

    前几天被派到一个小项目中做临时维护,工作地点不方便且不说,项目代码那叫一个恶心... 代码几乎完全没有注释.这应该是我们天朝大部分程序员的习惯,代码不写注释,给后面维护的同事带来多大麻烦啊! 几百行的 ...

  7. 2015.03.19---PHP XCAP开发,PHP XML导出, PHP数组的操作,PHP反射机制

    今日任务: 1.XCAP开发,XML导出 实际: 利用数组操作排序 收获: 1.数组的操作 2.php中反射机制--ReflectionClass,可以获取类中的属性和方法 model对象: [img ...

  8. 深入探索Java反射机制:解析原理与应用

    深入探索Java反射机制:解析原理与应用

  9. java invoke 泛型_利用Java反射机制和泛型,全自动解析json

    有啦这个简直,太爽啦, 利用Java 反射机制,利用Class 就可以得到 类的 变量  Field[] fields=cls.getDeclaredFields(); 还可以通过类中 的方法名字 去 ...

  10. java代码安全检测机制_全面解析:java中的反射机制,内含代码验证解析

    什么是反射? 在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功 ...

最新文章

  1. linux /etc/rc.d/目录的详解
  2. QML基础类型之geopath
  3. 详解Spring缓存注解@Cacheable,@CachePut , @CacheEvict使用
  4. ABAP function group和Tomcat library重复加载问题
  5. 『软件测试3』八大典型的黑盒测试方法已来袭,快快接住!
  6. Python处理csv文件
  7. 2021年财富世界500强,苹果是全球最赚钱公司,小米第338位,第一是它
  8. 拼多多开除即将拿到股票的安全大佬;虾米音乐将永久关停;GitHub 解禁伊朗开发者使用权
  9. VS2010整合NUnit进行单元测试
  10. Linux文件类型和权限
  11. 使用onenote记HTML笔记,以记录网页上的内容为例,教你如何利用OneNote 2010轻松记录笔记...
  12. 怎么样锁定计算机时间,电脑屏幕锁屏设置时间还是锁不了怎么办
  13. android studio 前言中不允许有内容。
  14. The requested URL * was not found on this server. 的解决方法
  15. hdu 3853 LOOPS
  16. 逍遥模拟器连接不到android,逍遥安卓模拟器无法连接网络的解决方法
  17. Kafka中的消费者组(Consumer Group)
  18. PowerSI提取S参数(插损、回损、串扰分析)
  19. 卡西欧计算机fx82cnx怎么玩游戏,卡西欧fx-82ES计算器乱码玩法问题
  20. 关于KV存储的一些总结更新中

热门文章

  1. 【微信小程序】获取Bmob后端云数据库某一数据表的所有记录
  2. ES2015简介和基本语法
  3. jsp是java的一种吗_jsp是什么
  4. JDK13 Switch表达式新特性
  5. MATLAB小技巧(30)非线性拟合 lsqcurefit
  6. 百面机器学习:算法工程师带你去面试
  7. UGI九宫格sliced显示问题
  8. 好用的电子邮箱测评,这么多的邮箱究竟哪个最好用呢?
  9. 学习笔记-部署和管理DPM 2016-04文件和应用程序保护
  10. OpenGL 栅格化