利用反射和xml配置文件手写一个小型的框架

通用的增删改查

  • 1. 利用xml配置实体类和数据库表名的映射关系
  • 2. 根据xml设计,用正确的数据结构映射类封装好xml信息
  • 3. 得到数据库连接前,读取xml信息,用map封装成映射数据
  • 4. 写dao时根据反射和map生成sql语句,拿到属性值
  • 测试

  • 为了解决上一篇文中实体类的局限性:不可加字段;实体名,表名,列的字段一样,而且顺序一样
  • 上一篇反射实现dao层增删改查
  • 本文实现结构

1. 利用xml配置实体类和数据库表名的映射关系

  • sql语句
create table ticket_info (ticket_id number primary key,ticket_name varchar(30) not null,  ticket_price number(10, 2) not null     
)
create sequence ticket_seqcreate table goods_info (goods_id number primary key, goods_name varchar(30) not null,goods_price number(10, 2) not null,goods_date date not null,      goods_factory varchar(50) not null 
)
create sequence goods_seq
  • xml, 映射表属性和实体类列

  • goods.xml

<?xml version="1.0" encoding="UTF-8"?><class name="com.lovely.entity.Goods" table="goods_info"><id name="gid" column="goods_id"><sequence>goods_seq</sequence></id><property name="gname" column="goods_name"></property><property name="gprice" column="goods_price"></property><property name="gdate" column="goods_date"></property><property name="gfactory" column="goods_factory"></property>
</class>
  • ticket.xml
<?xml version="1.0" encoding="UTF-8"?><!-- 实体类和表之间的映射关系 -->
<class name="com.lovely.entity.Ticket" table="ticket_info"> <!-- 类名和表名的映射关系 --><id name="tid" column="ticket_id"> <!-- 实体主键和表中主键列的映射关系 --><sequence>ticket_seq</sequence></id><property name="tname" column="ticket_name"></property> <!-- 属性名和表名列的映射关系 --><property name="tprice" column="ticket_price"></property></class>
  • goods, 和 entity的实体类
package com.lovely.entity;import java.sql.Date;public class Goods {private Integer gid;private String gname;private Double gprice;private Date gdate;private String gfactory;public Goods() {}public Integer getGid() {return gid;}public void setGid(Integer gid) {this.gid = gid;}public String getGname() {return gname;}public void setGname(String gname) {this.gname = gname;}public Double getGprice() {return gprice;}public void setGprice(Double gprice) {this.gprice = gprice;}public Date getGdate() {return gdate;}public void setGdate(Date gdate) {this.gdate = gdate;}public String getGfactory() {return gfactory;}public void setGfactory(String gfactory) {this.gfactory = gfactory;}}
package com.lovely.entity;public class Ticket {private Integer tid;private String tname;private Double tprice;public Ticket() {}public Ticket(Integer tid, String tname, Double tprice) {super();this.tid = tid;this.tname = tname;this.tprice = tprice;}public Integer getTid() {return tid;}public void setTid(Integer tid) {this.tid = tid;}public String getTname() {return tname;}public void setTname(String tname) {this.tname = tname;}public Double getTprice() {return tprice;}public void setTprice(Double tprice) {this.tprice = tprice;}@Overridepublic String toString() {return "Ticket [tid=" + tid + ", tname=" + tname + ", tprice=" + tprice+ "]\n";}}

2. 根据xml设计,用正确的数据结构映射类封装好xml信息

  • 主键id
