CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-github-binarywang--weixin-java-miniapp

Comprehensive Java SDK for WeChat MiniApp development with complete platform integration

Pending
Overview
Eval results
Files

configuration.mddocs/

Configuration

Comprehensive configuration management supporting memory-based and Redis-based storage with multi-app support, access token management, and production-ready deployment options for WeChat MiniApp applications.

Capabilities

Configuration Interface

Core configuration interface providing access to all WeChat MiniApp settings and credentials.

public interface WxMaConfig {
    // Basic Configuration
    String getAppid();
    void setAppid(String appid);
    String getSecret();
    void setSecret(String secret);
    String getToken();
    void setToken(String token);
    String getAesKey();
    void setAesKey(String aesKey);
    String getOriginalId();
    void setOriginalId(String originalId);
    String getCloudEnv();
    void setCloudEnv(String cloudEnv);
    
    // Access Token Management
    String getAccessToken();
    Lock getAccessTokenLock();
    boolean isAccessTokenExpired();
    void expireAccessToken();
    void updateAccessToken(WxAccessToken accessToken);
    void updateAccessToken(String accessToken, int expiresInSeconds);
    
    // Stable Access Token Support
    boolean isStableAccessToken();
    void useStableAccessToken(boolean use);
    
    // JSAPI Ticket Management
    String getJsapiTicket();
    Lock getJsapiTicketLock();
    boolean isJsapiTicketExpired();
    void expireJsapiTicket();
    void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);
    
    // Card API Ticket Management
    String getCardApiTicket();
    Lock getCardApiTicketLock();
    boolean isCardApiTicketExpired();
    void expireCardApiTicket();
    void updateCardApiTicket(String cardApiTicket, int expiresInSeconds);
    
    // HTTP Configuration
    String getHttpProxyHost();
    void setHttpProxyHost(String httpProxyHost);
    int getHttpProxyPort();
    void setHttpProxyPort(int httpProxyPort);
    String getHttpProxyUsername();
    void setHttpProxyUsername(String httpProxyUsername);
    String getHttpProxyPassword();
    void setHttpProxyPassword(String httpProxyPassword);
    
    // HTTP Client Configuration
    int getRetrySleepMillis();
    void setRetrySleepMillis(int retrySleepMillis);
    int getMaxRetryTimes();
    void setMaxRetryTimes(int maxRetryTimes);
    ApacheHttpClientBuilder getApacheHttpClientBuilder();
    void setApacheHttpClientBuilder(ApacheHttpClientBuilder apacheHttpClientBuilder);
    
    // API Signature (for server-side API)
    String getApiSignatureRsaPrivateKey();
    void setApiSignatureRsaPrivateKey(String apiSignatureRsaPrivateKey);
    String getApiSignatureAesKey();
    void setApiSignatureAesKey(String apiSignatureAesKey);
    String getApiSignatureRsaPrivateKeySn();
    void setApiSignatureRsaPrivateKeySn(String apiSignatureRsaPrivateKeySn);
    String getApiSignatureAesKeySn();
    void setApiSignatureAesKeySn(String apiSignatureAesKeySn);
    
    // Third-party Platform Support
    String getWechatMpAppid();
    void setWechatMpAppid(String wechatMpAppid);
}

Default Configuration Implementation

Memory-based configuration implementation suitable for single-instance deployments.

public class WxMaDefaultConfigImpl implements WxMaConfig, Serializable {
    // Configuration Storage
    private String appid;                       // Mini program App ID
    private String secret;                      // Mini program App Secret
    private String token;                       // Message encryption token
    private String aesKey;                      // Message encryption AES key
    private String originalId;                  // Original ID
    private String cloudEnv;                    // Cloud environment ID
    
    // Access Token Management
    private volatile String accessToken;        // Current access token
    private volatile long accessTokenExpiresTime; // Expiration timestamp
    private final Lock accessTokenLock = new ReentrantLock();
    private boolean stableAccessToken = false;  // Use stable access token interface
    
