作者:林冠宏 / 指尖下的幽灵
掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8
博客:http://www.cnblogs.com/linguanh/
GitHub : https://github.com/af913337456/

一直以来,我都是极其反感写重复的代码,所以喜欢利用面向对象的编程属性来自己造轮,或者是二次封装。

前序

GreenDao 相信很多 Android 开发者都熟悉,不知为何物的,这里不会再介绍它,建议自行百度,介绍文很多。
前天我再次在项目中使用到 Sqlite 来做缓存,一般的代码是下面这样的。

        Entity userInfo = schema.addEntity("UserEntity");userInfo.setTableName("UserInfo");userInfo.setClassNameDao("UserDao");userInfo.setJavaPackage(entityPath);userInfo.addIdProperty().autoincrement();userInfo.addIntProperty("peerId").unique().notNull().index();userInfo.addIntProperty("gender").notNull();userInfo.addStringProperty("mainName").notNull();userInfo.addStringProperty("pinyinName").notNull();userInfo.addStringProperty("realName").notNull();userInfo.addStringProperty("avatar").notNull();userInfo.addStringProperty("phone").notNull();userInfo.addStringProperty("email").notNull();userInfo.addIntProperty("departmentId").notNull();

表结构有多少个字段就写多少行,表多了还要分开写。GreenDao本身已经是很方便了,但我觉得还是不够方便。所以有了下面的"故事"。阅读完这个"故事",从此你使用 GreenDao 真正需要你手写的将会单表是不超过10行!

思想

做过服务端开发的都知道,一般 C/S 通讯采用的数据结构是 Json,当你们公司的后端人员做好了接口后,也会提供测试接口给前端开发者,因为我的APP接口一般也是我写,所以我有这个习惯,所以,为何不采用 Json的格式来动态生成 客户端所需要的所有类。故,选择读取Json

  • GreenDao 的默认 main 函数

public class dao {public static void main(String[] args) throws Exception {/** 你的生成逻辑代码 */}}

  • 解析JSON

由于上述是 Java 程序,所以不能使用 Android 的 Json 包,我们需要下面的几个 Jar 包,他们的作用的,在 Java 程序了里面使用到 Json 的操作 API,我们可以在解析完之后就不再引用这些 Jar 包。文末会提供


dependencies {...compile files('libs/commons-beanutils-1.7.0.jar')compile files('libs/commons-collections-3.2.jar')compile files('libs/commons-lang-2.4.jar')compile files('libs/commons-logging-1.0.4.jar')compile files('libs/ezmorph-1.0.3.jar')compile files('libs/json-lib-2.2.3-jdk15.jar')
}
  • 核心函数

利用 Java 关键字 instanceof 针对从 Json 里面解析出来的 value 的不同类型来生成不同的属性,Key 做字段名称,例如 {"name":"lgh"},解析出来就是 name 作为字段名词,由于 lgh 是字符串,所以对应的是字符串类型。

private static void createTable(Schema schema, String tableName,   /** 表名 */String idName,      /** 索引 */String json         /** Json */) {Entity create = schema.addEntity(tableName);JSONObject jsonObject = JSONObject.fromObject(json);Iterator iterator = jsonObject.keys();String key;Object value;while(iterator.hasNext()){ /** 遍历 Json */key = (String) iterator.next();  /** 字段名词 */value = jsonObject.get(key);if(value instanceof Integer){if(key.equals(idName)){/** 源码限制了,主键必需是 long 类型 */create.addLongProperty(key).primaryKey().autoincrement();continue;}create.addIntProperty(key);} else if (value instanceof String){create.addStringProperty(key).notNull();} else if (value instanceof Float){create.addFloatProperty(key).notNull();} else if (value instanceof Double){create.addDoubleProperty(key).notNull();/** 其它类型,请自行模仿添加 */} else{/** 集合类型违反了表结构 */throw new IllegalFormatFlagsException("集合类型违反了表结构");}}create.setHasKeepSections(true);}

  • 一个例子

