DbTableServiceImpl.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. package jnpf.base.service.impl;
  2. import com.google.common.collect.ImmutableMap;
  3. import jnpf.base.Page;
  4. import jnpf.base.Pagination;
  5. import jnpf.base.service.DbLinkService;
  6. import jnpf.base.service.DbTableService;
  7. import jnpf.base.util.dbutil.TableUtil;
  8. import jnpf.constant.MsgCode;
  9. import jnpf.database.datatype.db.DtDMEnum;
  10. import jnpf.database.datatype.db.interfaces.DtInterface;
  11. import jnpf.database.datatype.viewshow.ViewDataTypeEnum;
  12. import jnpf.database.datatype.viewshow.constant.DtViewConst;
  13. import jnpf.database.enums.DbAliasEnum;
  14. import jnpf.database.model.dbfield.DbFieldModel;
  15. import jnpf.database.model.dbtable.DbTableFieldModel;
  16. import jnpf.database.model.dto.PrepSqlDTO;
  17. import jnpf.database.model.entity.DbLinkEntity;
  18. import jnpf.database.model.page.DbTableDataForm;
  19. import jnpf.database.model.page.JdbcPageMod;
  20. import jnpf.database.source.DbBase;
  21. import jnpf.database.source.impl.DbPostgre;
  22. import jnpf.database.sql.enums.base.SqlComEnum;
  23. import jnpf.database.sql.util.SqlFastUtil;
  24. import jnpf.database.sql.util.SqlFrameUtil;
  25. import jnpf.database.util.DbTypeUtil;
  26. import jnpf.database.util.JdbcUtil;
  27. import jnpf.database.util.NotTenantPluginHolder;
  28. import jnpf.exception.DataException;
  29. import jnpf.util.StringUtil;
  30. import lombok.extern.slf4j.Slf4j;
  31. import org.springframework.beans.factory.annotation.Autowired;
  32. import org.springframework.stereotype.Service;
  33. import java.lang.reflect.Method;
  34. import java.util.ArrayList;
  35. import java.util.List;
  36. import java.util.Map;
  37. import java.util.Optional;
  38. import java.util.stream.Collectors;
  39. /**
  40. * 数据管理
  41. *
  42. * @author JNPF开发平台组
  43. * @version V3.1.0
  44. * @copyright 引迈信息技术有限公司
  45. * @date 2019年9月27日 上午9:18
  46. */
  47. @Slf4j
  48. @Service
  49. public class DbTableServiceImpl implements DbTableService {
  50. @Autowired
  51. private DbLinkService dblinkService;
  52. @Autowired
  53. private DbTableService dbTableService;
  54. @Override
  55. public List<DbTableFieldModel> getList(String dbLinkId, String methodName) throws Exception {
  56. DbLinkEntity dbLinkEntity = dblinkService.getResource(dbLinkId);
  57. return SqlFastUtil.getTableList(dbLinkEntity, methodName);
  58. }
  59. @Override
  60. public List<DbTableFieldModel> getListPage(String dbLinkId, Page page) throws Exception {
  61. List<DbTableFieldModel> list = getList(dbLinkId, DbAliasEnum.TABLE_TYPE.getAlias());
  62. if(StringUtil.isNotEmpty(page.getKeyword())){
  63. // 过滤不符条件的元素
  64. String keyWord = SqlFrameUtil.keyWordTrim(page.getKeyword()).toLowerCase();
  65. list = list.stream().filter(t->
  66. (StringUtil.isNotEmpty(t.getComment()) && t.getComment().toLowerCase().contains(keyWord))
  67. || t.getTable().toLowerCase().contains(keyWord)
  68. ).collect(Collectors.toList());
  69. }
  70. return list;
  71. }
  72. @Override
  73. public List<DbTableFieldModel> getListPage(String dbLinkId, Pagination pagination) throws Exception {
  74. List<DbTableFieldModel> list = getList(dbLinkId, null);
  75. if(StringUtil.isNotEmpty(pagination.getKeyword())){
  76. // 过滤不符条件的元素
  77. String keyWord = SqlFrameUtil.keyWordTrim(pagination.getKeyword()).toLowerCase();
  78. list = list.stream().filter(t->
  79. (StringUtil.isNotEmpty(t.getComment()) && t.getComment().toLowerCase().contains(keyWord))
  80. || t.getTable().toLowerCase().contains(keyWord)
  81. ).collect(Collectors.toList());
  82. }
  83. long beginIndex = (pagination.getCurrentPage() -1) * pagination.getPageSize();
  84. long endIndex = beginIndex + pagination.getPageSize();
  85. List<DbTableFieldModel> listVO = new ArrayList<>();
  86. for (int i = 0; i < list.size(); i++) {
  87. if(beginIndex <= i && i < endIndex){
  88. listVO.add(list.get(i));
  89. }
  90. }
  91. pagination.setTotal(list.size());
  92. return listVO;
  93. }
  94. @Override
  95. public DbTableFieldModel getTable(String dbLinkId, String table) throws Exception {
  96. DbLinkEntity dbLinkEntity = dblinkService.getResource(dbLinkId);
  97. DbTableFieldModel dbTableFieldModel = SqlFastUtil.getTable(dbLinkEntity, table);
  98. dbTableFieldModel.setHasTableData(getSum(dbLinkId, table) > 0);
  99. return dbTableFieldModel;
  100. }
  101. @Override
  102. public List<DbFieldModel> getFieldList(String dbLinkId, String table) throws Exception {
  103. DbLinkEntity dbLinkEntity = dblinkService.getResource(dbLinkId);
  104. return SqlFastUtil.getFieldList(dbLinkEntity, table);
  105. }
  106. @Override
  107. public boolean isExistTable(String dbLinkId, String table) throws Exception {
  108. DbLinkEntity dbLinkEntity = dblinkService.getResource(dbLinkId);
  109. return SqlFastUtil.isExistTable(dbLinkEntity, table);
  110. }
  111. @Override
  112. public boolean dropExistsTable(String dbLinkId, String table) throws Exception {
  113. DbLinkEntity dbLinkEntity = dblinkService.getResource(dbLinkId);
  114. if(isExistTable(dbLinkId, table)){
  115. return SqlFastUtil.dropTable(dbLinkEntity, table);
  116. }
  117. return true;
  118. }
  119. @Override
  120. public List<Map<String, Object>> getData(DbTableDataForm dbTableDataForm, String dbLinkId, String table) throws Exception {
  121. DbLinkEntity dbLinkEntity = dblinkService.getResource(dbLinkId);
  122. JdbcPageMod result = new JdbcPageMod();
  123. String orderKey = dbTableDataForm.getField();
  124. // 防止SQL注入
  125. String finalOrderKey = orderKey;
  126. if(getFieldList(dbLinkId, table).stream().noneMatch(field -> field.getField().equals(finalOrderKey))){
  127. throw new DataException("排序字段不存在");
  128. }
  129. if (dbLinkEntity != null) {
  130. List<Object> dataList = new ArrayList<>();
  131. if(DbTypeUtil.checkPostgre(dbLinkEntity)){
  132. table = DbPostgre.getTable(table);
  133. orderKey = DbPostgre.getTable(orderKey);
  134. // String schema = dbLinkEntity.getDbSchema();
  135. // if(StringUtil.isNotEmpty(schema)){
  136. // table = schema + "." + table;
  137. // }
  138. }
  139. StringBuilder sql = new StringBuilder(SqlComEnum.SELECT_TABLE.getOutSql(table));
  140. //模糊查询
  141. if (!StringUtil.isEmpty(dbTableDataForm.getKeyword()) && !StringUtil.isEmpty(orderKey)) {
  142. sql.append(" where " + orderKey + " like ?");
  143. dataList.add("%" + SqlFrameUtil.keyWordTrim(dbTableDataForm.getKeyword()) + "%");
  144. }
  145. result = JdbcUtil.queryPage(
  146. new PrepSqlDTO(sql.toString(), dataList).withConn(dbLinkEntity),
  147. checkOrderKey(orderKey, dbLinkId, table, dbLinkEntity.getDbType()),
  148. (int) dbTableDataForm.getCurrentPage(),
  149. (int) dbTableDataForm.getPageSize())
  150. .setIsLowerCase(true).setIsAlias(true).get();
  151. }
  152. dbTableDataForm.setTotal(result.getTotalRecord());
  153. return (List<Map<String, Object>>)result.getDataList();
  154. }
  155. private String checkOrderKey(String orderKey, String dbLinkId, String table, String dbEncode){
  156. try {
  157. if(DbBase.DM.equals(dbEncode)){
  158. List<DbFieldModel> fieldList = getFieldList(dbLinkId, table);
  159. Optional<DbFieldModel> first = fieldList.stream().filter(field -> field.getField().equals(orderKey)).findFirst();
  160. if(first.isPresent()){
  161. String dataType = first.get().getDataType();
  162. if(dataType.equals(DtDMEnum.CLOB.getDataType()) || dataType.equals(DtDMEnum.TEXT.getDataType())){
  163. // throw new Exception("无法使用CLOB、TEXT作为字段排序条件");
  164. Optional<DbFieldModel> first1 = fieldList.stream().filter(field -> field.getField().toLowerCase().contains("id")).findFirst();
  165. if(first1.isPresent()){
  166. return first1.get().getField();
  167. }
  168. }
  169. }
  170. }
  171. } catch (Exception e) {
  172. e.printStackTrace();
  173. }
  174. return orderKey;
  175. }
  176. @Override
  177. public int getSum(String dbLinkId,String table)throws Exception {
  178. DbLinkEntity dbLinkEntity = dblinkService.getResource(dbLinkId);
  179. return SqlFastUtil.getSum(dbLinkEntity, table);
  180. }
  181. /**=====================增删改========================**/
  182. @Override
  183. public void delete(String dbLinkId, String table) throws Exception {
  184. // 校验
  185. checkTab(table, dbLinkId, 1);
  186. SqlFastUtil.dropTable(dblinkService.getResource(dbLinkId), table);
  187. }
  188. @Override
  189. public void deleteAllTable(String dbLinkId, String dbType) throws Exception {
  190. DbLinkEntity dbLinkEntity = dblinkService.getResource(dbLinkId);
  191. if(!dbLinkEntity.getDbType().equals(dbType)) throw new Exception("数据库类型不符");
  192. for (DbTableFieldModel dbTableFieldModel : SqlFastUtil.getTableList(dbLinkEntity)) {
  193. SqlFastUtil.dropTable(dbLinkEntity, dbTableFieldModel.getTable());
  194. }
  195. }
  196. @Override
  197. public int createTable(DbTableFieldModel dbTableFieldModel) throws Exception {
  198. DbLinkEntity dbLinkEntity = dblinkService.getResource(dbTableFieldModel.getDbLinkId());
  199. // 数据库编码查询校验 (打印模板校验)
  200. String opeDb = dbLinkEntity.getDbType();
  201. String creDb = dbTableFieldModel.getDbEncode();
  202. if(StringUtil.isNotEmpty(creDb) && !creDb.equals(opeDb)){
  203. throw new DataException(MsgCode.DB008.get() + ":" + creDb + " -> " + opeDb);
  204. }
  205. // 表重名判断
  206. if (isExistTable(dbTableFieldModel.getDbLinkId(), dbTableFieldModel.getTable())) {
  207. return 0;
  208. }
  209. // 表主键检验
  210. checkPrimary(dbTableFieldModel.getDbFieldModelList(), dbLinkEntity.getDbType());
  211. // 创建表
  212. SqlFastUtil.creTable(dbLinkEntity, dbTableFieldModel);
  213. return 1;
  214. }
  215. @Override
  216. public void update(DbTableFieldModel dbTableFieldModel) throws Exception {
  217. // 校验
  218. checkTab(dbTableFieldModel.getUpdateOldTable(), dbTableFieldModel.getDbLinkId(), 2);
  219. DbLinkEntity dbLinkEntity = dblinkService.getResource(dbTableFieldModel.getDbLinkId());
  220. //临时表名
  221. String oldTable = dbTableFieldModel.getUpdateOldTable();
  222. String newTable = dbTableFieldModel.getUpdateNewTable();
  223. String tempTabName = "Temp_" + TableUtil.getStringRandom(5);
  224. // 第一步:创建新表 (成功则删除旧表,失败则回滚)
  225. checkPrimary(dbTableFieldModel.getDbFieldModelList(), dbLinkEntity.getDbType());
  226. SqlFastUtil.creTable(dbLinkEntity,
  227. new DbTableFieldModel(
  228. tempTabName,
  229. dbTableFieldModel.getComment(),
  230. dbTableFieldModel.getDbFieldModelList()
  231. ));
  232. // 第二步:删除旧表
  233. SqlFastUtil.dropTable(dbLinkEntity, oldTable);
  234. // 第三步:新表改名
  235. SqlFastUtil.reTableName(dbLinkEntity, tempTabName, newTable);
  236. }
  237. @Override
  238. public void addField(DbTableFieldModel dbTableFieldModel) throws Exception {
  239. DbLinkEntity dbLinkEntity = dblinkService.getResource(dbTableFieldModel.getDbLinkId());
  240. SqlFastUtil.addField(dbLinkEntity, dbTableFieldModel.getUpdateNewTable(), dbTableFieldModel.getDbFieldModelList());
  241. }
  242. @Override
  243. public DbTableFieldModel getDbTableModel(String dbLinkId, String tableName)throws Exception {
  244. NotTenantPluginHolder.setNotSwitchFlag();
  245. DbTableFieldModel dbTableModel = getList(dbLinkId, null).stream().filter(m -> m.getTable().equals(tableName)).findFirst().orElse(null);
  246. if(dbTableModel != null){
  247. dbTableModel.setDbFieldModelList(getFieldList(dbLinkId, tableName));
  248. return dbTableModel;
  249. }else {
  250. throw new DataException("请在数据库中添加对应的数据表");
  251. }
  252. }
  253. /* ================复用代码================== */
  254. /**
  255. * 校验表可操作
  256. *
  257. * @param table 表
  258. * @param dbLinkId 数据连接ID
  259. * @param type 1:删除 2:编辑
  260. * @throws Exception 错误信息
  261. */
  262. private void checkTab(String table, String dbLinkId, Integer type) throws Exception {
  263. if (TableUtil.checkByoTable(table)) throw new DataException(type == 1 ? MsgCode.DB101.get() : MsgCode.DB102.get());
  264. if (getSum(dbLinkId, table) > 0) throw new DataException(type == 1 ? MsgCode.DB201.get() : MsgCode.DB202.get());
  265. }
  266. /**
  267. * 检查主键
  268. * @param tableFieldList 表字段集合
  269. * @throws DataException ignore
  270. */
  271. private void checkPrimary(List<DbFieldModel> tableFieldList, String dbEncode) throws Exception {
  272. // 默认主键为字符串类型
  273. // 主键会自动添加"非空"限制,所以不用做判断。(为空不加语句,且数据库默认字段可为空)
  274. int autoIncrementNum = 0;
  275. for(DbFieldModel field : tableFieldList) {
  276. if(field.getIsAutoIncrement() != null && field.getIsAutoIncrement()){
  277. field.setNullSign("NOT NULL");
  278. // 一张表最多只有一个自增主键,且此字段必须为primary key或者unique key。
  279. autoIncrementNum += 1;
  280. if(autoIncrementNum > 1){
  281. throw new DataException("一张表最多只运行有一个自增主键");
  282. }
  283. if(!(field.getDataType().equals(DtViewConst.INT) || field.getDataType().equals(DtViewConst.BIGINT))){
  284. throw new DataException("自增字段类型必须为数字类型");
  285. }
  286. if(!field.getIsPrimaryKey()){
  287. throw new DataException("自增字段类型必须为主键");
  288. }
  289. }else {
  290. if (field.getIsPrimaryKey()) {
  291. field.setNullSign("NOT NULL");
  292. Method method = ViewDataTypeEnum.class.getMethod("getDt" + dbEncode + "Enum");
  293. Map<ViewDataTypeEnum, String> allowDtMap = ImmutableMap.of(
  294. ViewDataTypeEnum.VARCHAR, DtViewConst.VARCHAR,
  295. ViewDataTypeEnum.INT, DtViewConst.INT,
  296. ViewDataTypeEnum.BIGINT, DtViewConst.BIGINT
  297. );
  298. boolean primaryFlag = false;
  299. for (Map.Entry<ViewDataTypeEnum, String> mapEntity : allowDtMap.entrySet()) {
  300. DtInterface primaryVarcharEnum = (DtInterface)(method.invoke(mapEntity.getKey()));
  301. boolean enumFlag = field.getDataType().equalsIgnoreCase(primaryVarcharEnum.getDataType());
  302. boolean viewFlag = field.getDataType().equalsIgnoreCase(mapEntity.getValue());
  303. if(enumFlag || viewFlag){
  304. primaryFlag = true;
  305. }
  306. }
  307. if(!primaryFlag){
  308. throw new DataException("主键必须为字符串或整型、长整型");
  309. }
  310. }
  311. }
  312. }
  313. }
  314. }