Skip to content

Java 服务端示例 ​

本示例展示如何在 Java 服务端实现定时拉取配置、缓存密文、并向客户端提供接口。

示例使用 Spring Boot + Hutool HttpUtil + Redis,可根据实际技术栈调整。

接口域名见服务端接入说明 · 环境说明。


依赖 ​

xml
<!-- pom.xml -->
<dependency>
  <groupId>cn.hutool</groupId>
  <artifactId>hutool-all</artifactId>
  <version>5.8.25</version>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

定时拉取配置 ​

java
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class SdkConfigScheduler {

    private static final String CONFIG_API = "https://api.dc-server.cc/sdk/getAvailableDomainList";
    private static final String CACHE_KEY = "sdk:encrypted_config";
    // Redis TTL:30 分钟(拉取间隔的 3 倍,作为兜底)
    private static final long CACHE_TTL_MINUTES = 30;

    private final StringRedisTemplate redisTemplate;

    public SdkConfigScheduler(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 每 10 分钟拉取一次配置
     */
    @Scheduled(fixedDelay = 10 * 60 * 1000)
    public void fetchAndCache() {
        try {
            String responseBody = HttpUtil.get(CONFIG_API, 5000); // 5s 超时
            JSONObject json = JSONUtil.parseObj(responseBody);

            if (json.getInt("code") == 0) {
                String encryptedData = json.getStr("data");
                // 成功:更新缓存,重置 TTL
                redisTemplate.opsForValue().set(CACHE_KEY, encryptedData, CACHE_TTL_MINUTES, TimeUnit.MINUTES);
                System.out.println("[SdkConfig] 拉取成功,已更新缓存");
            } else {
                // 失败:保留上次缓存,不清空
                System.err.println("[SdkConfig] 拉取失败,code=" + json.getInt("code") + ",沿用上次缓存");
            }
        } catch (Exception e) {
            // 异常:保留上次缓存,不清空
            System.err.println("[SdkConfig] 拉取异常,沿用上次缓存: " + e.getMessage());
        }
    }
}

向客户端提供接口 ​

java
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class SdkConfigController {

    private static final String CACHE_KEY = "sdk:encrypted_config";

    private final StringRedisTemplate redisTemplate;

    public SdkConfigController(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 客户端调用此接口获取密文
     * GET /your-api/sdk-config
     */
    @GetMapping("/your-api/sdk-config")
    public ResponseEntity<Map<String, Object>> getSdkConfig() {
        Map<String, Object> result = new HashMap<>();
        String encryptedData = redisTemplate.opsForValue().get(CACHE_KEY);

        if (encryptedData != null && !encryptedData.isEmpty()) {
            result.put("code", 0);
            result.put("msg", "success");
            result.put("data", encryptedData); // 密文原样返回,不解密
            return ResponseEntity.ok(result);
        } else {
            result.put("code", -1);
            result.put("msg", "config not available");
            return ResponseEntity.ok(result);
        }
    }
}

启用定时任务 ​

在 Spring Boot 启动类上添加注解:

java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

关键说明 ​

  • 不解密 data:服务端只存储密文字符串,不尝试解密
  • 失败兜底:拉取失败时不清空缓存,沿用上次成功的密文
  • TTL 兜底:Redis TTL 设为 30 分钟,防止极端情况下缓存意外过期
  • 5 秒超时:HTTP 请求设置超时,避免定时任务被长时间阻塞

相关文档 ​