import net.sf.json.JSONObject;import java.util.IllegalFormatFlagsException;
import java.util.Iterator;import de.greenrobot.daogenerator.DaoGenerator;
import de.greenrobot.daogenerator.Entity;
import de.greenrobot.daogenerator.Schema;/**
 * 作者:林冠宏
 *
 * author: LinGuanHong ,lzq is my dear wife.
 *
 * My GitHub : https://github.com/af913337456/
 *
 * My Blog   : http://www.cnblogs.com/linguanh/
 *
 * on 2017/3/21.
 *
 *//** 创建一张表,以及它的字段逻辑,你不再需要手动一个个写,只需要传入 json */public class dao {private final static String YourOutPutDirPath = "./greendaohelper/src/main/java";private final static String YourOutPutDirName = "dao";public static void main(String[] args) throws Exception {Schema schema = new Schema(1, YourOutPutDirName);String tableJson ="{\n" +"    \"d_id\": 1278,\n" +         /** 整数类型 */"    \"d_area\": \"美国\",\n" +   /** 字符串 */"    \"d_content\": \"讲述一个军事英雄回到美国,随之也带来了很多麻烦。他将会和CTU组织合作,来救自己的命或者来拯救一起发生在美国本土的恐怖袭击的故事。\",\n" +"    \"d_directed\": \"斯蒂芬·霍普金斯 / 强·卡萨 / 尼尔森·麦科米克 / 布朗温·休斯\",\n" +"    \"d_dayhits\": \"2.3\",\n" + /** 浮点类型 */"    \"d_true_play_url\": \"xxx\"\n" +"  }";createTable(schema,"pushVideo", /** 表名 */"d_id",      /** 主键名词 */tableJson);createTable(schema,"lghTable", /** 表名 */"id",      /** 主键名词 */"{\n" +"    \"id\": 1278,\n" +         /** 整数类型 */"    \"name\": \"林冠宏\",\n" +   /** 字符串 */"    \"address\": \"阳江市\",\n" +"    \"head_url\": \"xxxxxxxx\"\n" +"  }");new DaoGenerator().generateAll(schema,YourOutPutDirPath);}/** o(n) *//** 聚合索引之类的,可以自己重载此函数 */private static void createTable(Schema schema,String tableName,String idName,String json) {...}
}

  • 运行结果

    在指定的路径/greendaohelper/src/main/java下生成文件夹dao,里面包含有

其中lghTablepushVideo 就是我们生成的 Bean 类,Dao后缀的就是数据表配置类
事实证明,完美符合理想的结果 。

拓展

上述讲述了如何自动快速地使用 Json 快速生成 Bean、表及其结构,我觉得还是不够爽,能更点地调用就更过瘾了。

  • 公共的抽象

    把 增、删、改、查,采用泛型抽象出来。

添加或更新一条

public void insertOrUpdateInfo(K entity){T userDao = getWirteDao();userDao.insertOrReplace(entity);
}

注意这个函数,它是标准的插入或更新一条数据,存在则更新,否则就是插入,两个泛型类型 KT,K 是 Bean 类,就是上面生成的, T 是dao 数据表配置类,也是上面生成的。到了这里,就是说,传入的泛型也是自动生成的,你完全不需要去手动打码。

  • 泛型约束

上面说的 T 泛型是属于 Dao 的配置类,稍作代码分析就可以看出,GreenDao 所有生成的数据表配置类都是继承于 AbstractDao 类。

所以,操作抽象类长这样

public abstract class DBInterface<K,T extends AbstractDao<K,Long>> {...
}

  • 完整例子

