SpringBoot调用华为云短信实现发短信功能

参考 发送短信_消息&短信 MSGSMS_华为云

1.引入华为云短信pom依赖

复制代码
<dependency>
    <groupId>com.huaweicloud.sdk</groupId>
    <artifactId>huaweicloud-sdk-smsapi</artifactId>
    <version>3.1.125</version>
</dependency>

2.参考华为云短信官方文档

Java_消息&短信 MSGSMS_华为云

java 复制代码
import com.huaweicloud.sdk.core.auth.BasicCredentials;
import com.huaweicloud.sdk.core.http.HttpMethod;
import com.huaweicloud.sdk.core.http.HttpRequest;
import com.huaweicloud.sdk.smsapi.utils.SmsAkSkSigner;

import com.knowdee.cc.common.domain.CcSendMsgInfo;
import com.knowdee.cc.common.service.ICcSendMsgInfoService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

import static java.nio.charset.StandardCharsets.UTF_8;

@Service
@Slf4j
public class HuaweiSmsService {

    @Value("${huawei.cloud.sms.access-key}")
    private String accessKey;

    @Value("${huawei.cloud.sms.secret-key}")
    private String secretKey;

    @Value("${huawei.cloud.sms.signature}")
    private String signature;

    @Value("${huawei.cloud.sms.endpoint}")
    private String endpoint;

    @Resource
    private ICcSendMsgInfoService ccSendMsgInfoService;

    private static CloseableHttpClient httpClient = null;

    public static void main(String[] args) throws Exception {
        /*
         * Send an SMS message using a special AK/SK authentication algorithm.
         * When the MSGSMS is used to send SMS messages, the AK is app_key, and the SK is app_secret.
         * There will be security risks if the app_key/app_secret used for authentication is directly written into code.
         * We suggest encrypting the app_key/app_secret in the configuration file or environment variables for storage.
         * In this sample, the app_key/app_secret is stored in environment variables for identity authentication.
         * Before running this sample, set the environment variables CLOUD_SDK_MSGSMS_APPKEY and CLOUD_SDK_MSGSMS_APPSECRET.
         * CLOUD_SDK_MSGSMS_APPKEY indicates the application key (app_key), and CLOUD_SDK_MSGSMS_APPSECRET indicates the application secret (app_secret).
         * You can obtain the value from Application Management on the console or by calling the open API of Application Management.
         */
        //String ak = System.getenv("CLOUD_SDK_MSGSMS_APPKEY");
        //String sk = System.getenv("CLOUD_SDK_MSGSMS_APPSECRET");
//        if (Objects.isNull(ak) || Objects.isNull(sk)) {
//            System.out.println("the ak or sk is null. please config the environment CLOUD_SDK_MSGSMS_APPKEY and CLOUD_SDK_MSGSMS_APPSECRET first!");
//            return;
//        }

        // To prevent API invoking failures caused by HTTPS certificate authentication failures, ignore the certificate trust issue to simplify the sample code.
//        httpClient = createIgnoreSSLHttpClient();
//        HuaweiSmsService huaweiSmsService = new HuaweiSmsService();
//        huaweiSmsService.sendSms("","xALlH903ix07t4agS5122U0O6A9J", "CSjuauYNbBHI0FqH3rCUI3Dpl0yA");
    }

