|
@@ -0,0 +1,225 @@
|
|
|
+package com.qmth.ops.biz.service;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.qmth.boot.core.exception.ParameterException;
|
|
|
+import com.qmth.boot.core.exception.StatusException;
|
|
|
+import com.qmth.ops.biz.dao.PropertyItemDao;
|
|
|
+import com.qmth.ops.biz.domain.*;
|
|
|
+import com.qmth.ops.biz.utils.PropertyFileUtil;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import javax.validation.constraints.NotNull;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.util.*;
|
|
|
+import java.util.function.Function;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class PropertyService extends ServiceImpl<PropertyItemDao, PropertyItem> {
|
|
|
+
|
|
|
+ private static final long BASELINE_ENV_ID = 0L;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private EnvService envService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private PropertyGroupService propertyGroupService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private PropertyItemDao propertyItemDao;
|
|
|
+
|
|
|
+ public List<PropertyItem> listBaseline(Long appId, Long versionId, Long moduleId) {
|
|
|
+ return propertyItemDao.selectList(new LambdaQueryWrapper<PropertyItem>().eq(PropertyItem::getAppId, appId)
|
|
|
+ .eq(PropertyItem::getVersionId, versionId).eq(PropertyItem::getModuleId, moduleId)
|
|
|
+ .eq(PropertyItem::getEnvId, BASELINE_ENV_ID).orderByAsc(PropertyItem::getKey));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public List<PropertyItem> updateBaseline(@NotNull App app, @NotNull Version version, @NotNull Module module,
|
|
|
+ @NotNull InputStream file, @NotNull FileFormat format, Version inheritVersion) throws IOException {
|
|
|
+ if (!version.getAppId().equals(app.getId())) {
|
|
|
+ throw new ParameterException("指定版本不属于该应用");
|
|
|
+ }
|
|
|
+ if (version.getArchived()) {
|
|
|
+ throw new ParameterException("指定版本已归档不能操作");
|
|
|
+ }
|
|
|
+ if (!module.getAppId().equals(app.getId())) {
|
|
|
+ throw new ParameterException("指定模块不属于该应用");
|
|
|
+ }
|
|
|
+ if (format != FileFormat.PROPERTY) {
|
|
|
+ throw new ParameterException("暂不支持非properties类型文件");
|
|
|
+ }
|
|
|
+ long time = System.currentTimeMillis();
|
|
|
+ propertyItemDao.delete(new LambdaUpdateWrapper<PropertyItem>().eq(PropertyItem::getAppId, app.getId())
|
|
|
+ .eq(PropertyItem::getVersionId, version.getId()).eq(PropertyItem::getModuleId, module.getId())
|
|
|
+ .eq(PropertyItem::getEnvId, BASELINE_ENV_ID));
|
|
|
+ final Map<String, PropertyItem> baseMap = new HashMap<>();
|
|
|
+ if (inheritVersion != null) {
|
|
|
+ listBaseline(app.getId(), inheritVersion.getId(), module.getId())
|
|
|
+ .forEach(item -> baseMap.put(item.getKey(), item));
|
|
|
+ }
|
|
|
+ List<PropertyItem> list = PropertyFileUtil.read(file);
|
|
|
+ for (PropertyItem item : list) {
|
|
|
+ item.setAppId(app.getId());
|
|
|
+ item.setVersionId(version.getId());
|
|
|
+ item.setModuleId(module.getId());
|
|
|
+ item.setEnvId(BASELINE_ENV_ID);
|
|
|
+ item.setCreateTime(time);
|
|
|
+ item.setUpdateTime(time);
|
|
|
+ PropertyItem base = baseMap.get(item.getKey());
|
|
|
+ if (base != null) {
|
|
|
+ item.setMode(base.getMode());
|
|
|
+ item.setComment(base.getComment());
|
|
|
+ } else {
|
|
|
+ item.setMode(PropertyMode.MUTABLE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ saveBatch(list);
|
|
|
+ List<PropertyItem> baseline = listBaseline(app.getId(), version.getId(), module.getId());
|
|
|
+ baseMap.clear();
|
|
|
+ baseline.forEach(item -> baseMap.put(item.getKey(), item));
|
|
|
+ List<Env> envList = envService.list(app.getId());
|
|
|
+ for (Env env : envList) {
|
|
|
+ resetEnvProperty(app, version, module, env, inheritVersion, baseMap);
|
|
|
+ }
|
|
|
+ return baseline;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据指定版本和最新基线,继承环境自定义配置
|
|
|
+ *
|
|
|
+ * @param app
|
|
|
+ * @param version
|
|
|
+ * @param module
|
|
|
+ * @param env
|
|
|
+ * @param inheritVersion
|
|
|
+ * @param baseMap
|
|
|
+ */
|
|
|
+ private void resetEnvProperty(App app, Version version, Module module, Env env, Version inheritVersion,
|
|
|
+ Map<String, PropertyItem> baseMap) {
|
|
|
+ propertyItemDao.delete(new LambdaUpdateWrapper<PropertyItem>().eq(PropertyItem::getAppId, app.getId())
|
|
|
+ .eq(PropertyItem::getVersionId, version.getId()).eq(PropertyItem::getModuleId, module.getId())
|
|
|
+ .eq(PropertyItem::getEnvId, env.getId()));
|
|
|
+ if (inheritVersion != null) {
|
|
|
+ long time = System.currentTimeMillis();
|
|
|
+ List<PropertyItem> inheritList = listPropertyItem(app.getId(), inheritVersion.getId(), module.getId(),
|
|
|
+ env.getId());
|
|
|
+ List<PropertyItem> saveList = new LinkedList<>();
|
|
|
+ for (PropertyItem item : inheritList) {
|
|
|
+ if (accept(item, baseMap)) {
|
|
|
+ item.setVersionId(version.getId());
|
|
|
+ item.setCreateTime(time);
|
|
|
+ item.setUpdateTime(time);
|
|
|
+ saveList.add(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ saveBatch(saveList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 继承版本的环境自定义配置,是否可以在当前版本保留
|
|
|
+ *
|
|
|
+ * @param item
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private boolean accept(PropertyItem item, Map<String, PropertyItem> baseMap) {
|
|
|
+ //当前基线包含且非只读,可以保留
|
|
|
+ PropertyItem base = baseMap.get(item.getKey());
|
|
|
+ if (base != null && base.getMode() != PropertyMode.READONLY) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ //配置分组判断是否保留
|
|
|
+ if (propertyGroupService.accept(item.getKey(), item.getValue())) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ //应用自定义且不在基线内,不能保留
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public PropertyItem updateBaselineItem(PropertyItem item) {
|
|
|
+ propertyItemDao.update(item, new LambdaUpdateWrapper<PropertyItem>()
|
|
|
+ .set(item.getMode() != null, PropertyItem::getMode, item.getMode())
|
|
|
+ .set(item.getComment() != null, PropertyItem::getComment, item.getComment())
|
|
|
+ .eq(PropertyItem::getAppId, item.getAppId()).eq(PropertyItem::getVersionId, item.getVersionId())
|
|
|
+ .eq(PropertyItem::getModuleId, item.getModuleId()).eq(PropertyItem::getEnvId, BASELINE_ENV_ID)
|
|
|
+ .eq(PropertyItem::getKey, item.getKey()));
|
|
|
+ return findOne(item.getAppId(), item.getVersionId(), item.getModuleId(), BASELINE_ENV_ID, item.getKey());
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<PropertyItem> listPropertyItem(Long appId, Long versionId, Long moduleId, Long envId) {
|
|
|
+ return propertyItemDao.selectList(new LambdaQueryWrapper<PropertyItem>().eq(PropertyItem::getAppId, appId)
|
|
|
+ .eq(PropertyItem::getVersionId, versionId).eq(PropertyItem::getModuleId, moduleId)
|
|
|
+ .eq(PropertyItem::getEnvId, envId).orderByAsc(PropertyItem::getKey));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public PropertyItem updatePropertyItem(PropertyItem item) {
|
|
|
+ PropertyItem base = findOne(item.getAppId(), item.getVersionId(), item.getModuleId(), BASELINE_ENV_ID,
|
|
|
+ item.getKey());
|
|
|
+ PropertyItem previous = findOne(item.getAppId(), item.getVersionId(), item.getModuleId(), item.getEnvId(),
|
|
|
+ item.getKey());
|
|
|
+ if (base != null && base.getMode() == PropertyMode.READONLY) {
|
|
|
+ throw new ParameterException("配置项只读");
|
|
|
+ }
|
|
|
+ if (item.getValue() == null) {
|
|
|
+ throw new ParameterException("配置值不能为空");
|
|
|
+ }
|
|
|
+ if (previous != null) {
|
|
|
+ propertyItemDao.update(previous,
|
|
|
+ new LambdaUpdateWrapper<PropertyItem>().set(PropertyItem::getValue, item.getValue())
|
|
|
+ .set(item.getComment() != null, PropertyItem::getComment, item.getComment())
|
|
|
+ .set(PropertyItem::getUpdateTime, System.currentTimeMillis())
|
|
|
+ .eq(PropertyItem::getAppId, item.getAppId())
|
|
|
+ .eq(PropertyItem::getVersionId, item.getVersionId())
|
|
|
+ .eq(PropertyItem::getModuleId, item.getModuleId())
|
|
|
+ .eq(PropertyItem::getEnvId, item.getEnvId()).eq(PropertyItem::getKey, item.getKey()));
|
|
|
+ return findOne(item.getAppId(), item.getVersionId(), item.getModuleId(), item.getEnvId(), item.getKey());
|
|
|
+ } else {
|
|
|
+ item.setMode(PropertyMode.MUTABLE);
|
|
|
+ item.setCreateTime(System.currentTimeMillis());
|
|
|
+ item.setUpdateTime(item.getCreateTime());
|
|
|
+ propertyItemDao.insert(item);
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public PropertyItem findOne(Long appId, Long versionId, Long moduleId, Long envId, String key) {
|
|
|
+ return propertyItemDao.selectOne(new LambdaQueryWrapper<PropertyItem>().eq(PropertyItem::getAppId, appId)
|
|
|
+ .eq(PropertyItem::getVersionId, versionId).eq(PropertyItem::getModuleId, moduleId)
|
|
|
+ .eq(PropertyItem::getEnvId, envId).eq(PropertyItem::getKey, key));
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<PropertyItem> mergePropertyList(Long appId, Long versionId, Long moduleId, Long envId) {
|
|
|
+ List<PropertyItem> list = listBaseline(appId, versionId, moduleId);
|
|
|
+ //获取环境定义配置项
|
|
|
+ Map<String, PropertyItem> itemMap = listPropertyItem(appId, versionId, moduleId, envId).stream()
|
|
|
+ .collect(Collectors.toMap(PropertyItem::getKey, Function.identity()));
|
|
|
+ //遍历基线
|
|
|
+ for (PropertyItem item : list) {
|
|
|
+ PropertyItem update = itemMap.get(item.getKey());
|
|
|
+ //非只读配置项更新
|
|
|
+ if (update != null && item.getMode() != PropertyMode.READONLY) {
|
|
|
+ item.setValue(update.getValue());
|
|
|
+ }
|
|
|
+ //需要覆盖的配置项不能校验
|
|
|
+ else if (update == null && item.getMode() == PropertyMode.OVERRIDE) {
|
|
|
+ throw new StatusException("配置项需要覆盖新值:" + item.getKey());
|
|
|
+ }
|
|
|
+ itemMap.remove(item.getKey());
|
|
|
+ }
|
|
|
+ //合并新增配置项
|
|
|
+ if (!itemMap.isEmpty()) {
|
|
|
+ list.addAll(itemMap.values());
|
|
|
+ list.sort(Comparator.comparing(PropertyItem::getKey));
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|