    // Token Update Callbacks
    private Consumer<WxAccessTokenEntity> updateAccessTokenBefore;
    private boolean enableUpdateAccessTokenBefore = false;
    
    // JSAPI Ticket Management
    private volatile String jsapiTicket;        // JSAPI ticket
    private volatile long jsapiTicketExpiresTime; // JSAPI ticket expiration
    private final Lock jsapiTicketLock = new ReentrantLock();
    
    // Card API Ticket Management
    private volatile String cardApiTicket;      // Card API ticket
    private volatile long cardApiTicketExpiresTime; // Card API ticket expiration
    private final Lock cardApiTicketLock = new ReentrantLock();
    
    // HTTP Configuration
    private String httpProxyHost;               // HTTP proxy host
    private int httpProxyPort = 0;             // HTTP proxy port
    private String httpProxyUsername;           // HTTP proxy username
    private String httpProxyPassword;           // HTTP proxy password
    private int retrySleepMillis = 1000;       // Retry delay in milliseconds
    private int maxRetryTimes = 5;             // Maximum retry attempts
    
    // HTTP Client Builder
    private ApacheHttpClientBuilder apacheHttpClientBuilder;
    
    // API Signature Configuration
    private String apiSignatureRsaPrivateKey;  // RSA private key for API signature
    private String apiSignatureAesKey;         // AES key for API signature
    private String apiSignatureRsaPrivateKeySn; // RSA key serial number
    private String apiSignatureAesKeySn;       // AES key serial number
    
    // Third-party Platform
    private String wechatMpAppid;              // Component app ID for third-party platforms
    
    // Constructors
    public WxMaDefaultConfigImpl();
    
    // Token Management Methods
    @Override
    public boolean isAccessTokenExpired();
    @Override
    public void updateAccessToken(String accessToken, int expiresInSeconds);
    @Override
    public void updateAccessToken(WxAccessToken accessToken);
    
    // Callback Configuration
    public void setUpdateAccessTokenBefore(Consumer<WxAccessTokenEntity> updateAccessTokenBefore);
    public void enableUpdateAccessTokenBefore(boolean enable);
    
    // All getters and setters...
}

Redis Configuration Implementations

Production-ready Redis-based configuration implementations for distributed deployments.

// Basic Redis Configuration
public class WxMaRedisConfigImpl extends AbstractWxMaRedisConfig {
    private final RedisTemplate<String, String> redisTemplate;
    
    public WxMaRedisConfigImpl(RedisTemplate<String, String> redisTemplate);
    public WxMaRedisConfigImpl(RedisTemplate<String, String> redisTemplate, String keyPrefix);
    
    // Redis operations using RedisTemplate
    @Override
    public String getConfigValue(String key, String defaultValue);
    @Override
    public void setConfigValue(String key, String value);
    @Override
    public void expireConfigValue(String key, int seconds);
}

// Redisson Configuration
public class WxMaRedissonConfigImpl extends AbstractWxMaRedisConfig {
    private final RedissonClient redissonClient;
    
    public WxMaRedissonConfigImpl(RedissonClient redissonClient);
    public WxMaRedissonConfigImpl(RedissonClient redissonClient, String keyPrefix);
    
    // Redisson operations with distributed locks
    @Override
    public Lock getConfigLock(String key);
    @Override
    public String getConfigValue(String key, String defaultValue);
    @Override
    public void setConfigValue(String key, String value);
}

// Enhanced Redis Configuration
public class WxMaRedisBetterConfigImpl extends AbstractWxMaRedisConfig {
    private final RedisTemplate<String, String> redisTemplate;
    private final StringRedisTemplate stringRedisTemplate;
    
    public WxMaRedisBetterConfigImpl(RedisTemplate<String, String> redisTemplate,
                                    StringRedisTemplate stringRedisTemplate);
    
    // Enhanced Redis operations with better performance
    @Override
    public void updateAccessToken(String accessToken, int expiresInSeconds);
    @Override
    public boolean isAccessTokenExpired();
}

// Redis Connection Configuration
public class WxMaRedisConnectionConfigImpl extends AbstractWxMaRedisConfig {
    private final RedisConnectionFactory connectionFactory;
    
