feat: DynamicServerConfigCrudService #969

This commit is contained in:
tjq 2024-08-24 19:24:58 +08:00
parent 3c40cd7543
commit 9b35af9b44
10 changed files with 266 additions and 0 deletions

View File

@ -13,6 +13,8 @@ import lombok.Getter;
@AllArgsConstructor
public enum ErrorCodes {
SYS_ACQUIRE_LOCK_FAILED("-10", "SYS_ACQUIRE_LOCK_FAILED"),
USER_NOT_LOGIN("-100", "UserNotLoggedIn"),
USER_NOT_EXIST("-101", "UserNotExist"),
USER_AUTH_FAILED("-102", "UserAuthFailed"),

View File

@ -23,6 +23,7 @@
<module>powerjob-server-core</module>
<module>powerjob-server-monitor</module>
<module>powerjob-server-auth</module>
<module>powerjob-server-infrastructure</module>
</modules>
@ -87,6 +88,11 @@
<artifactId>powerjob-server-persistence</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>tech.powerjob</groupId>
<artifactId>powerjob-server-infrastructure</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>tech.powerjob</groupId>
<artifactId>powerjob-server-core</artifactId>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>tech.powerjob</groupId>
<artifactId>powerjob-server</artifactId>
<version>5.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>powerjob-server-infrastructure</artifactId>
<version>${project.parent.version}</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>tech.powerjob</groupId>
<artifactId>powerjob-server-persistence</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,23 @@
package tech.powerjob.server.infrastructure.config;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 配置对象
*
* @author tjq
* @since 2024/8/24
*/
@Data
@Accessors(chain = true)
public class Config implements Serializable {
private String key;
private String value;
private String comment;
}

View File

@ -0,0 +1,18 @@
package tech.powerjob.server.infrastructure.config;
/**
* 配置服务
*
* @author tjq
* @since 2024/8/24
*/
public interface ConfigService {
/**
* 获取配置
* @param key 配置名称
* @param defaultValue 默认值
* @return 结果
*/
String fetchConfig(String key, String defaultValue);
}

View File

@ -0,0 +1,33 @@
package tech.powerjob.server.infrastructure.config;
import java.util.List;
import java.util.Optional;
/**
* 服务端配置 CRUD 服务
*
* @author tjq
* @since 2024/8/24
*/
public interface DynamicServerConfigCrudService {
/**
* 保存配置
* @param config 配置信息
*/
void save(Config config);
Optional<Config> fetch(String key);
/**
* 删除配置
* @param key
*/
void delete(String key);
/**
* 列出所有配置
* @return 配置
*/
List<Config> list();
}

View File

@ -0,0 +1,36 @@
package tech.powerjob.server.infrastructure.config.impl;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import tech.powerjob.server.infrastructure.config.Config;
import tech.powerjob.server.infrastructure.config.ConfigService;
import tech.powerjob.server.infrastructure.config.DynamicServerConfigCrudService;
import javax.annotation.Resource;
import java.util.Optional;
/**
* ConfigService
*
* @author tjq
* @since 2024/8/24
*/
@Service
public class ConfigServiceImpl implements ConfigService {
@Resource
private Environment environment;
@Resource
private DynamicServerConfigCrudService dynamicServerConfigCrudService;
@Override
public String fetchConfig(String key, String defaultValue) {
Optional<Config> configByDbOpt = dynamicServerConfigCrudService.fetch(key);
if (configByDbOpt.isPresent()) {
return configByDbOpt.get().getValue();
}
return environment.getProperty(key, defaultValue);
}
}

View File

@ -0,0 +1,105 @@
package tech.powerjob.server.infrastructure.config.impl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import tech.powerjob.common.enums.ErrorCodes;
import tech.powerjob.common.exception.PowerJobException;
import tech.powerjob.server.extension.LockService;
import tech.powerjob.server.infrastructure.config.Config;
import tech.powerjob.server.infrastructure.config.DynamicServerConfigCrudService;
import tech.powerjob.server.persistence.remote.model.SundryDO;
import tech.powerjob.server.persistence.remote.repository.SundryRepository;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* DynamicServerConfigCrudService
*
* @author tjq
* @since 2024/8/24
*/
@Slf4j
@Service
public class DynamicServerConfigCrudServiceImpl implements DynamicServerConfigCrudService {
@Resource
private LockService lockService;
@Resource
private SundryRepository sundryRepository;
private static final String PKEY = "sys.powerjob.server.config";
private static final int MAX_LOCK_TIME = 60000;
@Override
public void save(Config config) {
String lockKey = PKEY.concat(config.getKey());
boolean acquiredLock = lockService.tryLock(lockKey, MAX_LOCK_TIME);
if (!acquiredLock) {
throw new PowerJobException(ErrorCodes.SYS_ACQUIRE_LOCK_FAILED, "请稍后重试");
}
SundryDO sundryDO;
try {
Optional<SundryDO> oldConfigOpt = sundryRepository.findByPkeyAndSkey(PKEY, config.getKey());
if (oldConfigOpt.isPresent()) {
sundryDO = oldConfigOpt.get();
fillConfig2SundryDO(sundryDO, config);
} else {
// 纯新增
sundryDO = new SundryDO();
fillConfig2SundryDO(sundryDO, config);
sundryDO.setGmtCreate(new Date());
}
sundryRepository.saveAndFlush(sundryDO);
log.info("[DynamicServerConfigCrudService] save config successfully, config: {}, sundry: {}", config, sundryDO);
} finally {
lockService.unlock(lockKey);
}
}
@Override
public Optional<Config> fetch(String key) {
Optional<SundryDO> oldConfigOpt = sundryRepository.findByPkeyAndSkey(PKEY, key);
return oldConfigOpt.map(DynamicServerConfigCrudServiceImpl::convert2Config);
}
@Override
public void delete(String key) {
Optional<SundryDO> deletedOpt = sundryRepository.deleteByPkeyAndSkey(PKEY, key);
if (deletedOpt.isPresent()) {
log.info("[DynamicServerConfigCrudService] delete config[{}] successfully, origin data: {}", key, deletedOpt.get());
} else {
log.warn("[DynamicServerConfigCrudService] config[{}] not exist, no need to delete!", key);
}
}
@Override
public List<Config> list() {
List<SundryDO> allByPkey = sundryRepository.findAllByPkey(PKEY);
return Optional.ofNullable(allByPkey).orElse(Collections.emptyList()).stream().map(DynamicServerConfigCrudServiceImpl::convert2Config).collect(Collectors.toList());
}
private static void fillConfig2SundryDO(SundryDO sundryDO, Config config) {
sundryDO.setPkey(PKEY);
sundryDO.setSkey(config.getKey());
sundryDO.setContent(config.getValue());
sundryDO.setExtra(config.getComment());
sundryDO.setGmtModified(new Date());
}
private static Config convert2Config(SundryDO sundryDO) {
return new Config()
.setKey(sundryDO.getSkey())
.setValue(sundryDO.getContent())
.setComment(sundryDO.getExtra());
}
}

View File

@ -0,0 +1,7 @@
/**
* 基础服务层
*
* @author tjq
* @since 2024/8/24
*/
package tech.powerjob.server.infrastructure;

View File

@ -17,4 +17,6 @@ public interface SundryRepository extends JpaRepository<SundryDO, Long> {
List<SundryDO> findAllByPkey(String pkey);
Optional<SundryDO> findByPkeyAndSkey(String pkey, String skey);
Optional<SundryDO> deleteByPkeyAndSkey(String pkey, String skey);
}