public abstract class DBInterface<K,T extends AbstractDao<K,Long>> {private LghLogger lghLogger = LghLogger.getLogger(DBInterface.class);private DBInit dbInit;public DBInterface(){/** 不引起 DBInit 的重复实例化 */dbInit = DBInit.instance(); /** 初始化用的,这个类在后面提供 */}protected abstract T getWirteDao();protected abstract T getReadDao();protected abstract Property getIdProperty();private void isInit(){if(dbInit.getOpenHelper() == null){throw new NullPointerException("openHelper is null!");}}/**
     * Query for readable DB
     */protected DaoSession openReadableDb() {isInit();SQLiteDatabase db = dbInit.getOpenHelper().getReadableDatabase();DaoMaster daoMaster = new DaoMaster(db);DaoSession daoSession = daoMaster.newSession();return daoSession;}/**
     * Query for writable DB
     */protected DaoSession openWritableDb(){isInit();SQLiteDatabase db = dbInit.getOpenHelper().getWritableDatabase();DaoMaster daoMaster = new DaoMaster(db);DaoSession daoSession = daoMaster.newSession();return daoSession;}/** 增 */public void insertOrUpdateInfo(K entity){T userDao = getWirteDao();userDao.insertOrReplace(entity);}public void batchInsertOrUpdateAllInfo(List<K> entityList){if(entityList.size() <=0 ){lghLogger.d("本地数据库插入用户信息失败,条数是 0 ");return ;}T userDao = getWirteDao();userDao.insertOrReplaceInTx(entityList);}/** 删 */public void deleteOneById(int id){T userDao = getWirteDao();DeleteQuery<K> bd = userDao.queryBuilder().where(getIdProperty().eq(id)).buildDelete();bd.executeDeleteWithoutDetachingEntities();}public void deleteAllBeans(){T userDao =  getWirteDao();DeleteQuery<K> bd = userDao.queryBuilder().buildDelete();bd.executeDeleteWithoutDetachingEntities();}/** 改 *//** 在查里面,因为本身就是 insertOrUpdate *//** 查,加入了模糊查找 */public K getBeanById(int id){T dao = getReadDao();return dao.queryBuilder().where(getIdProperty().eq(id)).unique();}public K getBeanWithLike(Property property,String what){T dao = getReadDao();return dao.queryBuilder().where(property.like("%"+what+"%")).unique();}public List<K> loadAllBeans(){T dao = getReadDao();/** 倒叙 */return dao.queryBuilder().orderDesc(getIdProperty()).list();}public List<K> loadAllBeansWithLike(Property property, String what){T dao = getReadDao();return dao.queryBuilder().where(property.like("%"+what+"%")).orderAsc(getIdProperty()).list();}}

  • DBInit.java 负责初始化,静态内部类单例,避免了反复创建对象

    public class DBInit {private LghLogger lghLogger = LghLogger.getLogger(DBInit.class);private int loginUserId = 0;private DaoMaster.DevOpenHelper openHelper;public static DBInit instance(){return DBHelper.dbInit;
    }/** 私有 */
    private DBInit(){lghLogger.d("初始化 dbinit");initDbHelp(LghApp.context,1); /** 可以自己迁移初始化位置 */
    }public DaoMaster.DevOpenHelper getOpenHelper(){return openHelper;
    }private static class DBHelper{private static DBInit dbInit = new DBInit();}/**  十分建议使用 Application 的 context
      *  支持用用户的 ID 区分数据表
      *  */
    public void initDbHelp(Context ctx, int loginId){if(ctx == null || loginId <=0 ){throw  new RuntimeException("#DBInterface# init DB exception!");}/** 切换用户的时候, openHelper 不是 null */String DBName = "lgh_"+loginId+".db";if(openHelper!=null){/** 判断下 db name 是不是一样的,不是一样就重置 */String dbNameTemp = openHelper.getDatabaseName().trim();if(dbNameTemp.equals(DBName)){lghLogger.d("相同的用户,不用重新初始化本地 DB");return;}else{lghLogger.d("不是相同的用户,需要重新初始化本地 DB");openHelper.close();openHelper = null;}}if(loginUserId !=loginId ){loginUserId = loginId;close();lghLogger.d("DB init,loginId: "+loginId);DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(ctx, DBName, null);this.openHelper = helper;}else{lghLogger.d("DB init,failed: "+loginId);}
    }private void close() {if(openHelper !=null) {lghLogger.d("关闭数据库接口类");openHelper.close();openHelper = null;loginUserId = 0;}
    }
    }

  • 使用

有了上面的准备,就可以使用了,正在需要自己动手的代码几乎没有。下面我们建一个操作类型的子类VideoInfoDbCache,集成于 DBInterface,重写完三个抽象函数后,就是下面这样。

public class VideoInfoDbCacheextendsDBInterface<pushVideo, pushVideoDao> {@Overrideprotected pushVideoDao getWirteDao() {return openWritableDb().getPushVideoDao(); /** 该函数由 GreenDao 提供,不用自己编写 */}@Overrideprotected pushVideoDao getReadDao() {return openReadableDb().getPushVideoDao(); /** 该函数由 GreenDao 提供,不用自己编写 */}@Overrideprotected Property getIdProperty() {return pushVideoDao.Properties.D_id;       /** 自定义的拓展,这里获取了一般的 id 作为主属性 */}
}

现在我们看看 MainActivity 里面的使用。直接采用匿名对象,直接 new,直接用。

public class MainActivity extends AppCompatActivity {List<pushVideo> list;List<lghTable>  lghList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);...list = new VideoInfoDbCache().loadAllBeans();list = new VideoInfoDbCache().loadAllBeans();list = new VideoInfoDbCache().loadAllBeans();list = new VideoInfoDbCache().loadAllBeans();list = new VideoInfoDbCache().loadAllBeans();list = new VideoInfoDbCache().loadAllBeans();lghList = new LghTableDbCache().loadAllBeans();lghList = new LghTableDbCache().loadAllBeansWithLike(lghTableDao.Properties.Name,"林冠宏");...}
}

现在,够快了吧?还不够?您请留言,我补刀。

开源地址 https://github.com/af913337456/GreenDaoHelper/
提示:在编译APP的时候,最好把上述的 Java 程序的 json jar 包全部不再引用,而且注释 dao.java 文件,然后删除一次 greenDaoHelper library下的build文件夹,即可!

如果您认为这篇文章还不错或者有所收获,您可以通过扫描一下下面的支付宝二维码 打赏我一杯咖啡【物质支持】,也可以点击右下角的【推荐】按钮【精神支持】,因为这两种支持都是我继续写作,分享的最大动力