    public WxMaRedisConnectionConfigImpl(RedisConnectionFactory connectionFactory);
    public WxMaRedisConnectionConfigImpl(RedisConnectionFactory connectionFactory, String keyPrefix);
    
    // Direct Redis connection operations
}

Abstract Redis Configuration

Base class providing common Redis configuration functionality.

public abstract class AbstractWxMaRedisConfig implements WxMaConfig {
    protected String keyPrefix = "wx:ma:";     // Redis key prefix
    
    // Configuration Keys
    protected static final String ACCESS_TOKEN_KEY = "access_token";
    protected static final String JSAPI_TICKET_KEY = "jsapi_ticket";
    protected static final String CARD_API_TICKET_KEY = "card_api_ticket";
    
    // Lock Keys
    protected static final String ACCESS_TOKEN_LOCK_KEY = "access_token:lock";
    protected static final String JSAPI_TICKET_LOCK_KEY = "jsapi_ticket:lock";
    protected static final String CARD_API_TICKET_LOCK_KEY = "card_api_ticket:lock";
    
    // Abstract methods to be implemented by subclasses
    protected abstract String getValue(String key);
    protected abstract void setValue(String key, String value, int expireSeconds);
    protected abstract void expire(String key, int seconds);
    protected abstract Long getExpire(String key);
    protected abstract Lock getLock(String key);
    
    // Common Redis operations
    protected String buildKey(String key) {
        return keyPrefix + getAppid() + ":" + key;
    }
    
    // Token management using Redis
    @Override
    public String getAccessToken() {
        return getValue(buildKey(ACCESS_TOKEN_KEY));
    }
    
    @Override
    public boolean isAccessTokenExpired() {
        Long expire = getExpire(buildKey(ACCESS_TOKEN_KEY));
        return expire == null || expire < 200; // 200 second buffer
    }
    
    @Override
    public void updateAccessToken(String accessToken, int expiresInSeconds) {
        setValue(buildKey(ACCESS_TOKEN_KEY), accessToken, expiresInSeconds - 200);
    }
    
    @Override
    public Lock getAccessTokenLock() {
        return getLock(buildKey(ACCESS_TOKEN_LOCK_KEY));
    }
}

Usage Examples

Basic Configuration Setup

Memory-based Configuration (Development)

@Configuration
public class WeChatMiniAppConfig {
    
    @Value("${wechat.miniapp.appid}")
    private String appid;
    
    @Value("${wechat.miniapp.secret}")
    private String secret;
    
    @Value("${wechat.miniapp.token:}")
    private String token;
    
    @Value("${wechat.miniapp.aes-key:}")
    private String aesKey;
    
    @Bean
    public WxMaConfig wxMaConfig() {
        WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
        config.setAppid(appid);
        config.setSecret(secret);
        config.setToken(token);
        config.setAesKey(aesKey);
        
        // HTTP configuration
        config.setRetrySleepMillis(1000);
        config.setMaxRetryTimes(3);
        
        // Enable stable access token (recommended for production)
        config.useStableAccessToken(true);
        
        return config;
    }
    
    @Bean
    public WxMaService wxMaService(WxMaConfig wxMaConfig) {
        WxMaServiceImpl service = new WxMaServiceImpl();
        service.setWxMaConfig(wxMaConfig);
        return service;
    }
}

Redis-based Configuration (Production)

@Configuration
@ConditionalOnProperty(name = "wechat.redis.enabled", havingValue = "true")
public class WeChatRedisConfig {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    @Bean
    public WxMaConfig wxMaRedisConfig() {
        WxMaRedisConfigImpl config = new WxMaRedisConfigImpl(redisTemplate, "wechat:ma:");
        config.setAppid("your-appid");
        config.setSecret("your-secret");
        config.setToken("your-token");
        config.setAesKey("your-aes-key");
        
        // Configure HTTP settings
        config.setHttpProxyHost("proxy.company.com");
        config.setHttpProxyPort(8080);
        config.setHttpProxyUsername("proxy-user");
        config.setHttpProxyPassword("proxy-pass");
        
        // Configure retry settings
        config.setRetrySleepMillis(2000);
        config.setMaxRetryTimes(5);
        
        return config;
    }
}

