How to Configure SMS Service Integration with SMS4J in ContiNew Admin

ContiNew Admin integrates SMS4J by storing provider configurations in the database, converting them to SMS4J BaseConfig objects via SmsConfigUtil, and dynamically registering them with SmsFactory for runtime SMS sending.

ContiNew Admin provides a unified SMS service layer using the SMS4J library, enabling dynamic multi-provider support without application restarts. This guide explains how the system converts database-stored configurations into SMS4J-compatible objects and manages their lifecycle from startup to runtime CRUD operations according to the continew-org/continew-admin source code.

Dependency Declaration

The SMS4J integration begins with the Spring Boot starter dependency declared in the system module's Maven configuration.

Add the following to continew-system/pom.xml:

<dependency>
    <groupId>org.dromara.sms4j</groupId>
    <artifactId>sms4j-spring-boot-starter</artifactId>
</dependency>

This dependency provides the core SmsFactory and BaseConfig classes used throughout the integration.

Data Model and Configuration Storage

SMS configurations persist in the sys_sms_config database table and map to the SmsConfigResp DTO. This entity contains all fields required by SMS4J providers, including credentials, signatures, and provider-specific JSON parameters.

In continew-system/src/main/java/top/continew/admin/system/model/resp/SmsConfigResp.java:

public class SmsConfigResp extends BaseDetailResp {
    private String name;
    private String supplier;           // e.g., "cloopen", "aliyun"
    private String accessKey;
    private String secretKey;
    private String signature;
    private String templateId;
    private Integer weight;
    private Integer retryInterval;
    private Integer maxRetries;
    private String supplierConfig;     // JSON string for provider-specific params
    private Boolean isDefault;
    private DisEnableStatusEnum status;
}

The supplier field corresponds to SMS4J's SupplierConstant values, while supplierConfig holds optional provider-specific parameters as a JSON string.

Converting Database Configurations to SMS4J BaseConfig

The SmsConfigUtil.from() method translates SmsConfigResp objects into SMS4J provider-specific BaseConfig implementations. This utility maps standard fields (like accessKey) to SMS4J property names (like accessKeyId) and merges provider-specific JSON configurations.

In continew-system/src/main/java/top/continew/admin/system/config/sms/SmsConfigUtil.java:

public static BaseConfig from(SmsConfigResp smsConfig) {
    if (smsConfig == null) return null;
    BaseProviderFactory<?, ?> providerFactory =
        ProviderFactoryHolder.requireForSupplier(smsConfig.getSupplier());
    if (providerFactory == null) return null;

    Map<String, Object> configInfo = MapUtil.newHashMap();
    configInfo.put("configId", smsConfig.getId().toString());
    configInfo.put("accessKeyId", smsConfig.getAccessKey());
    configInfo.put("accessKeySecret", smsConfig.getSecretKey());
    configInfo.put("signature", smsConfig.getSignature());
    configInfo.put("templateId", smsConfig.getTemplateId());
    
    if (smsConfig.getWeight() != null) configInfo.put("weight", smsConfig.getWeight());
    if (smsConfig.getRetryInterval() != null) configInfo.put("retryInterval", smsConfig.getRetryInterval());
    if (smsConfig.getMaxRetries() != null) configInfo.put("maxRetries", smsConfig.getMaxRetries());
    
    if (StrUtil.isNotBlank(smsConfig.getSupplierConfig())) {
        configInfo.putAll(JSONUtils.toBean(smsConfig.getSupplierConfig(), Map.class));
    }
    return (BaseConfig) BeanUtil.toBean(configInfo, providerFactory.getConfigClass());
}

This method uses reflection to instantiate the correct configuration class for each SMS provider (e.g., AlibabaSmsConfig, TencentSmsConfig).

Loading Configurations at Application Startup

The SmsConfigLoader class implements ApplicationRunner to register all enabled SMS configurations when the Spring Boot application starts. It queries the database via SmsReadConfigDatabaseImpl and registers each configuration with SmsFactory.

In continew-system/src/main/java/top/continew/admin/system/config/sms/SmsConfigLoader.java:

public void run(ApplicationArguments args) {
    SmsFactory.createSmsBlend(smsReadConfig);
    SmsProxyFactory.addPreProcessor(smsLogProcessor);
    log.debug("短信配置初始化完成");
}

The SmsReadConfigDatabaseImpl provides the database-backed configuration source:

public List<BaseConfig> getSupplierConfigList() {
    SmsConfigQuery query = new SmsConfigQuery();
    query.setStatus(DisEnableStatusEnum.ENABLE);
    List<SmsConfigResp> list = smsConfigService.list(query, null);
    return CollUtil.isEmpty(list) ? List.of()
                                 : CollUtils.mapToList(list, SmsConfigUtil::from);
}

