您现在的位置:新闻首页>资本 > Java使用反射,把对象转换成 MongoDb 的结构
Java使用反射,把对象转换成 MongoDb 的结构
java基础教程栏目介绍如何把对象转换成MongoDb的结构
(免费):java基础教程
反射是 Java 的一个高级技巧,大量地用在各种开源项目上。比如,Spring、Tomcat、Jetty 等等项目中,都大量地用到了反射。
作为 Java 程序员,我们如果用好反射,不但能提高自己的技术水平,还能开发出更好的项目。
然而,虽然很多人听说过反射,但却不知道应该用在哪里。
那么,我们就从实际工作出发,使用反射,把对象转换成 MongoDb 的数据结构。当你在搞懂这个例子后,就能明白反射是怎么个用法。
需求分析
在电商系统中,一些数据要保存到 MongoDb 中,以此来提高查询的性能。但在此之前,我们必须把数据先转换成 MongoDb 的结构,也就是把 Java 对象转换成 Document。
比如,订单信息要存到 MongoDb 中,就得把订单对象转换成 Document。
可这样一来,每个实体类都得开发一个 2Doc() 方法。这个方法毫无技术含量,就是把各种字段 put 到 Document 里面。而且一旦字段多了,一不留神就会写错代码,你感受一下。
public class Order { private Long id; private Long userId; private String orderNo; private BigDecimal amount; private String createTime; private String updateTime; // 省略无数字段 // 转换方法:订单转doc public Document order2Doc(Order order) { Document doc = new Document(); doc.put("id", order.getId()); doc.put("userId", order.getUserId()); doc.put("orderNo", order.getOrderNo()); doc.put("amount", order.getAmount()); doc.put("createTime", order.getCreateTime()); doc.put("updateTime", order.getUpdateTime()); // 省略无数put... return doc; } }
除此之外,我们还得从 MongoDb 中取数据,把 Document 转换回 Java 对象,你再感受一下。
public class Order { private Long id; private Long userId; private String orderNo; private BigDecimal amount; private String createTime; private String updateTime; // 省略无数字段 // 转换方法:doc转订单 public Order doc2Order(Document doc) { Order order = new Order(); order.setId((Long) doc.get("id")); order.setUserId((Long) doc.get("userId")); order.setOrderNo((String) doc.get("orderNo")); order.setAmount((BigDecimal) doc.get("amount")); order.setCreateTime((String) doc.get("createTime")); order.setUpdateTime((String) doc.get("updateTime")); // 省略无数set... return order; } }
光是一个订单类都这么麻烦了,何况这样的类不止一个,而且项目总有新需求,如果一个字段改了,那你麻烦大了,说不定要把整个项目翻一遍。
因此,为了少出错,必须优化这两个转换方法,而这次优化用到了 Java 的两个高级特性:反射、泛型。为了让大家更直观的了解,我将分成两个版本迭代。
第一版,利用反射,简化实体类的转换方法;
第二版,利用泛型、反射,提取 MongoDb 工具类;
接下来,我们就一步步迭代吧~
利用反射,简化实体类的转换方法
在第一版的迭代中,我们要简化实体类的两个转换方法。
我们先从 Java 对象转 Document 开始,还是以 Order 类为例。
首先,我们通过反射,获取到订单类的所有字段信息;然后,使用循环遍历这些字段;最后,在循环中,我们放开字段的访问权限,把字段 put 到 Document 里面。
public class Order { // ...省略无数字段 public Document order2Doc(Order order) throws Exception { Document doc = new Document(); // 获取所有字段:通过 getClass() 方法获取 Class 对象,然后获取这个类所有字段 Field[] fields = order.getClass().getDeclaredFields(); for (Field field : fields) { // 开放字段操作权限 field.setAccessible(true); // 设置值 doc.put(field.getName(), field.get(order)); } return doc; } }
你可以看到,经过反射改造后,代码简单了很多。一个对象无论有多少个字段,要写多少 put 操作,只要这几行代码就能搞定。Java 对象转成 MongoDb 的结构,看起来也不那么麻烦了。
照着这个思路,我们再来改造第二个方法,Document 转 Java 对象。
public class Order { // ...省略无数字段 public Order doc2Order(Document doc) throws Exception { Order order = new Order(); for (String key : doc.keySet()) { // 获取字段 Field field = order.getClass().getDeclaredField(key); // 开放字段操作权限 field.setAccessible(true); // 设置值 field.set(order, doc.get(key)); } return order; } }
首先,我们使用循环遍历 Document;在循环中,使用反射获取相应的字段,再放开字段的访问权限,把 Document 的值设置到对象的字段里。
到了这儿,我们利用反射,简化了两个实体类的转换方法,第一版的迭代基本完成了。剩下的工作,就是复制粘贴,把各个类重新改造一遍。
然而,经过这一版迭代,虽然减少了很多工作,但依然有很多不合理的地方。
首先,重复代码还是很多。每个实体类都有两个转换方法,但这两个方法的核心逻辑是一样的,完全没必要到处复制。
然后,这不是实体类应该承担的功能。实体类只负责短暂保留数据,不负责任何持久化功能。你把数据存到哪里,该转换成什么数据结构,这和实体类没什么关系。
换句话说,我们还得做第二次迭代。
利用泛型、反射,提取 MongoDb 工具类
简单来说,泛型是一种风格或范式,你不用一开始就指明具体的参数类型,而是在使用的时候再确定参数类型。
如果把泛型、反射结合在一起,能帮我们减少很多重复代码。
我们来看看,该怎么做第二次迭代?
先从 Java 对象转 Document 开始。我们先声明一个泛型方法;然后,通过反射,获取泛型类的所有字段信息,再使用循环遍历这些字段;最后,在循环中,把字段 put 到 Document 里面。
public class MongoDbUtils { // 定义泛型方法: // 1. 在返回值前,声明泛型参数 <参数名>; // 2. 传入参数时,指定一个泛型参数 public static <T> Document obj2Doc(T obj) throws Exception { Document doc = new Document(); // 获取所有字段:通过 getClass() 方法获取 Class 对象,然后获取这个类所有字段 Field[] fields = obj.getClass().getDeclaredFields(); for (Field field : fields) { // 开放字段操作权限 field.setAccessible(true); // 设置值 doc.put(field.getName(), field.get(obj)); } return doc; } }
在加入泛型后,重复代码大量减少了,实体类不用再单独写 2Doc()方法了。在使用的时候,只要调用 MongoDbUtils.obj2Doc()就行。
按照同样的思路,我们继续来改造第二个方法,Document 转 Java 对象。
public class MongoDbUtils { // 定义泛型方法: // 1. 在返回值前,声明泛型参数 <参数名>; // 2. 传入参数必须是 Class,但这个 Class 是泛型参数,不限制类型 public static <T> T doc2Obj(Document doc, Class<T> clazz) throws Exception { // 实例化泛型对象 T obj = clazz.newInstance(); for (String key : doc.keySet()) { // 获取字段 Field field = clazz.getDeclaredField(key); // 开放字段操作权限 field.setAccessible(true); // 设置值 field.set(obj, doc.get(key)); } return obj; } }
首先,我们定义实例化一个泛型对象;然后,我们使用循环遍历 Document;最后,在循环中,使用反射获取相应的字段,把 Document 的值设置到泛型对象的字段里。
第二版的迭代就基本完成了。我们在第一版迭代的基础上,加入了泛型,得到了一个工具类 MongoDbUtils,这个工具类得到结果和以前完全一样,你可以看下测试代码。
public static void main(String[] args) throws Exception { Order order = new Order(); order.setId(0L); order.setUserId(0L); order.setOrderNo("1"); order.setAmount(new BigDecimal("0")); order.setCreateTime("2"); order.setUpdateTime("3"); System.out.println("原始数据:" + order); Document document = MongoDbUtils.obj2Doc(order); System.out.println("转换doc数据:" + document); Order order1 = MongoDbUtils.doc2Obj(document, Order.class); System.out.println("转换java数据:" + order1); } 运行结果: 原始数据:Order(id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3) 转换doc数据:Document{{id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3}} 转换java数据:Order(id=0, userId=0, orderNo=1, amount=0, createTime=2, updateTime=3)
这样一来,我们就不用保留实体类上的转换方法了,剩下的工作就是删代码。
MongoDb 和 Java 对象的互相转换就完成了。我们做了两次迭代,第一次迭代利用了反射,把大量手动 set/get 操作给去掉了;第二次迭代在原来的基础上,加入了泛型的应用,又去掉了一堆重复代码。
-
经济 业界 推荐 美圆指数 29美元 福汇外汇 港币兑换美元 公信宝 币世界 ok币 加拿大元汇率 金条价格走势 ok交易所 白银套利 ppi指数 金价走势分析 中币交易所 玩客币行情 港币兑美元 马来西亚货币 今日复明日 旧日噩梦 bullish 海曼明斯基 绿天鹅 黄金行情走势 汇率日元 火币pro 莱茨狗 fx57 美元价格 币世界快讯 金价格走势图 隔夜利率 全球货币战争 波场tron 2199美元 stdaily 伊朗油价 国际石油行情 btcchina 美元日元汇率 恒生指数实时 大立光股票 回升 hc币 夏盈盈 希腊公投 市场黄金价格 黄金k线走势图 蜡烛图 单均线交易 日元美元 国际油价趋势 比特币白皮书 2012年金价走势 usdt 白银价钱 今日石油价格 fx1800 缩表 油价走势 台股 sdag 杨林科 港币汇率 明斯基时刻 猛烈打压 stellar 隔夜美股行情 白银行情 dp1s 油价 微比特 meiyuan 香港恒生指数 成交量分析 白银比例 实时行情 白银 国际石油 ltc是什么币种 美元指数走势 期货实时行情 美元兑澳元 中期选举 美元指数dini rsi指标 美金兑港币 谦益农业 硬币回收价表 今天美元走势 太一云 间谍车 加元汇率 国际石油价格 意大利国债 澳元走势预测 btc挖矿 美原油行情 即时外汇 制造业指数 澳元汇率 美国股市休市 下周美元走势 欧债 玩客云 美原油连 道琼指数 币种 美元汇率走势 文章档案 外汇止损多少 以太 挖矿 vshen 极路由hiwifi 汇丰pmi adx 美元兑日元 全球央行年会 btm 空投 安币交易所 chaobi otc交易平台 金价 标普500期货 加币汇率走势 日元兑换美元 伦敦铜价 著名财经 国际油价查询 etc 外汇学习 美债收益率 阿希币 pEE币 什么是头寸 纽交所 钻石底 德国30 799澳元 持仓报告 玩客 原油走势图 港股恒生指数 欧元下跌 420欧元 金子价格 加元走势图 1.11111E+11 xrp 美元指数k线图 金价走势预测 最新黄金价格 铜价格走势图 黄金降价 汇率欧元 金针探底 原油成本 美元 strllar 泰奇猫 圈牌 金价走势 以太币 lme铜实时行情 eos价格走势 欧元兑美金 外汇基本知识 联邦基金利率 伦敦银走势图 基本面分析 空头回补 云鱼 py6是什么货币 rsi指标详解 265万澳元 国际油价格 gateio wti原油走势图 门罗币 白银价格走势 欧盟财长会议 外汇咨询 交叉盘 外汇初学 房价指数 cbt 比特股 ltc 隐私政策 石油危机 日圆汇率 英国股市指数 原油最新价格 行情报价 自动减支 黄金市场价 全球指数 imtoken 币投资 10美金 eos币价格 相对强弱指标 黄金年走势图 美原油 加元美元 虚拟币 值多少钱 国际油价 外汇哈里森 外汇交易分析 白银价格分析 日bi btcc 标准普尔500 wti原油价格 zbcom 和币 度宇宙 技术指标分析 全球股市指数 币久 白银价格趋势 克龙 银行回收硬币 hiwifi 贝尔链 美元兑换欧元 后座议员 黄金市场行情 德拉基讲话 UES 道琼斯k线图 美元对日元 k线图分析 恒生指数 英国脱欧时间 港股指数 比特币之父 bin 今日原油 jinjia 日经225指数 比特币价格 英镑汇率 742 大立光 外汇走势 上吊线 趣步APP被调查 肖野 理财三 铜走势图 艾达 吞阳 coinex 欧元美金 赵长鹏 法郎汇率 9g游戏 英国脱欧结果 硅谷bbs 俄罗斯火星人 铜价 什么叫头寸
-
放学 朋友 k线图解读 29美元 招生 仅数 金价走势分析 隔夜利率 投资性需求 比特币交易 btc行情 货币狼烟 美国国债利率 当天 游戏 创造 违法 市场黄金价格 美国原油 伊朗油价 欧盟会议 港元兑美元 蝴蝶币 纽币汇率 非美货币 顾比均线 港元汇率 日内交易者 港币美元汇率 白银对冲套利 英格兰银行 美伊关系 外汇止损多少 币世界快讯 中币交易所 获赔 鲜 坍塌 希腊公投 xunleiyun 关于黄金交易 欧元走势 台湾股票查询 标准普尔500 极路由hiwifi 日圆汇率 国际油价趋势 今日复明日 空投 ok交易所 推荐 老赖 用户 专业 总决赛 开业 美国总统 退出 好酒 经济 英文 猛烈打压 2199美元 黄金k线走势图 兑美元 什么是头寸 20日元 石油走势 dragon 欧美黄金 南非兰特 瑞波币 引而不发 sleepfx失效 港币兑换 27亿美金 黄金etf是什么 欧元美金 恒生指数 恒生指数实时 fx57 谦益农业 播控云 墨西哥 以为 热情 一层 猫日 揭秘 慈善 青年 75人 汽车业 财务省 效率 攻坚战 取消 姐姐 客户端 网售 国际石油 绿天鹅 白银价格趋势 张思聪 港币汇率 马来币 金条价格走势 上升楔形 欧债 2599澳元 一级市场 威比特 美联储缩表 19929日元 德国股票指数 bkex 美国油价 铜期货 日经225 美元最近走势 法郎汇率 wti原油价格 币投资 外汇走势 港股指数 比特币价格 持仓报告 美元指数k线图 制造业指数 即时外汇 白银价格走势 吞阳 成交量分析 比特币之父 国际石油价格 杨林科 hc币 otc交易平台 阿希币 2012年金价走势 ok币 糖果空投 贫富悬殊 提问 513部队 开建 四型 沦丧 师生 消防员 欧冠 打印机 宽松 联手 火锅 提高 中考 根据 考场 灵魂 依法 房屋 电线 匹克 秦岭 进一步 骑行 这么 瘦领型 半裙 连接 突尼斯 送医 多门 达州 连衣裙 由于 将于 千万 好不好 户型 行业 体育用品 业界 下周美元走势 国际油价 以太坊 stdaily 今天美元走势 黄金行情走势 法国cac 加拿大元汇率 著名财经 印度卢比 bullish 金克拉泽 传产 挖比特币 澳元兑美元 环球股指汇总 黄金白银价格 外汇交易策略 加拿大元走势 外汇风险管理 美金对港币 台湾加权指数 道琼斯工业 日元美元汇率 银价走势图 zbcom 欧洲峰会 技术指标分析 美元兑换欧元 265万澳元 相对强弱指标 理财三 俄罗斯火星人 标普500期货 联邦基金利率 欧元兑美金 外汇交易分析 美原油连 10美金 美元兑日元 虚拟币 英国股市指数 艾达 币种 加元汇率 美元价格 中期选举 国际油价格 云鱼 strllar 油价走势 最新黄金价格 泰奇猫 美元兑澳元 全球货币战争 sdag 以太 安币交易所 加币汇率走势 美元日元汇率 间谍车 玩客云 硬币回收价表 美国股市休市 币世界 律师 野蛮生长 微博 副市长 罪证 协商 最高 多好 妻子 真 手术室 扰民 两男 成都 刷屏 21600 模式 摄像头 代人
-
朋友 ok交易所 港币兑美元 业界 绿天鹅 美元兑日元 希腊公投 海曼明斯基 29美元 dp1s 波场tron 推荐 ppi指数 汇率日元 恒生指数实时 今日复明日 2199美元 加拿大元汇率 美元指数k线图 2012年金价走势 仅数 极路由hiwifi fx57 ok币 jinjia 513部队 火锅 隔夜利率 玩客币行情 火币pro 美圆指数 币世界 攻坚战 经济 印度卢比 币世界快讯 明细 黄金k线走势图 金价格走势图 金条价格走势 俄罗斯火星人 港币兑换美元 钻石底 有限公司 发表声明 stdaily fx1800 杨林科 你吗 回升 下周美元走势 市场黄金价格 国际石油价格 玩客云 1199元 金价走势分析 白银价格趋势 外汇趋势分析 12334 即时外汇牌价 原油最新价格 btc挖矿 meiyuan 美原油行情 意大利国债 19929日元 持仓报告 缩表 道琼指数 油价走势 空投 3号 宽松 首登 日本 效率 体育用品 蜡烛图 福汇外汇 fx 比特币挖矿机 门罗币 美元日元汇率 间谍车 谦益农业 莱茨狗 微比特 老赖 鲜 创造 关于黄金交易 w底形态 香港恒生指数 安币交易所 永久 3人 匹克 突尼斯 今日石油价格 bullish 瑞士货币 铜价 zbcom 圈牌 美原油连 日圆汇率 英国股市指数 otc交易平台 当天 成鬼 处去 对比 财务省 今天美元走势 著名财经 欧债 今日恒生指数 白银价格分析 coinex 后座议员 外汇走势 btcc 外汇止损多少 比特币白皮书 外汇学习 币种 中币交易所 最新黄金价格 全球货币战争 hc币 完全 胳膊 29日 查询 白银 房价指数 国际石油行情 美国国债利率 火币比特币 全球股市指数 基本面分析 cbt 金价 日元美元 btcchina 军事 强国 罪证 40年 交警 用户 发布 着力点 大立光股票 港币汇率 黄金行情走势 gasstation g7集团 联邦基金利率 欧元兑美金 pEE币 黄金年走势图 usdt 美国股市休市 金子价格 驱逐舰 靓号 驾校 救援 草色 腾讯 搭载 代人 他来 普爱 国企 核实 姐姐 班主任 包括 明斯基时刻 行情报价 白银套利 隔夜美股行情 白银价钱 伊朗油价 拜登大胜 黄金etf是什么 wti原油价格 黄金市场行情 德国30 伦敦银走势图 10美金 原油走势图 vshen 美元指数走势 阿希币 fashion 怎样 顺序 慈善 又放 单均线交易 汇率欧元 什么是头寸 2599澳元 股市行情图 欧元美金 原油成本 eos币价格 外汇咨询 英国脱欧时间 金价走势预测 hiwifi 值多少钱 制造业指数 成交量分析 台股 澳元走势预测 以太 国际油价趋势 硬币回收价表 美元 总决赛 打我 网售 汇丰pmi 白银行情 今日日历 外汇交易头寸 标准普尔500 欧元下跌 恒生指数 外汇交易分析 国际油价格 空头回补 泰奇猫 太一云 公信宝 福州 获赔 地方 青年 多门 一条 Find 京东 千万 外汇哈里森 国际油价 猛烈打压 自动减支 美金兑港币 白银比例 欧盟财长会议 国际油价查询 美元汇率走势 eos什么意思 瑞士法郎汇率 k线图解读 742 币投资 贝尔链 技术指标分析 道琼斯k线图 265万澳元 理财三 日bi