Multi-App Configuration

Multiple Mini Programs Support

@Configuration
public class MultiAppWeChatConfig {
    
    @Bean
    public WxMaService multiAppWxMaService() {
        WxMaServiceImpl service = new WxMaServiceImpl();
        
        // Configure multiple apps
        Map<String, WxMaConfig> configs = new HashMap<>();
        
        // App 1 - Main app
        WxMaDefaultConfigImpl config1 = new WxMaDefaultConfigImpl();
        config1.setAppid("app1-appid");
        config1.setSecret("app1-secret");
        config1.setToken("app1-token");
        configs.put("main", config1);
        
        // App 2 - Secondary app
        WxMaDefaultConfigImpl config2 = new WxMaDefaultConfigImpl();
        config2.setAppid("app2-appid");
        config2.setSecret("app2-secret");
        config2.setToken("app2-token");
        configs.put("secondary", config2);
        
        // App 3 - Test environment
        WxMaDefaultConfigImpl config3 = new WxMaDefaultConfigImpl();
        config3.setAppid("test-appid");
        config3.setSecret("test-secret");
        config3.setToken("test-token");
        configs.put("test", config3);
        
        service.setMultiConfigs(configs, "main"); // "main" as default
        
        return service;
    }
}

@Service
public class MultiAppService {
    
    @Autowired
    private WxMaService wxMaService;
    
    public void handleMainAppRequest(String jsCode) {
        // Use main app (default)
        WxMaJscode2SessionResult session = wxMaService.getUserService()
            .getSessionInfo(jsCode);
        // Process main app request...
    }
    
    public void handleSecondaryAppRequest(String jsCode) {
        // Switch to secondary app
        wxMaService.switchoverTo("secondary");
        try {
            WxMaJscode2SessionResult session = wxMaService.getUserService()
                .getSessionInfo(jsCode);
            // Process secondary app request...
        } finally {
            // Switch back to default
            wxMaService.switchoverTo("main");
        }
    }
    
    public void handleTestRequest(String jsCode) {
        // Use test environment
        wxMaService.switchoverTo("test");
        try {
            WxMaJscode2SessionResult session = wxMaService.getUserService()
                .getSessionInfo(jsCode);
            // Process test request...
        } finally {
            wxMaService.switchoverTo("main");
        }
    }
}

Advanced Configuration

Custom HTTP Client Configuration

@Configuration
public class CustomHttpClientConfig {
    
    @Bean
    public WxMaConfig customHttpConfig() {
        WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
        config.setAppid("your-appid");
        config.setSecret("your-secret");
        
        // Custom Apache HttpClient configuration
        ApacheHttpClientBuilder httpClientBuilder = ApacheHttpClientBuilder.create()
            .setConnectionTimeout(10000)        // 10 seconds connection timeout
            .setSocketTimeout(30000)            // 30 seconds socket timeout
            .setConnectionRequestTimeout(5000)   // 5 seconds connection request timeout
            .setMaxTotalConnections(200)        // Max total connections
            .setMaxConnectionsPerRoute(50)      // Max connections per route
            .setRetryCount(3);                  // Retry count
        
        // Custom connection pool configuration
        httpClientBuilder.setConnectionTimeToLive(300, TimeUnit.SECONDS);
        httpClientBuilder.setConnectionKeepAlive(true);
        
        config.setApacheHttpClientBuilder(httpClientBuilder);
        
        // Configure retry behavior
        config.setRetrySleepMillis(1500);
        config.setMaxRetryTimes(3);
        
        return config;
    }
}

Access Token Callback Configuration

@Component
public class TokenManagementService {
    