This implementation ensures only configurations with status = ENABLE are loaded at startup.

Dynamic Reload on CRUD Operations

When administrators create, update, or delete SMS configurations via the REST API, SmsConfigServiceImpl dynamically reloads the affected configuration without requiring an application restart.

In continew-system/src/main/java/top/continew/admin/system/service/impl/SmsConfigServiceImpl.java:

private void load(SmsConfigDO entity) {
    SmsConfigResp smsConfig = this.get(entity.getId());
    BaseConfig config = SmsConfigUtil.from(smsConfig);
    if (config != null) SmsFactory.createSmsBlend(config);
}

private void unload(String configId) {
    if (SmsFactory.getSmsBlend(configId) != null) SmsFactory.unregister(configId);
}

The service automatically invokes load() after creating a new configuration and unload() followed by load() after updates or deletions. This ensures the SMS4J runtime always reflects the current database state.

Sending SMS Messages

Once a configuration is loaded (either at startup or after creation), send SMS messages using the configuration ID (database primary key as string) to retrieve the appropriate SmsBlend instance.

import org.dromara.sms4j.api.proxy.SmsFactory;
import org.dromara.sms4j.api.entity.SmsResponse;

public class SmsService {
    public void sendVerificationCode(String phone, String configId) {
        SmsResponse result = SmsFactory.getSmsBlend(configId)
                .sendMessage(phone, "Your verification code is 123456");
        System.out.println("SMS sent, status: " + result.getStatus());
    }
}

All sent messages are automatically logged via SmsLogProcessor (registered in SmsConfigLoader) and stored in the sys_sms_log table for auditing purposes.

Configuring Provider-Specific Parameters

Some SMS providers require additional parameters beyond the standard access keys. ContiNew Admin supports these through the supplierConfig JSON field.

For example, to configure Alibaba Cloud SMS with region-specific settings:

{
  "region": "cn-hangzhou",
  "apiVersion": "2017-05-25"
}

When creating a configuration via the API or UI, populate the fields as follows:

  • supplier: aliyun
  • accessKey: Your Alibaba Cloud AccessKey ID
  • secretKey: Your Alibaba Cloud AccessKey Secret
  • signature: Your registered SMS signature
  • templateId: The SMS template code (e.g., SMS_12345678)
  • supplierConfig: {"region":"cn-hangzhou","apiVersion":"2017-05-25"}

The SmsConfigUtil.from() method merges these JSON properties into the final BaseConfig object using configInfo.putAll().

Summary

  • Dependency: Add sms4j-spring-boot-starter to continew-system/pom.xml to enable SMS4J support.
  • Data Model: Configurations store in sys_sms_config and map to SmsConfigResp with provider-specific JSON in supplierConfig.
  • Conversion: SmsConfigUtil.from() translates database entities to SMS4J BaseConfig objects using provider factories.
  • Startup Loading: SmsConfigLoader implements ApplicationRunner to register all enabled configs via SmsReadConfigDatabaseImpl.
  • Dynamic Management: SmsConfigServiceImpl calls load() and unload() methods to refresh configurations immediately after CRUD operations.
  • Sending: Use SmsFactory.getSmsBlend(configId).sendMessage() to send SMS using a specific configuration by its database ID.

Frequently Asked Questions

What is the database table name for SMS configurations in ContiNew Admin?

The system stores SMS configurations in the sys_sms_config table, which maps to the SmsConfigDO entity and SmsConfigResp DTO. This table contains fields for supplier type, credentials, signatures, template IDs, and a JSON column for provider-specific settings.

How does ContiNew Admin handle SMS configuration changes without restarting the application?

When configurations are created, updated, or deleted through SmsConfigServiceImpl, the service automatically invokes load() to register new configurations with SmsFactory.createSmsBlend() or unload() to remove them via SmsFactory.unregister(). This dynamic reload mechanism ensures SMS4J reflects database changes immediately without requiring an application restart.

What dependency is required to enable SMS4J integration in ContiNew Admin?

The integration requires the org.dromara.sms4j:sms4j-spring-boot-starter dependency declared in continew-system/pom.xml. This starter provides the SmsFactory, BaseConfig, and provider factory classes necessary for the unified SMS abstraction layer.

How do I send an SMS message programmatically after configuring a provider?

After creating and enabling a configuration (which automatically registers with SMS4J), retrieve the SmsBlend instance using SmsFactory.getSmsBlend(configId) where configId is the string representation of the configuration's database ID. Then call sendMessage(phoneNumber, content) to dispatch the SMS. The system automatically logs the attempt to sys_sms_log via the SmsLogProcessor pre-processor.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →