# How to Configure SMS Service Integration with SMS4J in ContiNew Admin

> Learn to configure SMS service integration with SMS4J in ContiNew Admin. Store provider settings in the database, convert them to BaseConfig objects, and dynamically register with SmsFactory for immediate SMS sending.

- Repository: [OpenContiNew/continew-admin](https://github.com/continew-org/continew-admin)
- Tags: how-to-guide
- Published: 2026-02-28

---

**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`](https://github.com/continew-org/continew-admin/blob/main/continew-system/pom.xml):

```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`](https://github.com/continew-org/continew-admin/blob/main/continew-system/src/main/java/top/continew/admin/system/model/resp/SmsConfigResp.java):

```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`](https://github.com/continew-org/continew-admin/blob/main/continew-system/src/main/java/top/continew/admin/system/config/sms/SmsConfigUtil.java):

```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`](https://github.com/continew-org/continew-admin/blob/main/continew-system/src/main/java/top/continew/admin/system/config/sms/SmsConfigLoader.java):

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

```

The `SmsReadConfigDatabaseImpl` provides the database-backed configuration source:

```java
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`](https://github.com/continew-org/continew-admin/blob/main/continew-system/src/main/java/top/continew/admin/system/service/impl/SmsConfigServiceImpl.java):

```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.

```java
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:

```json
{
  "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`](https://github.com/continew-org/continew-admin/blob/main/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`](https://github.com/continew-org/continew-admin/blob/main/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.