package com.lovely.base;public class MapperId {// 实体id 映射 数据库idprivate String idName;private String idColumn;private String seqName;public String getIdName() {return idName;}public void setIdName(String idName) {this.idName = idName;}public String getIdColumn() {return idColumn;}public void setIdColumn(String idColumn) {this.idColumn = idColumn;}public String getSeqName() {return seqName;}public void setSeqName(String seqName) {this.seqName = seqName;}@Overridepublic String toString() {return "MapperId [idName=" + idName + ", idColumn=" + idColumn+ ", seqName=" + seqName + "]";}}
  • MapperData 映射数据类
package com.lovely.base;import java.util.LinkedHashMap;public class MapperData {// 映射文件类// 实体全类名private String className;// 表名private String tableName;private MapperId mapperId;// 存储除主键外 实体属性 -> 数据表列 相关信息private LinkedHashMap<String, String> properties = new LinkedHashMap<String, String>();public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}public String getTableName() {return tableName;}public void setTableName(String tableName) {this.tableName = tableName;}public MapperId getMapperId() {return mapperId;}public void setMapperId(MapperId mapperId) {this.mapperId = mapperId;}public LinkedHashMap<String, String> getProperties() {return properties;}public void setProperties(LinkedHashMap<String, String> properties) {this.properties = properties;}@Overridepublic String toString() {return "MapperData [className=" + className + ", tableName="+ tableName + ", mapperId=" + mapperId + ", properties="+ properties + "]\n";}}

3. 得到数据库连接前,读取xml信息,用map封装成映射数据

  • 实体属性名和表的列名一样,也封装在map里面了
package com.lovely.dao;import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;import com.lovely.base.MapperData;
import com.lovely.base.MapperId;public class BaseDao {static {try {Class.forName("oracle.jdbc.OracleDriver");} catch (ClassNotFoundException e) {e.printStackTrace();}}/*** key: 全路径类名 * value: 类和表的映射关系 MapperData*/public static HashMap<String, MapperData> map = new HashMap<String, MapperData>();static {// 静态块解析xml映射文件try {			Class<?> baseDaoClass = Class.forName("com.lovely.dao.BaseDao");// 得到xml路径URL url = baseDaoClass.getResource("/com/lovely/mapper");String path = url.getFile();File file = new File(path);// 拿到所有xml文件File[] files = file.listFiles();for (int i = 0; i < files.length; i++) {// 解析xml一个文件// System.out.println(files[i].getName());SAXReader reader = new SAXReader();Document doc = reader.read(files[i]);// 拿到 class结点Element root = doc.getRootElement();MapperData mapperData = new MapperData();// 保存实体类名mapperData.setClassName(root.attributeValue("name")); // 保存数据表名mapperData.setTableName(root.attributeValue("table"));MapperId mapperId = new MapperId();// 主键结点映射关系Element primaryKey = root.element("id");// 实体类主键mapperId.setIdName(primaryKey.attributeValue("name"));// 表的主键mapperId.setIdColumn(primaryKey.attributeValue("column"));// 序列名称mapperId.setSeqName(primaryKey.elementText("sequence"));// 保存主键结点映射关系mapperData.setMapperId(mapperId);@SuppressWarnings("unchecked")// 所有 实体属性-表名结点映射关系List<Element> property = root.elements("property");LinkedHashMap<String, String> lhm = new LinkedHashMap<String, String>();for (Element field : property) {lhm.put(field.attributeValue("name"), field.attributeValue("column"));}mapperData.setProperties(lhm);// 把实体类 与 xml中的映射数据一一对应map.put(root.attributeValue("name"), mapperData);}} catch (Exception e) {e.printStackTrace();}}static {// 加载没有配置文件的实体类 try {Class<?> c = BaseDao.class;// mapper下的路径String path = c.getResource("/com/lovely/entity").getFile();File file = new File(path);File[] files = file.listFiles();for (int i = 0; i < files.length; i++) {String fileName = files[i].getName();String className = "com.lovely.entity." + fileName.substring(0, fileName.indexOf("."));// 没有映射文件的解析 对于数据库表名,字段,顺序 和 实体的类名 字段 顺序一样。if (!map.containsKey(className)) {// 实体类的类型描述Class<?> cc = Class.forName(className);MapperData value = new MapperData();// 设置实体类名和表名value.setClassName(cc.getName());value.setTableName(cc.getSimpleName());Field[] fields = cc.getDeclaredFields();Field.setAccessible(fields, true);// 拿到主键String primaryKeyName = fields[0].getName();MapperId mapperId = new MapperId();mapperId.setIdName(primaryKeyName);mapperId.setIdColumn(primaryKeyName);mapperId.setSeqName("seq_" + cc.getSimpleName());// 属性 主键列名 序列名value.setMapperId(mapperId);LinkedHashMap<String, String> properties = new LinkedHashMap<String, String>();// 设置除主键意外的属性for (int j = 1; j < fields.length; j++) {properties.put(fields[j].getName(), fields[j].getName());}value.setProperties(properties);map.put(className, value);}}} catch(Exception e) {e.printStackTrace();}}public static void main(String[] args) {System.out.println(map);}public static Connection getConn() {Connection conn = null;String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";try {conn = DriverManager.getConnection(url, "scott", "scott");} catch (SQLException e) {e.printStackTrace();}return conn;}public static void closeAll(Connection conn, PreparedStatement ps, ResultSet rs) {try {if (rs != null)rs.close();if (ps != null)ps.close();if (conn != null)conn.close();} catch (SQLException e) {e.printStackTrace();}}
}

4. 写dao时根据反射和map生成sql语句,拿到属性值

  • curd实现
package com.lovely.dao;import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;import com.lovely.base.MapperData;
import com.lovely.base.MapperId;/*** * @author echo lovely* * 万能增删改查**/
public class CommonDao {public int save(Object entity) {int count = -1;Class<?> c = entity.getClass();MapperData mapperData = BaseDao.map.get(c.getName());StringBuffer sql = new StringBuffer();sql.append("insert into ");sql.append(mapperData.getTableName() + " values (");// insert into tableName values (seq_table.nextval, ?, ?, ?...)sql.append(mapperData.getMapperId().getSeqName() + ".nextval");LinkedHashMap<String,String> properties = mapperData.getProperties();Set<String> keySet = properties.keySet();// 除主键外的 实体属性名for (int i = 0; i < keySet.size(); i++) {sql.append(", ?");}sql.append(")");System.out.println(sql);Connection conn = BaseDao.getConn();PreparedStatement ps = null;try {ps = conn.prepareStatement(sql.toString());// 设置参数的值// 取实体列int index = 1;for (String entityColumn : keySet) {// 反射根据属性名称拿值Field field = c.getDeclaredField(entityColumn);field.setAccessible(true);ps.setObject(index, field.get(entity));index ++;}count = ps.executeUpdate();} catch (Exception e) {e.printStackTrace();} finally {BaseDao.closeAll(conn, ps, null);}return count;}public List<Object> queryAll(Class<?> c) {List<Object> list = new ArrayList<Object>();// 拿到  实体类 与 表的列 映射关系MapperData mapperData = BaseDao.map.get(c.getName());String sql = "select * from " + mapperData.getTableName();Connection conn = BaseDao.getConn();PreparedStatement ps = null;ResultSet rs = null;LinkedHashMap<String, String> properties = mapperData.getProperties();try {ps = conn.prepareStatement(sql);rs = ps.executeQuery();// 表主键列名String primaryKeyName = mapperData.getMapperId().getIdColumn();String idName = mapperData.getMapperId().getIdName();while (rs.next()) {Object entity = c.newInstance();Object primaryKeyValue = rs.getObject(primaryKeyName);	// 主键属性Field primaryFiled = c.getDeclaredField(idName);if (primaryFiled.getType() == Integer.class)primaryKeyValue = rs.getInt(primaryKeyName);primaryFiled.setAccessible(true);primaryFiled.set(entity, primaryKeyValue);Set<Entry<String,String>> entrySet = properties.entrySet();for (Entry<String, String> entry : entrySet) {// 属性名称String filedName = entry.getKey();// 表的列名String columnName = entry.getValue();Object attributValue = rs.getObject(columnName);// System.out.println(filedName + "\t" + columnName + "...");// 除主键外的属性对象Field f = c.getDeclaredField(filedName);if (f.getType() == Double.class) {attributValue = rs.getDouble(columnName);} else if (f.getType() == java.sql.Timestamp.class) {attributValue = rs.getTimestamp(columnName);}f.setAccessible(true);f.set(entity, attributValue);}list.add(entity);			}} catch (Exception e) {e.printStackTrace();} finally {BaseDao.closeAll(conn, ps, rs);}return list;}public Object queryOne(Object obj) {Object entity = null;Class<?> c = obj.getClass();MapperData mapperData = BaseDao.map.get(c.getName());String sql = "select * from " + mapperData.getTableName() + " where " + mapperData.getMapperId().getIdColumn() + " = ?";System.out.println(sql);Connection conn = BaseDao.getConn();PreparedStatement ps = null;ResultSet rs = null;try {MapperId mapperId = mapperData.getMapperId();ps = conn.prepareStatement(sql);// 拿到主键属性对象Field field = c.getDeclaredField(mapperId.getIdName());field.setAccessible(true);ps.setObject(1, field.get(obj));rs = ps.executeQuery();	LinkedHashMap<String,String> properties = mapperData.getProperties();Set<Entry<String, String>> entrySet = properties.entrySet();if (rs.next()) {// 记得反射创建对象...entity = c.newInstance();Field idFiled = c.getDeclaredField(mapperId.getIdName());idFiled.setAccessible(true);// 取到主键值Object idColumn = rs.getObject(mapperId.getIdColumn());System.out.println(idColumn + "\t" + mapperId.getIdName() + "\t" + mapperId.getIdColumn());if (idFiled.getType() == Integer.class) {idColumn = rs.getInt(mapperId.getIdColumn());}	idFiled.set(entity, idColumn);for (Entry<String, String> entry : entrySet) {Field f1 = c.getDeclaredField(entry.getKey());f1.setAccessible(true);Object value = rs.getObject(entry.getValue());if (f1.getType() == Double.class)value = rs.getDouble(entry.getValue());else if (f1.getType() == Timestamp.class) {value = rs.getTimestamp(entry.getValue());}f1.set(entity, value);		}}} catch (Exception e) {e.printStackTrace();} finally {BaseDao.closeAll(conn, ps, rs);}return entity;}public int update(Object entity) {int count = -1;Class<?> c = entity.getClass();StringBuffer sql = new StringBuffer();// 根据类的全路径 拿到MapperDataMapperData mapperData = BaseDao.map.get(c.getName());// update tabName set * = ?, * = ?, * = ? .... where id = ?sql.append("update " + mapperData.getTableName() + " set ");LinkedHashMap<String,String> properties = mapperData.getProperties();// 除了主键外的所有属性集合Set<String> keySet = properties.keySet();// 数据库中表 列的集合Collection<String> cloumnNames = properties.values();int cloumnSize = cloumnNames.size();int index = 0;for (String cloumnName : cloumnNames) {if (index < cloumnSize - 1) sql.append(cloumnName + " = ?, ");else sql.append(cloumnName + " = ?");index ++;			}sql.append(" where " + mapperData.getMapperId().getIdColumn() + " = ?");System.out.println(sql);Connection conn = BaseDao.getConn();PreparedStatement ps = null;try {ps = conn.prepareStatement(sql.toString());int paramIndex = 1;for (String fieldAttribute : keySet) {// 映射的键 -> 实体属性对象Field field = c.getDeclaredField(fieldAttribute);field.setAccessible(true);Object obj = field.get(entity);ps.setObject(paramIndex, obj);paramIndex ++;}// 主键属性Field field = c.getDeclaredField(mapperData.getMapperId().getIdName());field.setAccessible(true);ps.setObject(paramIndex, field.get(entity));count = ps.executeUpdate();} catch (Exception e) {e.printStackTrace();} finally {BaseDao.closeAll(conn, ps, null);}return count;}public int delete(Object obj) {int count = -1;Class<?> c = obj.getClass();MapperData mapperData = BaseDao.map.get(c.getName());MapperId mapperId = mapperData.getMapperId();String sql = "delete from " + mapperData.getTableName() + " where " + mapperId.getIdColumn() + " = ?";Connection conn = BaseDao.getConn();PreparedStatement ps = null;try {ps = conn.prepareStatement(sql);// 反射拿到实体类 主键属性对象Field field = c.getDeclaredField(mapperId.getIdName());field.setAccessible(true);// 根据属性对象 取到 该对象的属性值ps.setObject(1, field.get(obj));count = ps.executeUpdate();} catch (Exception e) {e.printStackTrace();} finally {BaseDao.closeAll(conn, ps, null);}return count;		}}

测试

  • 一句代码搞定查询。。。

package com.lovely.test;import com.lovely.dao.CommonDao;
import com.lovely.entity.Student;
import com.lovely.entity.Ticket;public class Test1 {public static void main(String[] args) {CommonDao dao = new CommonDao();// 学生类的结构和表的结构一样System.out.println(dao.queryAll(Studdent.getClass()));// 配置了xml映射关系的System.out.println(dao.queryAll(Ticket.class));}}
[Student [sid=46, sname=jack, sgender=male, sbirth=2020-07-02 20:24:01.0, saddress=null, sinfo=null]
]
[Ticket [tid=2, tname=花木兰, tprice=33.2]
, Ticket [tid=3, tname=阿凡达2, tprice=50.5]
]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/420842.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DPtoLP/LPtoDP 和 ScreenToClient/ClientToScreen

设备坐标&#xff08;Device Coordinate&#xff09;又称为物理坐标&#xff08;Physical Coordinate&#xff09;&#xff0c;是指输出设备上的坐标。通常将屏幕上的设备坐标称为屏幕坐标。设备坐标用对象距离窗口左上角的水平距离和垂直距离来指定对象的位置&#xff0c;是以…

前端学习(1127):递归求数学题2

斐波那契数列 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head>…

1008 数组元素循环右移问题 (20分)

输入样例: 6 2 1 2 3 4 5 6 输出样例: 5 6 1 2 3 4 # -*- coding: utf-8 -*- import mathdef right_shift(lst, m):n len(lst)m m % nfor j in range(math.gcd(m, n)):temp lst[j]i jwhile (i - m) % n > j:lst[i] lst[(i - m) % n]i (i - m) % nlst[i] tempretur…

MVC分层开发模式

MVC 1. 什么是mvc开发模式2. 基于servlet手写mvc框架1. 什么是mvc开发模式 mvc不是一种技术&#xff0c;只是一种开发模式使用分层开发模式能在大型项目中&#xff0c;让开发人员更好的协同工作便于项目的维护和扩展 M: Model 模型层->数据库层->daoV: View 视图层->…

C#_uploadify_mvc_version

jQuery Uploadify在ASP.NET MVC3中的使用 1、Uploadify简介 Uploadify是基于jQuery的一种上传插件&#xff0c;支持多文件、带进度条显示上传&#xff0c;在项目开发中常被使用。 Uploadify官方网址&#xff1a;http://www.uploadify.com/ 2、ASP.NET MVC3中的使用Uploadify 搭…

1010 一元多项式求导 (25分)

输入样例: 3 4 -5 2 6 1 -2 0 输出样例: 12 3 -10 1 6 0 # -*- coding: utf-8 -*-def get_derivation(lst):length len(lst)idx 0while idx < length:if lst[idx 1] ! 0:lst[idx] * lst[idx 1]lst[idx 1] - 1else:lst[idx] 0idx 2return lstif __name__ __main__…

VS2012 发布网站步骤

VS2012中发布网站的方式与以往有了不同&#xff0c;前面的版本发布如图 而2012点publish的时候弹出框有所不同&#xff0c;这边需要新建一个profile名字随便起&#xff0c;发布的方式有好几种&#xff0c; 当然不同的方式配置不同&#xff0c;用的最多的就是files system了 选择…

python 生成个性二维码

1. 效果 gif 图片二维码 带背景图二维码&#xff08;修改了&#xff09; 2. 依赖库 核心库myqr pip install myqr其它依赖库安装pip install pip install pillow, numpy, imageio3. 核心代码 我这里是F盘下的joy文件夹下面代码改变路径&#xff0c;图片名称参数即可 im…

1011 A+B 和 C (15分)

输入样例&#xff1a; 4 1 2 3 2 3 4 2147483647 0 2147483646 0 -2147483648 -2147483647 输出样例&#xff1a; Case #1: false Case #2: true Case #3: true Case #4: false # -*- coding: utf-8 -*-if __name__ __main__:n eval(input())input_list []for i in range…

SharePoint 2013:解决添加域名后每次都需要登录的问题

在SharePoint 2013中&#xff0c;当我们添加一个域名给SP后&#xff08;添加域名的方法请参考此文&#xff1a;http://www.cnblogs.com/jianyus/archive/2013/08/10/3249461.html &#xff09;&#xff0c;每次用域名访问都需要输入用户名和密码&#xff0c;即使该用户已经正确…

1012 数字分类 (20分)

输入样例 1&#xff1a; 13 1 2 3 4 5 6 7 8 9 10 20 16 18 输出样例 1&#xff1a; 30 11 2 9.7 9 输入样例 2&#xff1a; 8 1 2 4 5 6 7 9 16 输出样例 2&#xff1a; N 11 2 N 9 # -*- coding: utf-8 -*-def class_numbers(nums):arr [0] * 5exists [0] * 5flag1 1…

mvc框架upgrade

upgrade...1. actionservlet核心控制器更改以上1&#xff0c;2点2. 工具类&#xff08;对反射拿到的属性对象数据转型&#xff09;3. 业务服务类使用适配器设计模式针对上一篇文字做出了改造&#xff0c;既然要写手写lowb版mvc框架&#xff0c;就得付出一定代价&#xff0c;加大…

1013 数素数 (20分)

输入样例&#xff1a; 5 27 输出样例&#xff1a; 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 # -*- encoding: utf-8 -*- import mathdef get_primes(n):prime_list [1] * (n 1)for i in range(2, int(math.sqrt(n)) 1):if prime_list[i]…

1014 福尔摩斯的约会 (20分)

输入样例&#xff1a; 3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm 输出样例&#xff1a; THU 14:04 # -*- coding: utf-8 -*- import stringweek {A: MON,B: TUE,C: WED,D: THU,E: FRI,F: SAT,G: SUN}hour {0:00, 1:01, 2:02, 3:03, 4:04, 5:05, 6:0…

MSSQL如何在没有主键的表中删除重复数据

MSSQL如何在没有主键的表中删除重复数据 原文:MSSQL如何在没有主键的表中删除重复数据为了对重复数据进行实验&#xff0c;下面建一个设计不太好&#xff08;没有主键&#xff09;表并插入了一些重复数据&#xff1a; create database testdbuse testdb ; go create table Dups…

1015 德才论 (25分)

输入样例&#xff1a; 14 60 80 10000001 64 90 10000002 90 60 10000011 85 80 10000003 85 80 10000004 80 85 10000005 82 77 10000006 83 76 10000007 90 78 10000008 75 79 10000009 59 90 10000010 88 45 10000012 80 100 10000013 90 99 10000014 66 60 输出样例&#…

1016 部分A+B (15分)

输入样例 1&#xff1a; 3862767 6 13530293 3 输出样例 1&#xff1a; 399 输入样例 2&#xff1a; 3862767 1 13530293 8 输出样例 2&#xff1a; 0 # -*- coding: utf-8 -*-if __name__ __main__:input_list input().split()a, d_a, b, d_b input_list[0], input_li…

马哥学习笔记二十七——IO复用

I/O动作模式  阻塞 非阻塞 I/O复用 信号驱动 异步 转载于:https://www.cnblogs.com/wangyongbin/p/3817353.html