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.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; @Service public class PropertyService extends ServiceImpl { private static final long BASELINE_ENV_ID = 0L; private static final String APP_VERSION_KEY = "com.qmth.solar.app-version"; private static final String APP_CODE_KEY = "com.qmth.solar.app-code"; @Resource private EnvService envService; @Resource private PropertyGroupService propertyGroupService; @Resource private PropertyItemDao propertyItemDao; public List listBaseline(Long versionId, Long moduleId) { return propertyItemDao.selectList( new LambdaQueryWrapper().eq(PropertyItem::getVersionId, versionId) .eq(PropertyItem::getModuleId, moduleId).eq(PropertyItem::getEnvId, BASELINE_ENV_ID) .orderByAsc(PropertyItem::getKey)); } @Transactional public List updateBaseline(@NotNull Version version, @NotNull Module module, @NotNull InputStream file, @NotNull FileFormat format, Version inheritVersion) throws IOException { if (!version.getAppId().equals(module.getAppId())) { throw new ParameterException("指定版本与模块不匹配"); } if (version.getArchived()) { throw new ParameterException("指定版本已归档不能操作"); } if (format != FileFormat.PROPERTY) { throw new ParameterException("暂不支持非properties类型文件"); } long time = System.currentTimeMillis(); final Map baseMap = new HashMap<>(); if (inheritVersion != null) { listBaseline(inheritVersion.getId(), module.getId()).forEach(item -> baseMap.put(item.getKey(), item)); } else { listBaseline(version.getId(), module.getId()).forEach(item -> baseMap.put(item.getKey(), item)); } propertyItemDao.delete(new LambdaUpdateWrapper().eq(PropertyItem::getVersionId, version.getId()) .eq(PropertyItem::getModuleId, module.getId()).eq(PropertyItem::getEnvId, BASELINE_ENV_ID)); List list = PropertyFileUtil.read(file); for (PropertyItem item : list) { 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 baseline = listBaseline(version.getId(), module.getId()); baseMap.clear(); baseline.forEach(item -> baseMap.put(item.getKey(), item)); List envList = envService.list(version.getAppId()); for (Env env : envList) { resetEnvProperty(version, module, env, inheritVersion, baseMap); } return baseline; } /** * 根据指定版本和最新基线,继承环境自定义配置 * * @param version * @param module * @param env * @param inheritVersion * @param baseMap */ private void resetEnvProperty(Version version, Module module, Env env, Version inheritVersion, Map baseMap) { List currentList = listPropertyItem(version.getId(), module.getId(), env.getId()); propertyItemDao.delete(new LambdaUpdateWrapper().eq(PropertyItem::getVersionId, version.getId()) .eq(PropertyItem::getModuleId, module.getId()).eq(PropertyItem::getEnvId, env.getId())); long time = System.currentTimeMillis(); Map saveMap = new HashMap<>(); for (PropertyItem item : currentList) { if (accept(item, baseMap)) { saveMap.put(item.getKey(), item); } } if (inheritVersion != null) { List inheritList = listPropertyItem(inheritVersion.getId(), module.getId(), env.getId()); for (PropertyItem item : inheritList) { if (!saveMap.containsKey(item.getKey()) && accept(item, baseMap)) { item.setVersionId(version.getId()); item.setCreateTime(time); item.setUpdateTime(time); saveMap.put(item.getKey(), item); } } } saveBatch(saveMap.values()); } /** * 继承版本的环境自定义配置,是否可以在当前版本保留 * * @param item * @return */ private boolean accept(PropertyItem item, Map 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() .set(item.getMode() != null, PropertyItem::getMode, item.getMode()) .set(item.getComment() != null, PropertyItem::getComment, item.getComment()) .eq(PropertyItem::getVersionId, item.getVersionId()).eq(PropertyItem::getModuleId, item.getModuleId()) .eq(PropertyItem::getEnvId, BASELINE_ENV_ID).eq(PropertyItem::getKey, item.getKey())); return findOne(item.getVersionId(), item.getModuleId(), BASELINE_ENV_ID, item.getKey()); } public List listPropertyItem(Long versionId, Long moduleId, Long envId) { return propertyItemDao.selectList( new LambdaQueryWrapper().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.getVersionId(), item.getModuleId(), BASELINE_ENV_ID, item.getKey()); PropertyItem previous = findOne(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().set(PropertyItem::getValue, item.getValue()) .set(item.getComment() != null, PropertyItem::getComment, item.getComment()) .set(PropertyItem::getUpdateTime, System.currentTimeMillis()) .eq(PropertyItem::getVersionId, item.getVersionId()) .eq(PropertyItem::getModuleId, item.getModuleId()) .eq(PropertyItem::getEnvId, item.getEnvId()).eq(PropertyItem::getKey, item.getKey())); return findOne(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; } } @Transactional public void deletePropertyItem(PropertyItem item) { PropertyItem base = findOne(item.getVersionId(), item.getModuleId(), BASELINE_ENV_ID, item.getKey()); if (base != null) { throw new ParameterException("存在基线配置项时不能删除"); } PropertyItem current = findOne(item.getVersionId(), item.getModuleId(), item.getEnvId(), item.getKey()); if (current == null) { throw new ParameterException("配置项不存在"); } propertyItemDao .delete(new LambdaQueryWrapper().eq(PropertyItem::getVersionId, item.getVersionId()) .eq(PropertyItem::getModuleId, item.getModuleId()).eq(PropertyItem::getEnvId, item.getEnvId()) .eq(PropertyItem::getKey, item.getKey())); } public PropertyItem findOne(Long versionId, Long moduleId, Long envId, String key) { return propertyItemDao.selectOne( new LambdaQueryWrapper().eq(PropertyItem::getVersionId, versionId) .eq(PropertyItem::getModuleId, moduleId).eq(PropertyItem::getEnvId, envId) .eq(PropertyItem::getKey, key)); } public List mergePropertyList(String appCode, Version version, Long moduleId, Long envId) { List list = listBaseline(version.getId(), moduleId); //获取环境定义配置项 Map itemMap = listPropertyItem(version.getId(), 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()); } //强制增加appCode与appVersion配置项,自动根据当前app和version填充 boolean hasCode = false; boolean hasVersion = false; for (PropertyItem item : list) { if (item.getKey().equals(APP_CODE_KEY)) { item.setValue(appCode); hasCode = true; } else if (item.getKey().equals(APP_VERSION_KEY)) { item.setValue(version.getName()); hasVersion = true; } } if (!hasCode) { PropertyItem item = new PropertyItem(); item.setKey(APP_CODE_KEY); item.setValue(appCode); list.add(item); } if (!hasVersion) { PropertyItem item = new PropertyItem(); item.setKey(APP_VERSION_KEY); item.setValue(version.getName()); list.add(item); } list.sort(Comparator.comparing(PropertyItem::getKey)); return list; } }