PropertyService.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. package com.qmth.ops.biz.service;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
  4. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  5. import com.qmth.boot.core.exception.ParameterException;
  6. import com.qmth.boot.core.exception.StatusException;
  7. import com.qmth.ops.biz.dao.PropertyItemDao;
  8. import com.qmth.ops.biz.domain.*;
  9. import com.qmth.ops.biz.utils.PropertyFileUtil;
  10. import org.springframework.stereotype.Service;
  11. import org.springframework.transaction.annotation.Transactional;
  12. import javax.annotation.Resource;
  13. import javax.validation.constraints.NotNull;
  14. import java.io.IOException;
  15. import java.io.InputStream;
  16. import java.util.Comparator;
  17. import java.util.HashMap;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.function.Function;
  21. import java.util.stream.Collectors;
  22. @Service
  23. public class PropertyService extends ServiceImpl<PropertyItemDao, PropertyItem> {
  24. private static final long BASELINE_ENV_ID = 0L;
  25. private static final String APP_VERSION_KEY = "com.qmth.solar.app-version";
  26. private static final String APP_CODE_KEY = "com.qmth.solar.app-code";
  27. @Resource
  28. private EnvService envService;
  29. @Resource
  30. private PropertyGroupService propertyGroupService;
  31. @Resource
  32. private PropertyItemDao propertyItemDao;
  33. public List<PropertyItem> listBaseline(Long versionId, Long moduleId) {
  34. return propertyItemDao.selectList(
  35. new LambdaQueryWrapper<PropertyItem>().eq(PropertyItem::getVersionId, versionId)
  36. .eq(PropertyItem::getModuleId, moduleId).eq(PropertyItem::getEnvId, BASELINE_ENV_ID)
  37. .orderByAsc(PropertyItem::getKey));
  38. }
  39. @Transactional
  40. public List<PropertyItem> updateBaseline(@NotNull Version version, @NotNull Module module,
  41. @NotNull InputStream file, @NotNull FileFormat format, Version inheritVersion) throws IOException {
  42. if (!version.getAppId().equals(module.getAppId())) {
  43. throw new ParameterException("指定版本与模块不匹配");
  44. }
  45. if (version.getArchived()) {
  46. throw new ParameterException("指定版本已归档不能操作");
  47. }
  48. if (format != FileFormat.PROPERTY) {
  49. throw new ParameterException("暂不支持非properties类型文件");
  50. }
  51. long time = System.currentTimeMillis();
  52. final Map<String, PropertyItem> baseMap = new HashMap<>();
  53. if (inheritVersion != null) {
  54. listBaseline(inheritVersion.getId(), module.getId()).forEach(item -> baseMap.put(item.getKey(), item));
  55. } else {
  56. listBaseline(version.getId(), module.getId()).forEach(item -> baseMap.put(item.getKey(), item));
  57. }
  58. propertyItemDao.delete(new LambdaUpdateWrapper<PropertyItem>().eq(PropertyItem::getVersionId, version.getId())
  59. .eq(PropertyItem::getModuleId, module.getId()).eq(PropertyItem::getEnvId, BASELINE_ENV_ID));
  60. List<PropertyItem> list = PropertyFileUtil.read(file);
  61. for (PropertyItem item : list) {
  62. item.setVersionId(version.getId());
  63. item.setModuleId(module.getId());
  64. item.setEnvId(BASELINE_ENV_ID);
  65. item.setCreateTime(time);
  66. item.setUpdateTime(time);
  67. PropertyItem base = baseMap.get(item.getKey());
  68. if (base != null) {
  69. item.setMode(base.getMode());
  70. item.setComment(base.getComment());
  71. } else {
  72. item.setMode(PropertyMode.MUTABLE);
  73. }
  74. }
  75. saveBatch(list);
  76. List<PropertyItem> baseline = listBaseline(version.getId(), module.getId());
  77. baseMap.clear();
  78. baseline.forEach(item -> baseMap.put(item.getKey(), item));
  79. List<Env> envList = envService.list(version.getAppId());
  80. for (Env env : envList) {
  81. resetEnvProperty(version, module, env, inheritVersion, baseMap);
  82. }
  83. return baseline;
  84. }
  85. /**
  86. * 根据指定版本和最新基线,继承环境自定义配置
  87. *
  88. * @param version
  89. * @param module
  90. * @param env
  91. * @param inheritVersion
  92. * @param baseMap
  93. */
  94. private void resetEnvProperty(Version version, Module module, Env env, Version inheritVersion,
  95. Map<String, PropertyItem> baseMap) {
  96. List<PropertyItem> currentList = listPropertyItem(version.getId(), module.getId(), env.getId());
  97. propertyItemDao.delete(new LambdaUpdateWrapper<PropertyItem>().eq(PropertyItem::getVersionId, version.getId())
  98. .eq(PropertyItem::getModuleId, module.getId()).eq(PropertyItem::getEnvId, env.getId()));
  99. long time = System.currentTimeMillis();
  100. Map<String, PropertyItem> saveMap = new HashMap<>();
  101. for (PropertyItem item : currentList) {
  102. if (accept(item, baseMap)) {
  103. saveMap.put(item.getKey(), item);
  104. }
  105. }
  106. if (inheritVersion != null) {
  107. List<PropertyItem> inheritList = listPropertyItem(inheritVersion.getId(), module.getId(), env.getId());
  108. for (PropertyItem item : inheritList) {
  109. if (!saveMap.containsKey(item.getKey()) && accept(item, baseMap)) {
  110. item.setVersionId(version.getId());
  111. item.setCreateTime(time);
  112. item.setUpdateTime(time);
  113. saveMap.put(item.getKey(), item);
  114. }
  115. }
  116. }
  117. saveBatch(saveMap.values());
  118. }
  119. /**
  120. * 继承版本的环境自定义配置,是否可以在当前版本保留
  121. *
  122. * @param item
  123. * @return
  124. */
  125. private boolean accept(PropertyItem item, Map<String, PropertyItem> baseMap) {
  126. //当前基线包含且非只读,可以保留
  127. PropertyItem base = baseMap.get(item.getKey());
  128. if (base != null && base.getMode() != PropertyMode.READONLY) {
  129. return true;
  130. }
  131. //配置分组判断是否保留
  132. if (propertyGroupService.accept(item.getKey(), item.getValue())) {
  133. return true;
  134. }
  135. //应用自定义且不在基线内,不能保留
  136. return false;
  137. }
  138. @Transactional
  139. public PropertyItem updateBaselineItem(PropertyItem item) {
  140. propertyItemDao.update(item, new LambdaUpdateWrapper<PropertyItem>()
  141. .set(item.getMode() != null, PropertyItem::getMode, item.getMode())
  142. .set(item.getComment() != null, PropertyItem::getComment, item.getComment())
  143. .eq(PropertyItem::getVersionId, item.getVersionId()).eq(PropertyItem::getModuleId, item.getModuleId())
  144. .eq(PropertyItem::getEnvId, BASELINE_ENV_ID).eq(PropertyItem::getKey, item.getKey()));
  145. return findOne(item.getVersionId(), item.getModuleId(), BASELINE_ENV_ID, item.getKey());
  146. }
  147. public List<PropertyItem> listPropertyItem(Long versionId, Long moduleId, Long envId) {
  148. return propertyItemDao.selectList(
  149. new LambdaQueryWrapper<PropertyItem>().eq(PropertyItem::getVersionId, versionId)
  150. .eq(PropertyItem::getModuleId, moduleId).eq(PropertyItem::getEnvId, envId)
  151. .orderByAsc(PropertyItem::getKey));
  152. }
  153. @Transactional
  154. public PropertyItem updatePropertyItem(PropertyItem item) {
  155. PropertyItem base = findOne(item.getVersionId(), item.getModuleId(), BASELINE_ENV_ID, item.getKey());
  156. PropertyItem previous = findOne(item.getVersionId(), item.getModuleId(), item.getEnvId(), item.getKey());
  157. if (base != null && base.getMode() == PropertyMode.READONLY) {
  158. throw new ParameterException("配置项只读");
  159. }
  160. if (item.getValue() == null) {
  161. throw new ParameterException("配置值不能为空");
  162. }
  163. if (previous != null) {
  164. propertyItemDao.update(previous,
  165. new LambdaUpdateWrapper<PropertyItem>().set(PropertyItem::getValue, item.getValue())
  166. .set(item.getComment() != null, PropertyItem::getComment, item.getComment())
  167. .set(PropertyItem::getUpdateTime, System.currentTimeMillis())
  168. .eq(PropertyItem::getVersionId, item.getVersionId())
  169. .eq(PropertyItem::getModuleId, item.getModuleId())
  170. .eq(PropertyItem::getEnvId, item.getEnvId()).eq(PropertyItem::getKey, item.getKey()));
  171. return findOne(item.getVersionId(), item.getModuleId(), item.getEnvId(), item.getKey());
  172. } else {
  173. item.setMode(PropertyMode.MUTABLE);
  174. item.setCreateTime(System.currentTimeMillis());
  175. item.setUpdateTime(item.getCreateTime());
  176. propertyItemDao.insert(item);
  177. return item;
  178. }
  179. }
  180. @Transactional
  181. public void deletePropertyItem(PropertyItem item) {
  182. PropertyItem base = findOne(item.getVersionId(), item.getModuleId(), BASELINE_ENV_ID, item.getKey());
  183. if (base != null) {
  184. throw new ParameterException("存在基线配置项时不能删除");
  185. }
  186. PropertyItem current = findOne(item.getVersionId(), item.getModuleId(), item.getEnvId(), item.getKey());
  187. if (current == null) {
  188. throw new ParameterException("配置项不存在");
  189. }
  190. propertyItemDao
  191. .delete(new LambdaQueryWrapper<PropertyItem>().eq(PropertyItem::getVersionId, item.getVersionId())
  192. .eq(PropertyItem::getModuleId, item.getModuleId()).eq(PropertyItem::getEnvId, item.getEnvId())
  193. .eq(PropertyItem::getKey, item.getKey()));
  194. }
  195. public PropertyItem findOne(Long versionId, Long moduleId, Long envId, String key) {
  196. return propertyItemDao.selectOne(
  197. new LambdaQueryWrapper<PropertyItem>().eq(PropertyItem::getVersionId, versionId)
  198. .eq(PropertyItem::getModuleId, moduleId).eq(PropertyItem::getEnvId, envId)
  199. .eq(PropertyItem::getKey, key));
  200. }
  201. public List<PropertyItem> mergePropertyList(String appCode, Version version, Long moduleId, Long envId) {
  202. List<PropertyItem> list = listBaseline(version.getId(), moduleId);
  203. //获取环境定义配置项
  204. Map<String, PropertyItem> itemMap = listPropertyItem(version.getId(), moduleId, envId).stream()
  205. .collect(Collectors.toMap(PropertyItem::getKey, Function.identity()));
  206. //遍历基线
  207. for (PropertyItem item : list) {
  208. PropertyItem update = itemMap.get(item.getKey());
  209. //非只读配置项更新
  210. if (update != null && item.getMode() != PropertyMode.READONLY) {
  211. item.setValue(update.getValue());
  212. }
  213. //需要覆盖的配置项不能校验
  214. else if (update == null && item.getMode() == PropertyMode.OVERRIDE) {
  215. throw new StatusException("配置项需要覆盖新值:" + item.getKey());
  216. }
  217. itemMap.remove(item.getKey());
  218. }
  219. //合并新增配置项
  220. if (!itemMap.isEmpty()) {
  221. list.addAll(itemMap.values());
  222. }
  223. //强制增加appCode与appVersion配置项,自动根据当前app和version填充
  224. boolean hasCode = false;
  225. boolean hasVersion = false;
  226. for (PropertyItem item : list) {
  227. if (item.getKey().equals(APP_CODE_KEY)) {
  228. item.setValue(appCode);
  229. hasCode = true;
  230. } else if (item.getKey().equals(APP_VERSION_KEY)) {
  231. item.setValue(version.getName());
  232. hasVersion = true;
  233. }
  234. }
  235. if (!hasCode) {
  236. PropertyItem item = new PropertyItem();
  237. item.setKey(APP_CODE_KEY);
  238. item.setValue(appCode);
  239. list.add(item);
  240. }
  241. if (!hasVersion) {
  242. PropertyItem item = new PropertyItem();
  243. item.setKey(APP_VERSION_KEY);
  244. item.setValue(version.getName());
  245. list.add(item);
  246. }
  247. list.sort(Comparator.comparing(PropertyItem::getKey));
  248. return list;
  249. }
  250. }