    /**
     * Example of Invoking the batchSendSms Interface to Send an SMS Message
     *
     * @param ak AK is the app_key of the SMS application.
     * @param sk SK is the app_secret of the SMS application.
     * @throws UnsupportedEncodingException
     */
    public Boolean sendSms(String templateId, String phone, String content) throws UnsupportedEncodingException {
        // This address is of Beijing 4. Replace it with the actual value.
        //String uri = "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1";
        try {
            httpClient = createIgnoreSSLHttpClient();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String uri = endpoint + "/sms/batchSendSms/v1";
        // Construct the message body of the sample code.
        // For details about how to construct a body, see the API description.
        StringBuilder body = new StringBuilder();

        appendToBody(body, "from=", signature);
        appendToBody(body, "&to=", phone);
        appendToBody(body, "&templateId=", templateId);
        appendToBody(body, "&templateParas=", "[\"" + content + "\"]");
        //appendToBody(body, "&statusCallback=", "https://test/report");
        log.info("body:" + body);
        //System.out.println("body:" + body);

        // Signature operation of the batchsendsms interface
        Boolean flag = false;
        Map<String, String> signedHeaders = sign(accessKey, secretKey, body.toString(), uri);
        if (Objects.isNull(signedHeaders)) {
            //System.out.println("sign failed!");
            log.info("sign failed!");
            return flag;
        }

        // Print Signature Results
        //System.out.println("BatchSendSms sign result:" + signedHeaders);
        log.info("BatchSendSms sign result:" + signedHeaders);

        HttpPost postRequest = new HttpPost(uri);
        postRequest.setHeader("Accept", "application/json");
        postRequest.setHeader("Content-Type", "application/x-www-form-urlencoded");
        signedHeaders.forEach((key, value) -> postRequest.setHeader(key, value));
        postRequest.setEntity(new StringEntity(body.toString(), StandardCharsets.UTF_8));

        // Invoke /sms/batchSendSms/v1 api to send messages
        try (CloseableHttpResponse response = httpClient.execute(postRequest)) {
            // Print the response status code.
//            System.out.println("Response Status Code: " + response.getStatusLine().getStatusCode());
//            System.out.println("Response Content: " + EntityUtils.toString(response.getEntity()));
            log.info("Response Status Code: " + response.getStatusLine().getStatusCode());
            log.info("Response Content: " + EntityUtils.toString(response.getEntity()));
            if (response.getStatusLine().getStatusCode() == 200) {
                flag = true;
            }else{
                CcSendMsgInfo ccSendMsgInfo = new CcSendMsgInfo();
                ccSendMsgInfo.setContent(content);
                ccSendMsgInfo.setTemplateId(templateId);
                ccSendMsgInfo.setTime(new Date());
                ccSendMsgInfo.setPhone(phone);
                ccSendMsgInfo.setFailInfo(response.getStatusLine().getReasonPhrase());
                ccSendMsgInfoService.getBaseMapper().insert(ccSendMsgInfo);
            }
            // Print the response content.
        } catch (IOException e) {
            //System.out.println("response exception:" + e);
            log.info("response exception:" + e);
        }
        return flag;
    }

    /**
     * Create an HTTP client that ignores the HTTPS certificate check.
     *
     * @return HTTP client
     * @throws Exception
     */
    private CloseableHttpClient createIgnoreSSLHttpClient() throws Exception {
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (x509CertChain, authType) -> true).build();
        return HttpClients.custom().setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)).build();
    }

    /**
     * Add the parameter to the original body after URL encoding.
     *
     * @param body Message body
     * @param key  Parameter key
     * @param val  Parameter value
     * @throws UnsupportedEncodingException
     */
    private static void appendToBody(StringBuilder body, String key, String val) throws UnsupportedEncodingException {
        if (null != val && !val.isEmpty()) {
            body.append(key).append(URLEncoder.encode(val, UTF_8.name()));
        }
    }

    /**
     * The algorithm for generating the signature header field (Authorization, X-Sdk-Date, Host) is provided.
     *
     * @param ak       AK is the app_key of the SMS application.
     * @param sk       SK is the app_secret of the SMS application.
     * @param body     Message body to be signed
     * @param endpoint the api uri
     * @return signature header field (Authorization, X-Sdk-Date, Host)
     */
    private static Map<String, String> sign(String ak, String sk, String body, String endpoint) {
        // The signature algorithm uses the AK and SK signature algorithms provided by HUAWEI CLOUD IAM and API Gateway.
        // Signature algorithm implementation. The capabilities provided by the SDK are used here.
        // Developers can also use the signature capability provided by HUAWEI CLOUD APIG. For details, see the following website: https://support.huaweicloud.com/devg-apisign/api-sign-sdk-java.html
        // For the signature operation of an interface, the signature must contain the body.
        return SmsAkSkSigner.sign(HttpRequest.newBuilder().withBodyAsString(body)
                        .withMethod(HttpMethod.POST)
                        .withEndpoint(endpoint)
                        .addHeader("Content-Type", "application/x-www-form-urlencoded").build(),
                new BasicCredentials().withAk(ak).withSk(sk));
    }
}

3.踩坑问题

3.1如果使用短信模版时,要注意短信templateParas参数的个数

相关推荐
东阳马生架构1 小时前
Netty基础—4.NIO的使用简介一
java·网络·netty
luckyext1 小时前
Postman用JSON格式数据发送POST请求及注意事项
java·前端·后端·测试工具·c#·json·postman
程序视点1 小时前
Redis集群机制及一个Redis架构演进实例
java·redis·后端
鱼樱前端1 小时前
Navicat17基础使用
java·后端
黑风风2 小时前
深入理解Spring Boot Starter及如何自定义Starter
java·spring boot·后端
px52133442 小时前
Solder leakage problems and improvement strategies in electronics manufacturing
java·前端·数据库·pcb工艺
鱼樱前端2 小时前
Mac M1安装MySQL步骤
java·后端
白衣神棍2 小时前
【八股文】ArrayList和LinkedList的区别
java
啥都想学的又啥都不会的研究生2 小时前
Redis设计与实现-数据持久化
java·数据库·redis·笔记·缓存·面试
王网aaa3 小时前
堆结构和堆排序
java·算法·排序算法