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参数的个数

相关推荐
m0_587383008 分钟前
智慧场馆解决方案实战指南:从系统架构到落地部署全解析
java·spring boot·架构·系统架构
ZC跨境爬虫12 分钟前
LeetCode 13. 罗马数字转整数(多解法详解 + Java Python 实现)
java·python·leetcode
省长18 分钟前
Sa-Token v1.46.0 发布 🚀,来看看有没有令你心动的功能!
java·后端·开源
LayZhangStrive42 分钟前
融360 一面
java·面试·后端开发
城管不管1 小时前
重生——第十次面试之开源中国一面挂
java·linux·开发语言·算法·面试·职场和发展·开源
Java小白笔记1 小时前
Windows系统免软件命令激活
java·网络·人工智能·windows·ai·ai编程
爱敲键盘的猴子1 小时前
深入理解 Java HashMap
java·hashmap
霸道流氓气质1 小时前
Java开发者AI编程常用MCP、Skills、Rules全景汇总
java·开发语言·ai编程
天涯醉青楼2 小时前
Spring Boot 接口返回 Bean 时字段名“变形”的深度剖析与解决方案
java
步行cgn2 小时前
MyBatis 高级映射与延迟加载完全指南
java·tomcat·mybatis