package com.yanzuoguang.dao.impl; import com.yanzuoguang.dao.BaseDao; import com.yanzuoguang.dao.DaoConst; import com.yanzuoguang.dao.QueryPara; import com.yanzuoguang.db.DbExecute; import com.yanzuoguang.util.base.ObjectHelper; import com.yanzuoguang.util.exception.CodeException; import com.yanzuoguang.util.helper.DateHelper; import com.yanzuoguang.util.helper.StringHelper; import com.yanzuoguang.util.vo.*; import java.util.*; /** * 数据库操作的基本工具类 * 1. 实现了基本的增删该查 * 2. 实现了统计的增肌和修改 * 3. 实现了一定功能的基本验证,验证数据是否存在 * 4. 数据主键的获取等功能。 * 5. 获取自增等功能 * * @author 颜佐光 */ public abstract class BaseDaoImpl extends BaseDaoSql implements BaseDao { /** * 构造函数 */ public BaseDaoImpl() { } public BaseDaoImpl(DbExecute db, TableSqlCache table) { super(db, table); } /** * 获取当前主键 * * @return */ private String getIdentity() { return StringHelper.toString(this.getDb().queryCell(this.getClass(), "GET_KEY", "SELECT @@IDENTITY")); } /** * 获取主键名称 * * @return 获取主键名称 */ protected String getKey() { if (this.table == null) { throw new RuntimeException("类" + this.getClass().getName() + "未发现表结构"); } return this.table.getTable().getKeyName(); } /** * 获取主键值 * * @param model 需要获取主键的实体 * @return */ protected String getKeyString(Object model) { String keyField = this.getKey(); Object key = ObjectHelper.get(model, keyField); if (StringHelper.isEmpty(key)) { return ""; } String keyString = key.toString(); if (DaoConst.ZERO.equals(keyString)) { keyString = ""; } return keyString; } /** * 设置主键值 * * @param model 需要设置的实体 * @param key 需要设置的主键值 */ protected void setKeyString(Object model, String key) { String keyField = this.getKey(); ObjectHelper.set(model, keyField, key); } /** * 根据输入参数来获取主键 * * @param from 可以为实体或字符串。为实体时必须包含 主键 字段 或者 id 字段。 * @return */ protected String getInputKey(Object from) { String key; if (from != null && from.getClass() == String.class) { key = StringHelper.toString(from); } else { key = this.getKeyString(from); } if (StringHelper.isEmpty(key)) { key = StringHelper.toString(ObjectHelper.get(from, "id")); } if (StringHelper.isEmpty(key)) { key = ""; } return key; } protected String createReplace(String sqlName, Object model) { // 判断主键是字符串和需要生成主键 boolean isKeyString = this.table.getTable().getKeyType() == String.class; String keyString = this.getKeyString(model); // 生成主键 if (StringHelper.isEmpty(keyString) && isKeyString) { keyString = StringHelper.getNewID(); this.setKeyString(model, keyString); } // 检测数据合法性 this.check(DaoConst.OPERATOR_TYPE_CREATE, keyString, model); // 执行创建的SQL语句 int ret = updateSql(sqlName, model); // 判断是否需要获取自增编号(主键为整形) if (StringHelper.isEmpty(keyString) && !isKeyString) { keyString = this.getIdentity(); this.setKeyString(model, keyString); } // 最终处理 this.created(model); // 返回执行结果 String retVal = ret > 0 ? keyString : ""; return retVal; } /** * 创建数据,当不传入了主键时,则会自动生成主键,传入时不会生成。 * * @param model 需要创建的数据 * @return 创建的主键编号, 创建成功,返回主键,否则为空 */ @Override public String create(Object model) { return createReplace(DaoConst.CREATE, model); } /** * 创建数据,当不传入了主键时,则会自动生成主键,传入时不会生成。 * * @param model 需要创建的数据 * @return 创建的主键编号, 创建成功,返回主键,否则为空 */ @Override public String replace(Object model) { return createReplace(DaoConst.REPLACE, model); } /** * 修改数据 * * @param model 需要修改的数据 * @return 删除的主键编号 */ @Override public String update(Object model) { String keyString = this.getKeyString(model); if (StringHelper.isEmpty(keyString)) { throw new RuntimeException("表" + this.table.getTable().getName() + "主键值为空时不能更新"); } this.check(DaoConst.OPERATOR_TYPE_UPDATE, keyString, model); SqlData sqlData = this.getSql(DaoConst.UPDATE); int ret = updateSql(sqlData, model); if (ret == 0) { throw new RuntimeException("修改失败,请确认是否被其他人修改,版本号传入是否正确"); } String retVal = ret > 0 ? keyString : ""; return retVal; } /** * 保存数据 * * @param model 需要保存的数据 * @return 保存的主键编号 */ @Override public String save(Object model) { String id = this.getKeyString(model); if (StringHelper.isEmpty(id)) { return create(model); } else { return update(model); } } /** * 删除数据 * * @param model 需要删除的数据 * @return 删除的主键编号 */ @Override public int remove(Object model) { // 获取来源主键 Object from = model; String keyString = getInputKey(from); // 调用删除日志 this.check(DaoConst.OPERATOR_TYPE_REMOVE, keyString, from); // 当主键存在值时,直接通过主键删除 if (!StringHelper.isEmpty(keyString)) { // 去掉其他非主键的属性 from = new HashMap<String, Object>(DaoConst.COLLECTION_INIT_SIZE); this.setKeyString(from, keyString); } // 处理来源值 for (TableFieldVo fieldVo : this.table.getTable().getRemoveUpdate()) { Object fromValue = ObjectHelper.get(model, fieldVo.inputName); ObjectHelper.set(from, fieldVo.inputName, fromValue); } // 调用删除语句 SqlData sqlData = this.getSql(DaoConst.REMOVE); return updateSql(sqlData, from); } /** * 创建数据,当不传入了主键时,则会自动生成主键,传入时不会生成。 * * @param model 需要创建的数据 * @return 创建的主键编号 */ @Override public List<String> createList(Collection model) { List<String> ret = new ArrayList<>(); for (Object item : model) { ret.add(this.create(item)); } return ret; } /** * 创建数据,当不传入了主键时,则会自动生成主键,传入时不会生成。 * * @param model 需要创建的数据 * @return 创建的主键编号 */ @Override public List<String> createArray(Object... model) { return createList(Arrays.asList(model)); } /** * 修改数据 * * @param model 需要修改的数据 * @return 删除的主键编号 */ @Override public List<String> updateList(Collection model) { List<String> ret = new ArrayList<>(); for (Object item : model) { ret.add(this.update(item)); } return ret; } /** * 创建数据,当不传入了主键时,则会自动生成主键,传入时不会生成。 * * @param model 需要创建的数据 * @return 创建的主键编号 */ @Override public List<String> replaceArray(Object... model) { return replaceList(Arrays.asList(model)); } /** * 修改数据 * * @param model 需要修改的数据 * @return 删除的主键编号 */ @Override public List<String> replaceList(Collection model) { List<String> ret = new ArrayList<>(); for (Object item : model) { ret.add(this.replace(item)); } return ret; } /** * 修改数据 * * @param model 需要修改的数据 * @return 删除的主键编号 */ @Override public List<String> updateArray(Object... model) { return updateList(Arrays.asList(model)); } /** * 保存数据,有主键时修改,无主键时创建 * * @param model 需要保存的数据 * @return 保存的主键编号 */ @Override public List<String> saveList(Collection model) { List<String> ret = new ArrayList<>(); for (Object item : model) { ret.add(this.save(item)); } return ret; } /** * 保存数据,有主键时修改,无主键时创建 * * @param model 需要保存的数据 * @return 保存的主键编号 */ @Override public List<String> saveArray(Object... model) { return saveList(Arrays.asList(model)); } /** * 删除数据,可以用于父子表删除,如通过订单删除游客信息 visitorDao.remove({orderId:1}); * int field; * * @param model 需要删除的数据,可以是主键字符串(Int),或者是包含主键的实体,或者是包含其他非主键的实体完全匹配. * @return 删除的记录数量 */ @Override public int removeList(Collection model) { int ret = 0; for (Object item : model) { ret += this.remove(item); } return ret; } /** * 删除数据,可以用于父子表删除,如通过订单删除游客信息 visitorDao.remove({orderId:1}); * int field; * * @param model 需要删除的数据,可以是主键字符串(Int),或者是包含主键的实体,或者是包含其他非主键的实体完全匹配. * @return 删除的记录数量 */ @Override public int removeArray(Object... model) { return removeList(Arrays.asList(model)); } /** * 检测数据 * * @param operatorType 操作方法类型 * @param keyString 主键 * @param model 需要检测的数据 */ protected void check(int operatorType, String keyString, Object model) { if (operatorType == DaoConst.OPERATOR_TYPE_CREATE || operatorType == DaoConst.OPERATOR_TYPE_UPDATE) { if (model instanceof InitDao) { InitDao to = (InitDao) model; to.init(); } List<SqlData> sqlArray = this.table.getSqlType(DaoConst.SQL_TYPE_EXISTS); if (sqlArray != null) { for (SqlData sql : sqlArray) { this.checkExist(sql.getName(), model, String.format("%s已经存在", sql.getName())); } } } else if (operatorType == DaoConst.OPERATOR_TYPE_REMOVE) { if (model instanceof InitRemoveDao) { InitRemoveDao to = (InitRemoveDao) model; to.initRemove(); } } } /** * 获取请求对象爱 * * @param model 来源对象 * @return */ protected Object getLoadFrom(Object model, QueryPara queryPara) { if (queryPara != null && queryPara.isFullCond()) { return model; } // 对查询条件进行初始化 if (model instanceof InitDaoQuery) { ((InitDaoQuery) model).initCond(); } // 获取来源主键 Object from = model; String key = this.getInputKey(from); // 当主键存在时,只通过主键加载 if (!StringHelper.isEmpty(key)) { from = new HashMap<String, Object>(DaoConst.COLLECTION_INIT_SIZE); this.setKeyString(from, key); } return from; } private <T extends Object> void checkLoadResult(T toItem, List<T> tos) { // 判断来源主键是否存在,不存在则获取加载后的主键 if (toItem != null) { String key = this.getKeyString(toItem); check(DaoConst.OPERATOR_TYPE_LOAD, key, toItem); } if (tos != null) { for (T item : tos) { String key = this.getKeyString(item); check(DaoConst.OPERATOR_TYPE_LOAD, key, item); } } } /** * 加载数据 * * @param model 加载数据的请求参数 * @param resultClass 需要加载的数据的类型 * @param queryPara 查询参数 * @param <T> 返回数据的类型 * @return 需要返回的数据 */ @Override public <T extends Object> T load(Object model, Class<T> resultClass, QueryPara queryPara) { // 获取来源主键 Object from = this.getLoadFrom(model, queryPara); // 通过传入数据进行加载 T to = this.queryFirst(resultClass, DaoConst.LOAD, from, queryPara); if (to == null) { return null; } // 判断来源主键是否存在,不存在则获取加载后的主键 checkLoadResult(to, null); return to; } /** * 加载数据 * * @param model 加载数据的请求参数 * @param resultClass 需要加载的数据的类型 * @param <T> 返回数据的类型 * @return 需要返回的数据 */ @Override public <T extends Object> T load(Object model, Class<T> resultClass) { return this.load(model, resultClass, null); } /** * 加载数据 * * @param model 加载数据的请求参数 * @param resultClass 需要加载的数据的类型 * @param queryPara 查询参数 * @param <T> 返回数据的类型 * @return 需要返回的数据 */ @Override public <T extends Object> List<T> loadList(Object model, Class<T> resultClass, QueryPara queryPara) { // 获取来源主键 Object from = this.getLoadFrom(model, queryPara); // 通过传入数据进行加载 List<T> to = this.query(resultClass, DaoConst.LOAD, from, queryPara); if (to == null || to.size() == 0) { return new ArrayList<>(); } checkLoadResult(null, to); return to; } /** * 加载数据 * * @param model 加载数据的请求参数 * @param resultClass 需要加载的数据的类型 * @param <T> 返回数据的类型 * @return 需要返回的数据 */ @Override public <T extends Object> List<T> loadList(Object model, Class<T> resultClass) { return this.loadList(model, resultClass, null); } /** * 加载分页数据 * * @param model 加载数据的请求参数 * @param resultClass 需要加载的数据的类型 * @param <T> 返回数据的类型 * @return 需要返回的数据 */ @Override public <T extends Object> PageSizeData<T> loadPage(PageSizeReqVo model, Class<T> resultClass) { return this.loadPage(model, model, resultClass, null); } /** * 加载分页数据 * * @param model 加载数据的请求参数 * @param resultClass 需要加载的数据的类型 * @param queryPara 查询参数 * @param <T> 返回数据的类型 * @return 需要返回的数据 */ @Override public <T extends Object> PageSizeData<T> loadPage(PageSizeReqVo model, Class<T> resultClass, QueryPara queryPara) { return this.loadPage(model, model, resultClass, queryPara); } /** * 加载分页数据 * * @param model 加载数据的请求参数 * @param resultClass 需要加载的数据的类型 * @param <T> 返回数据的类型 * @return 需要返回的数据 */ @Override public <T extends Object> PageSizeData<T> loadPage(PageSizeReqVo pageReq, Object model, Class<T> resultClass) { return this.loadPage(pageReq, model, resultClass, null); } /** * 加载分页数据 * * @param model 加载数据的请求参数 * @param resultClass 需要加载的数据的类型 * @param queryPara 查询参数 * @param <T> 返回数据的类型 * @return 需要返回的数据 */ @Override public <T extends Object> PageSizeData<T> loadPage(PageSizeReqVo pageReq, Object model, Class<T> resultClass, QueryPara queryPara) { // 获取来源主键 Object from = this.getLoadFrom(model, queryPara); // 通过传入数据进行加载 PageSizeData<T> to = this.queryPage(resultClass, pageReq, DaoConst.LOAD, from, queryPara); if (to == null || to.getPageTotal() == 0) { return to; } // 判断来源主键是否存在,不存在则获取加载后的主键 checkLoadResult(null, to.getList()); return to; } /** * 加载分页数据 * * @param model 加载数据的请求参数 * @param resultClass 需要加载的数据的类型 * @param <T> 返回数据的类型 * @return 需要返回的数据 */ @Override public <T extends Object> List<T> loadPageData(PageSizeReqVo model, Class<T> resultClass) { return this.loadPageData(model, model, resultClass, null); } /** * 加载分页数据 * * @param model 加载数据的请求参数 * @param resultClass 需要加载的数据的类型 * @param queryPara 查询参数 * @param <T> 返回数据的类型 * @return 需要返回的数据 */ @Override public <T extends Object> List<T> loadPageData(PageSizeReqVo model, Class<T> resultClass, QueryPara queryPara) { return this.loadPageData(model, model, resultClass, queryPara); } /** * 加载分页数据 * * @param model 加载数据的请求参数 * @param resultClass 需要加载的数据的类型 * @param <T> 返回数据的类型 * @return 需要返回的数据 */ @Override public <T extends Object> List<T> loadPageData(PageSizeReqVo pageReq, Object model, Class<T> resultClass) { return this.loadPageData(pageReq, model, resultClass, null); } /** * 加载分页数据 * * @param model 加载数据的请求参数 * @param resultClass 需要加载的数据的类型 * @param queryPara 查询参数 * @param <T> 返回数据的类型 * @return 需要返回的数据 */ @Override public <T extends Object> List<T> loadPageData(PageSizeReqVo pageReq, Object model, Class<T> resultClass, QueryPara queryPara) { // 获取来源主键 Object from = this.getLoadFrom(model, queryPara); // 通过传入数据进行加载 List<T> to = this.queryPageData(resultClass, pageReq, DaoConst.LOAD, from, queryPara); if (to == null) { return new ArrayList<>(); } // 判断来源主键是否存在,不存在则获取加载后的主键 checkLoadResult(null, to); return to; } /** * 设置MD5主键 * * @param model * @param <T> */ @Override public <T extends Object> String setGroupId(T model) { // 判断前台实体 if (model == null) { return StringHelper.EMPTY; } String md5Field = this.table.getTable().getMD5KeyName(); String md5From = StringHelper.isEmpty(md5Field) ? StringHelper.EMPTY : ObjectHelper.getString(model, md5Field); // 获取前台分组的MD5标识 String md5 = md5From; if (StringHelper.isEmpty(md5)) { md5 = this.getMd5(DaoConst.GROUP_QUERY, model); } if (!StringHelper.isEmpty(md5Field)) { ObjectHelper.set(model, md5Field, md5); } if (this.table.getTable().getKeyType() == String.class) { this.setKeyString(model, md5); } return md5; } /** * 添加统计数据 * * @param cls 类型 * @param model 实体 * @param <T> 泛型类型 * @return 增加统计的数据编号 */ @Override public <T extends Object> String addGroup(Class<T> cls, T model) { this.setGroupId(model); // 判断前台实体 if (model == null) { return ""; } // 获取标识的实体 T from; String md5Field = this.table.getTable().getMD5KeyName(); if (this.table.getTable().getKeyType() == String.class) { from = model; } else if (!StringHelper.isEmpty(md5Field)) { Map<String, Object> map = new HashMap<>(DaoConst.COLLECTION_INIT_SIZE); map.put(md5Field, ObjectHelper.get(model, md5Field)); from = this.load(map, cls); } else { from = this.queryFirst(cls, DaoConst.GROUP_QUERY, model); } // 当没有存在,则创建,否则 UpdateAdd if (from == null) { return this.create(model); } else { // 获取后台的编号,并写入到前台传入的数据上面 String keyField = this.getKey(); Object key = ObjectHelper.get(from, keyField); ObjectHelper.set(model, keyField, key); if (model instanceof InitDao) { ((InitDao) model).init(); } // 执行更新SQL语句 SqlData sqlData = this.getSql(DaoConst.GROUP_ADD); int ret = this.updateSql(sqlData, model); if (ret < 1) { return this.create(model); } else { return key.toString(); } } } /** * 添加统计数组 * * @param cls 类型 * @param models 请求实体 * @param <T> 泛型数据 * @return 返回列表 */ @Override public <T extends Object> List<String> addGroupList(Class<T> cls, List<T> models) { List<String> ret = new ArrayList<>(); for (T model : models) { ret.add(this.addGroup(cls, model)); } return ret; } /** * 添加统计数组 * * @param cls 类型 * @param models 请求实体 * @param <T> 泛型数据 * @return 返回列表 */ @Override public <T extends Object> List<String> addGroupArray(Class<T> cls, T... models) { return this.addGroupList(cls, Arrays.asList(models)); } /** * 根据SQL语句名称和实体获取MD5值 * * @param sqlName SQL语句名称 * @param model 获取加密之后的实体 * @param <T> 获取的类型 * @return 获取加密之后的值 */ protected <T extends Object> String getMd5(String sqlName, T model) { SqlData sql = this.getSql(sqlName); StringBuilder sb = new StringBuilder(); String date = StringHelper.EMPTY; for (SqlDataField field : sql.getSqlDataFields()) { List<Object> values = field.getCond().getValues(model); for (Object item : values) { if (sb.length() > 0) { sb.append(":"); } sb.append(item); if (StringHelper.isEmpty(date)) { String itemString = String.valueOf(item); if (item instanceof Date) { date = DateHelper.getDateTimeString((Date) item); } else if (DateHelper.isDateFormat(itemString)) { date = itemString; } } } } if (StringHelper.isEmpty(date)) { return StringHelper.md5(sb.toString()); } else { return StringHelper.getNewMD5Id(DateHelper.getDateTime(date), sb.toString()); } } /** * 添加统计数据列表 * * @param sqlName 需要执行的SQL语句名称 * @param model 需要执行的SQL语句的实体 * @return */ protected int addGroupList(String sqlName, Object model) { this.updateSql(sqlName + "_GroupInit", model); return this.updateSql(sqlName + "_GroupAdd", model); } /*** * 查询数据是否存在,当存在时修改,否则增加 * @param cls 需要创建的实体的类型 * @param requests 前台参数,不能包含主键以及其他不需要修改的字段 * @return 保存成功,返回保存的ID,保存失败,返回空值 */ @Override public <T extends Object> List<String> saveByLoadArray(Class<T> cls, Object... requests) { return this.saveByLoadList(cls, Arrays.asList(requests)); } /*** * 查询数据是否存在,当存在时修改,否则增加 * @param cls 需要创建的实体的类型 * @param requests 前台参数,不能包含主键以及其他不需要修改的字段 * @return 保存成功,返回保存的ID,保存失败,返回空值 */ @Override public <T extends Object> List<String> saveByLoadList(Class<T> cls, List requests) { List<String> ret = new ArrayList<>(); if (requests != null) { for (Object model : requests) { ret.add(this.saveByLoad(cls, model)); } } return ret; } /*** * 查询数据是否存在,当存在时修改,否则增加 * @param cls 需要创建的实体的类型 * @param request 前台参数,不能包含主键以及其他不需要修改的字段 * @return 保存成功,返回保存的ID,保存失败,返回空值 */ @Override public <T extends Object> String saveByLoad(Class<T> cls, Object request) { String key = this.getInputKey(request); T from = null; if (!StringHelper.isEmpty(key)) { from = this.load(request, cls); return saveFromCreate(cls, from, request); } return saveFromCreate(cls, from, request); } /** * 根据from来创建对象,对象存在时修改,对象不存在时创建 * * @param cls 自动创建的对象类型 * @param from 需要修改的对象,当该对象不存在时创建数据 * @param request 需要创建的对象 * @param <T> 创建的数据类型 * @return 创建成功的编号 */ protected <T extends Object> String saveFromCreate(Class<T> cls, T from, Object request) { if (from == null) { try { from = cls.newInstance(); } catch (Exception ex) { throw new RuntimeException("创建对象" + cls.getName() + "出错", ex); } ObjectHelper.writeWithFrom(from, request); return this.create(from); } else { TableStruct tableStruct = this.table.getTable(); // 写入历史版本号 TableFieldVo version = tableStruct.getVersion(); if (version != null) { Object hisVersion = ObjectHelper.get(from, version.inputName); ObjectHelper.writeWithFrom(from, request); ObjectHelper.set(from, version.inputName, hisVersion); } else { ObjectHelper.writeWithFrom(from, request); } return this.update(from); } } /*** * 查询数据是否存在,当存在时修改,否则增加 * @param cls 需要创建的实体的类型 * @param sqlName 执行的SQL语句 * @param request 前台参数,不能包含主键以及其他不需要修改的字段 * @return 保存成功,返回保存的ID,保存失败,返回空值 */ public <T extends Object> String saveWith(Class<T> cls, String sqlName, Object request) { if (request instanceof InitDao) { ((InitDao) request).init(); } TableStruct tableStruct = this.table.getTable(); // 获取所有条件字段 MapRow condition = new MapRow(); List<TableFieldVo> fields = tableStruct.getFields(DaoConst.FIELD_SAVE_WITH); for (TableFieldVo field : fields) { condition.put(field.inputName, ObjectHelper.get(request, field.inputName)); } // 查询历史数据 T from = this.queryFirst(cls, sqlName, condition); return saveFromCreate(cls, from, request); } /** * 创建成功后的处理 * * @param model 创建的实体数据 */ protected void created(Object model) { } /** * 执行是否存在的SQL语句 * * @param sqlName SQL语句名称 * @param model 实体 * @param msg 消息 */ protected void checkExist(String sqlName, Object model, String msg) { MapRow row = this.queryFirst(sqlName, model); if (row != null) { throw new CodeException(msg); } } /** * 对数据据进行集合操作 * * @param daoVo * @return */ @Override public List<String> dataDao(DataDaoVo daoVo) { List<String> res = new ArrayList<>(); res.addAll(this.createList(daoVo.getCreates())); res.addAll(this.updateList(daoVo.getUpdates())); this.removeList(daoVo.getRemoves()); return res; } }