MingsoftService.java 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. package mingsoft;
  2. import cn.hutool.core.bean.BeanUtil;
  3. import cn.hutool.core.bean.copier.CopyOptions;
  4. import cn.hutool.core.io.FileUtil;
  5. import cn.hutool.core.lang.Assert;
  6. import cn.hutool.core.util.ArrayUtil;
  7. import cn.hutool.db.DbUtil;
  8. import cn.hutool.db.ds.pooled.DbConfig;
  9. import cn.hutool.db.ds.pooled.PooledDataSource;
  10. import lombok.SneakyThrows;
  11. import lombok.extern.slf4j.Slf4j;
  12. import mingsoft.client.Info;
  13. import mingsoft.client.MingsoftClient;
  14. import mingsoft.client.MingsoftData;
  15. import mingsoft.client.MingsoftPreView;
  16. import java.io.File;
  17. import java.util.Comparator;
  18. import java.util.Map;
  19. import java.util.Objects;
  20. import java.util.Optional;
  21. import java.util.stream.Collectors;
  22. /**
  23. * 操作封装
  24. *
  25. * @param client 客户端
  26. * @param codes 本地代码备份
  27. * @author hosea
  28. * @date 2025-12-24
  29. */
  30. @Slf4j(topic = "Service")
  31. public record MingsoftService(MingsoftClient client, Map<Info, MingsoftData> codes) {
  32. public MingsoftService {
  33. Assert.notNull(client, "客户端不能为空");
  34. }
  35. /**
  36. * 创建
  37. *
  38. * @param config 客户端配置
  39. * @param dbFile 本地代码备份
  40. */
  41. public static Optional<MingsoftService> of(String config, String dbFile) {
  42. return MingsoftClient.of(config)
  43. .flatMap(client -> of(client, dbFile));
  44. }
  45. /**
  46. * 创建
  47. *
  48. * @param client 客户端
  49. * @param dbFile 本地代码备份
  50. */
  51. @SneakyThrows
  52. public static Optional<MingsoftService> of(MingsoftClient client, String dbFile) {
  53. return loadLocalCodeBackup(dbFile)
  54. .map(codes -> new MingsoftService(client, codes));
  55. }
  56. /**
  57. * 加载本地代码备份
  58. *
  59. * @param dbFile 备份代码的SQLite文件
  60. */
  61. public static Optional<Map<Info, MingsoftData>> loadLocalCodeBackup(String dbFile) throws Exception {
  62. DbConfig config = new DbConfig();
  63. config.setUrl("jdbc:sqlite:" + dbFile);
  64. config.setMaxActive(2);
  65. try (PooledDataSource ds = new PooledDataSource(config)) {
  66. return Optional.of(DbUtil.use(ds)
  67. .query("select * from ms where version is not null")
  68. .stream()
  69. .map(entity -> BeanUtil.fillBeanWithMap(entity, new MingsoftData(), CopyOptions.create().ignoreCase()))
  70. .collect(Collectors.groupingBy(MingsoftData::toInfo, Collectors.maxBy(Comparator.comparing(MingsoftData::getVersion))))
  71. .values()
  72. .stream()
  73. .map(opt -> opt.orElse(null))
  74. .filter(Objects::nonNull)
  75. .collect(Collectors.toMap(MingsoftData::toInfo, v -> v)))
  76. .map(list -> {
  77. log.info("查到SQLite的代码 Size:{}", list.size());
  78. return list;
  79. });
  80. }
  81. }
  82. /**
  83. * 查服务器上的代码
  84. */
  85. public Optional<Map<Info, MingsoftData>> queryCodes() {
  86. return Optional.of(client.list()
  87. .map(json -> json.toBean(MingsoftData.class))
  88. .collect(Collectors.toMap(MingsoftData::toInfo, v -> v)))
  89. .map(map -> {
  90. log.info("查到服务器上的代码 Size:{}", map.size());
  91. return map;
  92. });
  93. }
  94. /**
  95. * 复制代码,永远还原到{@link Info#FORM_ID}这个表单ID
  96. * <p>
  97. * {@link #copy(Info, Info, String)}
  98. *
  99. * @param old 旧的
  100. * @param news 新的
  101. */
  102. public boolean copy(Info old, Info news) {
  103. return copy(old, news, Info.FORM_ID);
  104. }
  105. /**
  106. * 复制代码
  107. * <p>
  108. * 从{@link #codes}备份中取是旧的代码
  109. * <p>
  110. * 然后设置新的信息进去
  111. * <p>
  112. * 还原到服务器上指定ID的表单
  113. *
  114. * @param old 旧的
  115. * @param news 新的
  116. * @param id 表单ID
  117. */
  118. public boolean copy(Info old, Info news, String id) {
  119. return update(id, codes.get(old).clone().info(news));
  120. }
  121. /**
  122. * 还原代码,永远还原到{@link Info#FORM_ID}这个表单ID
  123. * <p>
  124. * {@link #restore(Info, String)}
  125. *
  126. * @param old 旧的
  127. */
  128. public boolean restore(Info old) {
  129. return restore(old, Info.FORM_ID);
  130. }
  131. /**
  132. * 还原代码
  133. * <p>
  134. * 从{@link #codes}备份中取是旧的代码
  135. * <p>
  136. * 还原到服务器上指定ID的表单
  137. *
  138. * @param old 旧的
  139. * @param id 表单ID
  140. */
  141. public boolean restore(Info old, String id) {
  142. return update(id, codes.get(old));
  143. }
  144. /**
  145. * 修改指定表单ID的代码
  146. *
  147. * @param id 表单ID
  148. * @param code 代码
  149. */
  150. public boolean update(String id, MingsoftData code) {
  151. log.info("修改 ID:{} Name:{} Table:{}", id, code.getPmoName(), code.getPmoTableName());
  152. return client.update(code.clone().setId(id)).isPresent();
  153. }
  154. /**
  155. * 下载{@link Info#FORM_ID}代码
  156. */
  157. public Optional<byte[]> downloadCode() {
  158. return downloadCode(Info.FORM_ID);
  159. }
  160. /**
  161. * 下载代码
  162. *
  163. * @param ids 表单ID
  164. */
  165. public Optional<byte[]> downloadCode(String... ids) {
  166. return Optional.ofNullable(ids)
  167. .filter(ArrayUtil::isNotEmpty)
  168. .flatMap(client::download)
  169. .map(bs -> {
  170. log.info("下载代码 ID:{} Length:{}", ids, bs.length);
  171. return bs;
  172. });
  173. }
  174. /**
  175. * 保存下载{@link Info#FORM_ID}代码
  176. *
  177. * @param saveFile 保存的文件,如果已经存在,则不会保存
  178. */
  179. public Optional<File> saveDownloadCode(File saveFile) {
  180. return saveDownloadCode(saveFile, Info.FORM_ID);
  181. }
  182. /**
  183. * 保存下载代码
  184. *
  185. * @param saveFile 保存的文件,如果已经存在,则不会保存
  186. * @param ids 表单ID
  187. */
  188. public Optional<File> saveDownloadCode(File saveFile, String... ids) {
  189. return Optional.ofNullable(saveFile)
  190. .filter(file -> !file.exists())
  191. .map(file -> {
  192. FileUtil.mkParentDirs(file);
  193. return file;
  194. })
  195. .flatMap(file -> downloadCode(ids).map(bytes -> {
  196. File f = FileUtil.writeBytes(bytes, file);
  197. log.info("保存代码 ID:{} Length:{} File:{}", ids, bytes.length, f);
  198. return f;
  199. }));
  200. }
  201. /**
  202. * 预览{@link Info#FORM_ID}代码
  203. */
  204. public Optional<Map<String, MingsoftPreView>> previewCode() {
  205. return previewCode(Info.FORM_ID);
  206. }
  207. /**
  208. * 预览代码
  209. *
  210. * @param id 表单ID
  211. */
  212. public Optional<Map<String, MingsoftPreView>> previewCode(String id) {
  213. return Optional.of(client.preview(id)
  214. .map(item -> item.toBean(MingsoftPreView.class))
  215. .collect(Collectors.toMap(MingsoftPreView::getCode, v -> v)))
  216. .map(map -> {
  217. log.info("预览代码 Size:{}", map.size());
  218. return map;
  219. });
  220. }
  221. }