类名: OkHTTPUtils - *
说明: 用于封装请求后返回的参数 - * - * @author :Wind - * @date :2022/7/11 16:12 - **/ - public class OKResponse { - private ResponseBody body; - private Headers headers; - private Integer code; - - public ResponseBody getBody() { - return body; - } - - public OKResponse setBody(ResponseBody body) { - this.body = body; - return this; - } - - public Headers getHeaders() { - return headers; - } - - public OKResponse setHeaders(Headers headers) { - this.headers = headers; - return this; - } - - public Integer getCode() { - return code; - } - - public OKResponse setCode(Integer code) { - this.code = code; - return this; - } - - /** - *
说明:将返回结果序列化到实体类中 - *
传入对象必须实现了getter和setter方法,否则将序列化失败
- * @name: getJSONBody
- * @param t 要序列化的对象
- * @author :Wind
- */
- public 说明:将返回结果序列化为一个json对象
- *
- * @name: getJSONObject
- * @author :Wind
- */
- public JSONObject getJSONObject(){
- try {
- return JSONObject.parseObject(this.getBody().string());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public String toString() {
- return "OKResponse{" +
- "body=" + body +
- ", headers=" + headers +
- ", code=" + code +
- '}';
- }
- }
}
diff --git a/sms-aggregation-comm/src/main/java/kim/wind/sms/comm/utils/http/OKResponse.java b/sms-aggregation-comm/src/main/java/kim/wind/sms/comm/utils/http/OKResponse.java
new file mode 100644
index 00000000..41b907e5
--- /dev/null
+++ b/sms-aggregation-comm/src/main/java/kim/wind/sms/comm/utils/http/OKResponse.java
@@ -0,0 +1,84 @@
+package kim.wind.sms.comm.utils.http;
+
+import com.alibaba.fastjson.JSONObject;
+import okhttp3.Headers;
+import okhttp3.ResponseBody;
+
+import java.io.IOException;
+
+/**
+ * OKResponse
+ * 用于封装请求后返回的参数
+ *
+ * @author :Wind
+ * 2023/3/31 23:52
+ **/
+public class OKResponse {
+ private ResponseBody body;
+ private Headers headers;
+ private Integer code;
+
+ public ResponseBody getBody() {
+ return body;
+ }
+
+ public OKResponse setBody(ResponseBody body) {
+ this.body = body;
+ return this;
+ }
+
+ public Headers getHeaders() {
+ return headers;
+ }
+
+ public OKResponse setHeaders(Headers headers) {
+ this.headers = headers;
+ return this;
+ }
+
+ public Integer getCode() {
+ return code;
+ }
+
+ public OKResponse setCode(Integer code) {
+ this.code = code;
+ return this;
+ }
+
+ /**
+ * 说明:将返回结果序列化到实体类中
+ * 传入对象必须实现了getter和setter方法,否则将序列化失败
+ * @name: getJSONBody
+ * @param t 要序列化的对象
+ * @author :Wind
+ */
+ public 说明:将返回结果序列化为一个json对象
+ *
+ * @name: getJSONObject
+ * @author :Wind
+ */
+ public JSONObject getJSONObject(){
+ try {
+ return JSONObject.parseObject(this.getBody().string());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "OKResponse{" +
+ "body=" + body +
+ ", headers=" + headers +
+ ", code=" + code +
+ '}';
+ }
+}
\ No newline at end of file
diff --git a/sms-aggregation-huawei/.mvn/wrapper/maven-wrapper.jar b/sms-aggregation-huawei/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 00000000..bf82ff01
Binary files /dev/null and b/sms-aggregation-huawei/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/sms-aggregation-huawei/.mvn/wrapper/maven-wrapper.properties b/sms-aggregation-huawei/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 00000000..ca5ab4ba
--- /dev/null
+++ b/sms-aggregation-huawei/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
diff --git a/sms-aggregation-huawei/pom.xml b/sms-aggregation-huawei/pom.xml
new file mode 100644
index 00000000..3bec5be1
--- /dev/null
+++ b/sms-aggregation-huawei/pom.xml
@@ -0,0 +1,37 @@
+
+ 华为云短信应用常量
+ *
+ * @author :Wind
+ * 2023/3/31 19:33
+ **/
+public abstract class Constant {
+ /**
+ * 用于格式化鉴权头域,给"Authorization"参数赋值
+ */
+ public static final String AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\"";
+ /**
+ * 用于格式化鉴权头域,给"X-WSSE"参数赋值
+ */
+ public static final String WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\"";
+ /**
+ * 访问URI
+ */
+ public static final String REQUEST_URL = "/sms/batchSendSms/v1";
+ /**
+ * Content-Type
+ */
+ public static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
+ /**
+ * 华为云规定 java时间格式
+ */
+ public static final String JAVA_DATE = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+ private Constant() {
+ }
+}
diff --git a/sms-aggregation-huawei/src/main/java/kim/wind/sms/huawei/entity/HuaweiError.java b/sms-aggregation-huawei/src/main/java/kim/wind/sms/huawei/entity/HuaweiError.java
new file mode 100644
index 00000000..9110caa6
--- /dev/null
+++ b/sms-aggregation-huawei/src/main/java/kim/wind/sms/huawei/entity/HuaweiError.java
@@ -0,0 +1,58 @@
+package kim.wind.sms.huawei.entity;
+
+/**
+ * HuaweiError
+ * 华为官方状态码枚举
+ *
+ * @author :Wind
+ * 2023/3/31 22:11
+ **/
+public enum HuaweiError {
+ E000000("000000","短信平台处理请求成功"),
+ E200015("E200015","待发送短信数量太大"),
+ E200028("E200028","模板变量校验失败"),
+ E200029("E200029","E200029"),
+ E200030("E200030","模板未激活"),
+ E200031("E200031","协议校验失败"),
+ E200033("E200033","模板类型不正确"),
+ E200041("E200041","同一短信内容接收号码重复")
+ ;
+
+ private final String value;
+
+ private final String code;
+
+ HuaweiError(String code, String value) {
+ this.value = value;
+ this.code = code;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public String getCode() {
+ return code;
+ }
+ public static String getValue(String code){
+ switch (code){
+ case "000000":
+ return E000000.getValue();
+ case "E200015":
+ return E200015.getValue();
+ case "E200028":
+ return E200028.getValue();
+ case "E200029":
+ return E200029.getValue();
+ case "E200030":
+ return E200030.getValue();
+ case "E200031":
+ return E200031.getValue();
+ case "E200033":
+ return E200033.getValue();
+ case "E200041":
+ return E200041.getValue();
+ }
+ return "";
+ }
+}
diff --git a/sms-aggregation-huawei/src/main/java/kim/wind/sms/huawei/entity/HuaweiResponse.java b/sms-aggregation-huawei/src/main/java/kim/wind/sms/huawei/entity/HuaweiResponse.java
new file mode 100644
index 00000000..490f3efe
--- /dev/null
+++ b/sms-aggregation-huawei/src/main/java/kim/wind/sms/huawei/entity/HuaweiResponse.java
@@ -0,0 +1,26 @@
+package kim.wind.sms.huawei.entity;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * HuaweiResponse
+ * 华为响应参数
+ *
+ * @author :Wind
+ * 2023/3/31 22:20
+ **/
+@Data
+public class HuaweiResponse {
+
+ /** 请求返回的结果码*/
+ private String code;
+
+ /** 请求返回的结果码描述*/
+ private String description;
+
+ /** 短信ID列表,当目的号码存在多个时,每个号码都会返回一个SmsID。
+ 当返回异常响应时不携带此字段*/
+ private List 短信ID列表
+ *
+ * @author :Wind
+ * 2023/3/31 21:55
+ **/
+@Data
+public class SmsId {
+
+ /** 短信的唯一标识*/
+ private String smsMsgId;
+
+ /** 短信发送方的号码*/
+ private String from;
+
+ /** 短信接收方的号码*/
+ private String originTo;
+
+ /** 短信状态码*/
+ private String status;
+
+ /** 短信资源的创建时间,即短信平台接收到用户发送短信请求的时间,为UTC时间*/
+ private String createTime;
+
+
+}
diff --git a/sms-aggregation-huawei/src/main/java/kim/wind/sms/huawei/service/HuaweiBuilder.java b/sms-aggregation-huawei/src/main/java/kim/wind/sms/huawei/service/HuaweiBuilder.java
new file mode 100644
index 00000000..aa7ecdec
--- /dev/null
+++ b/sms-aggregation-huawei/src/main/java/kim/wind/sms/huawei/service/HuaweiBuilder.java
@@ -0,0 +1,145 @@
+package kim.wind.sms.huawei.service;
+
+import kim.wind.sms.huawei.constant.Constant;
+import kim.wind.sms.huawei.entity.HuaweiError;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+public class HuaweiBuilder {
+ private HuaweiBuilder(){}
+
+ /**
+ * buildWsseHeader
+ * 构造X-WSSE参数值
+ * @author :Wind
+ */
+ static String buildWsseHeader(String appKey, String appSecret) {
+ if (null == appKey || null == appSecret || appKey.isEmpty() || appSecret.isEmpty()) {
+ System.out.println("buildWsseHeader(): appKey or appSecret is null.");
+ return null;
+ }
+ String time = dateFormat(new Date());
+ String nonce = UUID.randomUUID().toString().replace("-", ""); //Nonce
+ MessageDigest md;
+ byte[] passwordDigest = null;
+
+ try {
+ md = MessageDigest.getInstance("SHA-256");
+ md.update((nonce + time + appSecret).getBytes());
+ passwordDigest = md.digest();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+
+ String passwordDigestBase64Str = Base64.getEncoder().encodeToString(passwordDigest); //PasswordDigest
+ //若passwordDigestBase64Str中包含换行符,请执行如下代码进行修正
+ //passwordDigestBase64Str = passwordDigestBase64Str.replaceAll("[\\s*\t\n\r]", "");
+ return String.format(Constant.WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, time);
+ }
+
+ static void trustAllHttpsCertificates() throws Exception {
+ TrustManager[] trustAllCerts = new TrustManager[] {
+ new X509TrustManager() {
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ return;
+ }
+ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ return;
+ }
+ public X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+ }
+ };
+ SSLContext sc = SSLContext.getInstance("SSL");
+ sc.init(null, trustAllCerts, null);
+ HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
+ }
+
+ /**
+ * buildRequestBody
+ * 构造请求Body体
+ * @param sender
+ * @param receiver
+ * @param templateId
+ * @param templateParas
+ * @param statusCallBack
+ * @param signature | 签名名称,使用国内短信通用模板时填写
+ * @author :Wind
+ */
+ static String buildRequestBody(String sender, String receiver, String templateId, String templateParas,
+ String statusCallBack, String signature) {
+ if (null == sender || null == receiver || null == templateId || sender.isEmpty() || receiver.isEmpty()
+ || templateId.isEmpty()) {
+ System.out.println("buildRequestBody(): sender, receiver or templateId is null.");
+ return null;
+ }
+ Map