    @Bean
    public WxMaConfig tokenCallbackConfig() {
        WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
        config.setAppid("your-appid");
        config.setSecret("your-secret");
        
        // Enable token update callbacks
        config.enableUpdateAccessTokenBefore(true);
        
        // Set token update callback
        config.setUpdateAccessTokenBefore(tokenEntity -> {
            logger.info("Access token about to be updated: {} -> {}", 
                       tokenEntity.getOldToken(), tokenEntity.getNewToken());
            
            // Store token update in audit log
            auditService.logTokenUpdate(tokenEntity);
            
            // Update token in external cache if needed
            externalCacheService.updateToken(tokenEntity.getNewToken());
            
            // Notify monitoring system
            monitoringService.notifyTokenUpdate(tokenEntity);
        });
        
        return config;
    }
    
    @Autowired
    private AuditService auditService;
    
    @Autowired
    private ExternalCacheService externalCacheService;
    
    @Autowired
    private MonitoringService monitoringService;
}

Production Configuration Examples

Redis Cluster Configuration

@Configuration
@Profile("production")
public class ProductionRedisConfig {
    
    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration(
            Arrays.asList(
                "redis-cluster-node1:7000",
                "redis-cluster-node2:7000", 
                "redis-cluster-node3:7000"
            )
        );
        clusterConfig.setPassword("redis-password");
        
        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
            .commandTimeout(Duration.ofSeconds(2))
            .shutdownTimeout(Duration.ZERO)
            .build();
            
        return new LettuceConnectionFactory(clusterConfig, clientConfig);
    }
    
    @Bean
    public WxMaConfig productionWxMaConfig(RedisConnectionFactory connectionFactory) {
        WxMaRedisConnectionConfigImpl config = new WxMaRedisConnectionConfigImpl(
            connectionFactory, "prod:wechat:ma:"
        );
        
        config.setAppid("prod-appid");
        config.setSecret("prod-secret");
        config.setToken("prod-token");
        config.setAesKey("prod-aes-key");
        
        // Production settings
        config.useStableAccessToken(true);
        config.setRetrySleepMillis(2000);
        config.setMaxRetryTimes(5);
        
        // Configure for high availability
        config.setHttpProxyHost(null); // No proxy in production
        config.setMaxRetryTimes(10);   // More retries for reliability
        
        return config;
    }
}

Environment-specific Configuration

@Configuration
public class EnvironmentAwareConfig {
    
    @Value("${spring.profiles.active:dev}")
    private String activeProfile;
    
    @Bean
    @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")
    public WxMaConfig devConfig() {
        WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
        config.setAppid("dev-appid");
        config.setSecret("dev-secret");
        config.setRetrySleepMillis(500);  // Faster retries in dev
        config.setMaxRetryTimes(2);       // Fewer retries in dev
        
        return config;
    }
    
    @Bean
    @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "staging") 
    public WxMaConfig stagingConfig(RedisTemplate<String, String> redisTemplate) {
        WxMaRedisConfigImpl config = new WxMaRedisConfigImpl(
            redisTemplate, "staging:wechat:ma:"
        );
        config.setAppid("staging-appid");
        config.setSecret("staging-secret");
        config.useStableAccessToken(true);
        
        return config;
    }
    
    @Bean
    @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "prod")
    public WxMaConfig productionConfig(RedissonClient redissonClient) {
        WxMaRedissonConfigImpl config = new WxMaRedissonConfigImpl(
            redissonClient, "prod:wechat:ma:"
        );
        config.setAppid("prod-appid");
        config.setSecret("prod-secret");
        config.useStableAccessToken(true);
        config.setRetrySleepMillis(3000);
        config.setMaxRetryTimes(8);
        
        return config;
    }
}

Configuration Monitoring and Health Checks

@Component
public class WeChatConfigHealthIndicator implements HealthIndicator {
    
    @Autowired
    private WxMaService wxMaService;
    