GreenDao 工具类 --- 使用 Json 快速生成 Bean、表及其结构,炒鸡快!相关推荐

  1. Unity 工具类 之 简单快速 获取当前所在位置,所在城市,经纬度等

    Unity  工具类 之 简单快速 获取当前所在位置,所在城市,经纬度等 目录 Unity  工具类 之 简单快速 获取当前所在位置,所在城市,经纬度等 一.方法提要: 二.使用注意: 三.json ...

  2. [工具库]JOJSONBuilder工具类——一键把多个bean对象数据转换为JSON格式数据

    本人大四即将毕业的准程序员(JavaSE.JavaEE.android等)一枚,小项目也做过一点,于是乎一时兴起就写了一些工具. 我会在本博客中陆续发布一些平时可能会用到的工具. 代码质量可能不是很好 ...

  3. java验证码画布类型,【Java工具类】使用Kaptcha生成验证码写回页面中

    1. 导入依赖 导入kaptcha依赖: com.github.penggle kaptcha 2.3.2 2. 编写配置类: @Configuration public class KaptchaC ...

  4. [工具库]JOXMLBuilder工具类——一键把多个bean对象数据转换为XML格式数据

    本人大四即将毕业的准程序员(JavaSE.JavaEE.android等)一枚,小项目也做过一点,于是乎一时兴起就写了一些工具. 我会在本博客中陆续发布一些平时可能会用到的工具. 代码质量可能不是很好 ...

  5. JSON格式转换工具类、json转map

    这里推荐两个JSON转换工具类 阿里巴巴的FastJSON maven仓库地址 可以参考我这篇文章 或者这篇文章 Jackson工具类 这个参考我这篇文章 json格式数据转换成Map 使用阿里巴巴的 ...

  6. jxl 新版电子表格_Android使用jxl快速生成Excel表

    前言 在Android开发时,有些时候需要把app中List集合数据,导出到Excel表中,方便进一步操作.Android可以使用jxl或poi来导出Excel,关于jxl和poi的比较网上有很多说法 ...

  7. 如何快速生成数据库表结构以及数据字典

    快速生成数据字典 1 简述 在从业过程中,经常遇到一些先行后设计.先开发再总结的老旧项目:当接手一个老旧项目时,想要快速了解项目,从数据库设计必定是最优选择:有经验的开发人员,从数据库的表设计.字段设 ...

  8. 常用工具类之使用kaptcha生成验证码

    验证码的作用 防止恶意破解密码.刷票.论坛灌水.刷页. 有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登录尝试,实际上使用验证码是现在很多网站通行的方式(比如招商银行的网上个人银 ...

  9. 【实体类】如何快速生成实体类?

    新建一个实体类: Person.java public class Person {private String aString;private String bString;private Stri ...

最新文章

  1. centOS7.4服务器 yum安装 搭建lamp环境
  2. C#精髓【月儿原创】第一讲 使用垃圾回收器
  3. 从BERT、XLNet到MPNet,细看NLP预训练模型发展变迁史
  4. OFDM专题之子载波间干扰问题(一)
  5. spark sql 上个月_SPARK-SQL内置函数之时间日期类
  6. 从python中的列表中获取唯一值[重复]
  7. linux shell 判断字符串是否为数字
  8. java hashtable排序_java中哈希表中有迭代器模式的实现,可以认为其是顺序表吗?...
  9. 刚毕业的我,参与了一场大厂之间的争夺之战
  10. 面向对象封装继承多态五大基本原则魔法方法反射
  11. Windows server 2019 - Raid5 搭建+测试
  12. javascript闭包(转)
  13. qtcreator安装及配置
  14. coj #10066新的开始(最小生成树)
  15. ceph存储 FC HBA、iSCSI HBA、以太网卡3者区别
  16. HBuilderx连接微信开发者工具
  17. JVM之垃圾回收 II ——方法区和堆区的垃圾回收、STW
  18. AI最全数据集汇总:语音、歌声、音乐、图片、视频等领域开源数据集链接汇总
  19. weblogic portal 11g 集群
  20. 打印后台程序没有运行,怎么办?

热门文章

  1. Python零基础入门(零)——Anaconda安装(python安装)和使用
  2. java弹出提示框jo类_Java JobMeta.getJobLogTable方法代码示例
  3. MATLAB 读取 各类文件
  4. winx修改计算机用户名,怎么修改我的电脑用户名win10
  5. 华为nova2s云相册在哪里_华为反人类的用户体验
  6. android webview video标签,Android WebView支持html5 video标签
  7. 小于等于0_从0开始学ARMARM汇编指令其实很简单
  8. iPhone4S安装Linux系统,别失望太早 iPhone 4S其实就是iPhone 5
  9. python 直线虚线_python – matplotlib中的虚线而不是缺失值
  10. 最简单的爬虫代码 python_最精简的爬虫 --仅需4行代码(python)