    @Override
    public Health health() {
        try {
            WxMaConfig config = wxMaService.getWxMaConfig();
            
            // Check basic configuration
            if (config.getAppid() == null || config.getSecret() == null) {
                return Health.down()
                    .withDetail("error", "Missing required configuration")
                    .build();
            }
            
            // Check access token
            String accessToken = config.getAccessToken();
            boolean tokenExpired = config.isAccessTokenExpired();
            
            Health.Builder builder = Health.up()
                .withDetail("appid", config.getAppid())
                .withDetail("hasAccessToken", accessToken != null)
                .withDetail("tokenExpired", tokenExpired)
                .withDetail("configType", config.getClass().getSimpleName());
            
            // Check Redis connection if using Redis config
            if (config instanceof AbstractWxMaRedisConfig) {
                builder.withDetail("storageType", "Redis");
            } else {
                builder.withDetail("storageType", "Memory");
            }
            
            return builder.build();
            
        } catch (Exception e) {
            return Health.down()
                .withDetail("error", e.getMessage())
                .build();
        }
    }
}

@Component
public class ConfigurationMetrics {
    
    @Autowired
    private WxMaService wxMaService;
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    @PostConstruct
    public void initMetrics() {
        // Track access token age
        Gauge.builder("wechat.access_token.age.seconds")
            .description("Age of current access token in seconds")
            .register(meterRegistry, this, metrics -> {
                try {
                    WxMaConfig config = wxMaService.getWxMaConfig();
                    // Calculate token age based on expiration
                    return config.isAccessTokenExpired() ? -1 : 
                           calculateTokenAge(config.getAccessToken());
                } catch (Exception e) {
                    return -1;
                }
            });
    }
    
    @EventListener
    public void onAccessTokenUpdate(AccessTokenUpdateEvent event) {
        meterRegistry.counter("wechat.access_token.updates.total")
            .increment();
    }
    
    @Scheduled(fixedRate = 60000) // Every minute
    public void recordConfigMetrics() {
        try {
            WxMaConfig config = wxMaService.getWxMaConfig();
            
            // Record token expiration status
            meterRegistry.gauge("wechat.access_token.expired", 
                              config.isAccessTokenExpired() ? 1 : 0);
            
            // Record JSAPI ticket status
            meterRegistry.gauge("wechat.jsapi_ticket.expired",
                              config.isJsapiTicketExpired() ? 1 : 0);
            
        } catch (Exception e) {
            logger.error("Failed to record config metrics: {}", e.getMessage());
        }
    }
}

Configuration Security Best Practices

@Configuration
public class SecureConfigurationExample {
    
    // Use environment variables for sensitive data
    @Value("${WECHAT_APPID}")
    private String appid;
    
    @Value("${WECHAT_SECRET}")
    private String secret;
    
    @Value("${WECHAT_AES_KEY}")
    private String aesKey;
    
    @Bean
    public WxMaConfig secureConfig() {
        WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
        config.setAppid(appid);
        config.setSecret(secret);
        config.setAesKey(aesKey);
        
        // Configure API signature for enhanced security
        config.setApiSignatureRsaPrivateKey(loadRsaPrivateKey());
        config.setApiSignatureAesKey(loadApiAesKey());
        
        return config;
    }
    
    private String loadRsaPrivateKey() {
        try {
            // Load from secure key management system
            return keyManagementService.getPrivateKey("wechat-rsa");
        } catch (Exception e) {
            logger.error("Failed to load RSA private key: {}", e.getMessage());
            throw new ConfigurationException("Security key loading failed", e);
        }
    }
    
    private String loadApiAesKey() {
        try {
            return keyManagementService.getAesKey("wechat-api");
        } catch (Exception e) {
            logger.error("Failed to load API AES key: {}", e.getMessage());
            throw new ConfigurationException("Security key loading failed", e);
        }
    }
    
    @Autowired
    private KeyManagementService keyManagementService;
}

This configuration module provides comprehensive setup options for WeChat MiniApp applications, supporting both development and production environments with proper security, monitoring, and scalability considerations.

Install with Tessl CLI

npx tessl i tessl/maven-com-github-binarywang--weixin-java-miniapp

docs

analytics.md

cloud-development.md

configuration.md

core-services.md

development-tools.md

ecommerce.md

index.md

live-streaming.md

logistics.md

media-content.md

messaging.md

qr-codes.md

user-management.md

tile.json