【Delphi】开发阿里云发送短信控件(三)含源代码

Delphi 阿里云短信控件实现

一、数据结构定义

对于每一个函数,都有返回参数和专有参数,为此,专门定义了这些数据结构,这些参数的定义和阿里约定是完全一致的,包括变量名称,具体如下:

//发送短信返回结果记录
  TRET_SendSms = record
    BizId         : string;  //发送回执ID,可根据该ID在接口QuerySendDetails中查询具体的发送状态。
    Code          : string;  //请求状态码。 返回OK代表请求成功。其他错误码详见错误码列表。
    Message_      : string;  //状态码的描述。
    RequestId     : string;  //请求ID。
  end;

  //签名参数记录
  TSignature_Param = record
    ParamName   : string;    //参数名称
    ParamValue  : string;    //参数值
  end;

  //签名参数记录列表
  TSignature_Params = TArray<TSignature_Param>;

  //查看新增签名状态的返回结果
  TRET_QuerySmsSign = record
    Code          : String;   //OK 请求状态码。返回OK代表请求成功。其他错误码详见错误码列表。
    CreateDate    : string;   //2019-01-08 16:44:13 短信签名的创建日期和时间。
    Message_      : String;   //OK 状态码描述。
    Reason        : string;   //文件不能证明信息真实性,请重新上传 审核备注。如果审核状态为审核通过或审核中,参数Reason显示为“无审核备注”。如果审核状态为审核未通过,参数Reason显示审核的具体原因。
    RequestId     : string;   //CC89A90C-978F-46AC-B80D-54738371E7CA 请求ID。
    SignName      : String;   //阿里云 短信签名。
    SignStatus    : integer;  //1 签名审核状态。其中: 0:审核中。1:审核通过。2:审核失败,请在返回参数Reason中查看审核失败原因。
  end;

  //增加模板返回记录结构
  TRET_AddSmsTemplate = record
    Code        : String;  //OK 请求状态码。返回OK代表请求成功。其他错误码详见错误码列表。
    Message_    : String;  //OK 状态码的描述。
    RequestId   : String;  //F655A8D5-B967-440B-8683-DAD6FF8DE990 请求ID。
    TemplateCode: String;  //SMS_152550005 短信模板CODE。您可以使用模板CODE通过API接口QuerySmsTemplate或在控制台查看模板申请状态和结果。
  end;

  //查询短信模板返回记录结构
  TRET_QuerySmsTemplate = record
    Code          : String;  //OK 请求状态码。返回OK代表请求成功。其他错误码详见错误码列表。
    CreateDate    : String;  //2019-06-04 11:42:17 短信模板的创建日期和时间。
    Message_      : string;  //OK 状态码的描述。
    Reason        : String;  //非验证码类型短信,请选择短信通知类型为推广短信。审核备注。如果审核状态为审核通过或审核中,参数Reason显示为“无审核备注”。如果审核状态为审核未通过,参数Reason显示审核的具体原因。
    RequestId     : String;  //0A974B78-02BF-4C79-ADF3-90CFBA1B55B1 请求ID。
    TemplateCode  : String;  //SMS_167035184 短信模板CODE。
    TemplateContent : string;//亲爱的会员!阿里云短信服务祝您新年快乐!模板内容。
    TemplateName  : String;  //阿里云短信测试模板 模板名称。
    TemplateStatus: Integer; //1 模板审核状态。其中:0:审核中。1:审核通过。2:审核失败,请在返回参数Reason中查看审核失败原因。
    TemplateType  : Integer; //1 短信类型。其中:0:验证码。1:短信通知。2:推广短信。3:国际/港澳台消息。、
  end;

  //查询发送记录明细结构
  TRET_SmsSendDetailDTO = record
    Content       : String;  //【阿里云】验证码为:123,您正在登录,若非本人操作,请勿泄露短信内容。
    ErrCode       : string;  //DELIVERED 运营商短信状态码。短信发送成功:DELIVERED。短信发送失败:失败错误码请参考错误码文档。
    OutId         : string;  //123 外部流水扩展字段。
    PhoneNum      : String;  //15200000000 接收短信的手机号码。
    ReceiveDate   : String;  //2019-01-08 16:44:13 短信接收日期和时间。
    SendDate      : String;  //2019-01-08 16:44:10 短信发送日期和时间。
    SendStatus    : Byte;    //短信发送状态,包括:1:等待回执。2:发送失败。3:发送成功。
    SendStatusMsg : string;  //显示对应 SendStatus 的中文信息
    TemplateCode  : String;  //SMS_122310183 短信模板ID。
  end;


  TRET_QuerySendDetails = record
    Code      : String;  //OK 请求状态码。返回OK代表请求成功。其他错误码详见错误码列表。
    Message_  : String;  //OK 状态码的描述。
    RequestId : String;  //819BE656-D2E0-4858-8B21-B2E477085AAF 请求ID。
    SmsSendDetailDTO : TArray<TRET_SmsSendDetailDTO>;
    TotalCount: String;  //1 短信发送总条数。
  end;
  //返回参数格式定义
  TRet_Format = (JSON,XML);

二、控件公开属性定义

在这里插入图片描述
具体的参数定义如下:

published
    //声明属性
    property P_accessKeyId: string read FP_accessKeyId write Set_FP_accessKeyId;
    property P_accessSecret: string read FP_accessSecret write Set_FP_accessSecret;
    property P_Format: TRet_Format read FP_Format write Set_FP_Format default TRet_Format.JSON;
    property P_RegionId: string read FP_RegionId write Set_FP_RegionId;
    property P_SignatureMethod: string read FP_SignatureMethod write Set_FP_SignatureMethod;
    property P_SignatureVersion: string read FP_SignatureVersion write Set_FP_SignatureVersion;
    property P_Timestamp: string read FP_Timestamp;
    property P_Version: string read FP_Version write Set_FP_Version;
    property Ali_Host : string read FAli_Host write Set_FAli_Host;
 end    

三、控件私有方法说明(验签等需要)

  1. 初始化公共参数函数init_PublicParams 初始化所有公共参数到 Signature_Params 数组中。

公共参数使用 TSignature_Param 记录数组进行保存。

procedure TAli_SMS_Component.init_PublicParams(var Signature_Params: TSignature_Params);
var
  UTC_Time : TDateTime;
begin
  //设置公共参数列表长度
  SetLength(Signature_Params,8);
  //1. //访问密钥 ID。AccessKey 用于调用 API。
  Signature_Params[0].ParamName  := 'AccessKeyId';
  Signature_Params[0].ParamValue := FP_accessKeyId;
  //2. 返回参数的语言类型。取值范围:json | xml。默认值:json。
  Signature_Params[1].ParamName  := 'Format';
  if FP_Format = TRet_Format.JSON then
    Signature_Params[1].ParamValue := 'JSON'
  else
    Signature_Params[1].ParamValue := 'XML';
  //目前默认就只有 JSON
  Signature_Params[1].ParamValue := 'JSON';
  //3. API支持的RegionID,如短信API的值为:cn-hangzhou。
  Signature_Params[2].ParamName  := 'RegionId';
  Signature_Params[2].ParamValue := FP_RegionId;
  //4. 签名方式。取值范围:HMAC-SHA1。
  Signature_Params[3].ParamName  := 'SignatureMethod';
  Signature_Params[3].ParamValue := FP_SignatureMethod;
  //5. 签名唯一随机数。用于防止网络重放攻击,建议您每一次请求都使用不同的随机数。
  FP_SignatureNonce := 'SMS_' + FormatDateTime('YYYY-MM-DD hh:mm:ss zzz',Now);
  Signature_Params[4].ParamName  := 'SignatureNonce';
  Signature_Params[4].ParamValue := FP_SignatureNonce;
  //6. 签名算法版本。取值范围:1.0
  Signature_Params[5].ParamName  := 'SignatureVersion';
  Signature_Params[5].ParamValue := FP_SignatureVersion;
  //7. 请求的时间戳。按照ISO8601 标准表示,并需要使用UTC时间,格式为yyyy-MM-ddTHH:mm:ssZ。示例:2018-01-01T12:00:00Z 表示北京时间 2018 年 01 月 01 日 20 点 00 分 00 秒。
  UTC_Time := IncHour(Now,-8);    //比北京时间晚8个小时
  FP_Timestamp := FormatDateTime('YYYY-MM-DD',UTC_Time) + 'T' + FormatDateTime('hh:mm:ss',UTC_Time) + 'Z';   //请求的时间戳。按照ISO8601 标准表示,并需要使用UTC时间,格式为yyyy-MM-ddTHH:mm:ssZ。示例:2018-01-01T12:00:00Z 表示北京时间 2018 年 01 月 01 日 20 点 00 分 00 秒。
  Signature_Params[6].ParamName  := 'Timestamp';
  Signature_Params[6].ParamValue := FP_Timestamp;
  //8. API 的版本号,格式为 YYYY-MM-DD。取值范围:2017-05-25。
  Signature_Params[7].ParamName  := 'Version';
  Signature_Params[7].ParamValue := FP_Version;
end;
  1. 参数列表进行按字典排序函数:Sort_Params
//对于参数列表进行按字典排序 Ascending_order 默认是升序排列
procedure TAli_SMS_Component.Sort_Params(var Signature_Params: TSignature_Params; Ascending_order: boolean);
var
  i, j : Integer;
  T : TSignature_Param;
begin
  if Ascending_order then // 由大到校排序
  begin
    for i := low(Signature_Params) to high(Signature_Params) - 1 do
      for j := low(Signature_Params) to high(Signature_Params) - i - 1 do
        if Signature_Params[j].ParamName > Signature_Params[j + 1].ParamName then
        begin
          T := Signature_Params[j];
          Signature_Params[j] := Signature_Params[j + 1];
          Signature_Params[j + 1] := T;
        end;
  end // end if
  else // 由小到大排序
  begin
    for i := low(Signature_Params) to high(Signature_Params) - 1 do
      for j := low(Signature_Params) to high(Signature_Params) - i - 1 do
        if Signature_Params[j].ParamName < Signature_Params[j + 1].ParamName then
        begin
          T := Signature_Params[j];
          Signature_Params[j] := Signature_Params[j + 1];
          Signature_Params[j + 1] := T;
        end;
  end; // end else
end;
  1. 特殊URL编码,就是阿里的POP编码函数:specialUrlEncode
function TAli_SMS_Component.specialUrlEncode(url: string): string;
begin
  Result := TNetEncoding.URL.Encode(url);
  Result := Result.Replace('+','%20').Replace('*','%2A').Replace('%7E','~');
end;
  1. 获取签名函数: Signature
{***********************************************************
入口参数:
     Special_Params: 每条命令专有参数数组
     HTTPMethod:命令的请求方法字符串,GET或者是POS
出口参数:
     Query_Str:表示命令请求的实际字符串,发送请求的时候需要
     Signature:请求参数获取的签名字符串,这个是关键!!!!!!    
}

procedure TAli_SMS_Component.Get_Signature(
  const Special_Params: TSignature_Params; HTTPMethod : string; var Query_Str, Signature: string);
var
  i,count : integer;
  URL_Str : string;
  B       : TBytes;
  SMSParams: TSignature_Params;
  PCount  : integer;
begin
  //1. 初始化公共参数
  init_PublicParams(SMSParams);
  //2. 初始化专有参数
  PCount := Length(SMSParams);
  count  := length(Special_Params);
  //2.1 设置参数数组的总长度
  SetLength(SMSParams,PCount + count);
  //2.2 把专有参数拼接到公共参数的后面
  for i := 0 to count - 1 do
    begin
       SMSParams[i + PCount].ParamName  := Special_Params[i].ParamName;
       SMSParams[i + PCount].ParamValue := Special_Params[i].ParamValue;
    end;
  //3. 对所有参数进行排序,按照升序
  Sort_Params(SMSParams);
  //4. 组合成需要签名的字符串
  count := length(SMSParams);  //参数的总长度
  Query_Str := '';
  for i := 0 to count - 1 do
     Query_Str := Query_Str + specialUrlEncode(SMSParams[i].ParamName) + '=' + specialUrlEncode(SMSParams[i].ParamValue) + '&';
  //4.1
  // 去除最后一个 &
  Query_Str := Query_Str.Substring(0,Length(Query_Str) - 1);
  //5. 按POP的签名规则拼接成最终的待签名串。
  URL_Str := HTTPMethod + '&' + specialUrlEncode('/') + '&' + specialUrlEncode(Query_Str);
  //6. 签名
  //6.1进行数字签名 HmacSHA1
  B := THashSHA1.GetHMACAsBytes(URL_Str,FP_accessSecret + '&');
  //6.2进行base64
  Signature := TNetEncoding.Base64.EncodeBytesToString(B);
end;
  1. 图片等文件进行Base64编码函数:Image_Base64
function TAli_SMS_Component.Image_Base64(FileName: string): string;
var
  B : TBytes;
  M : TMemoryStream;
begin
  if not FileExists(FileName) then Exit('');
  M := TMemoryStream.Create;
  try
    M.LoadFromFile(FileName);
    M.Position := 0;
    SetLength(B,M.Size);
    M.Read(B[0],M.Size);
    Result := TNetEncoding.Base64.EncodeBytesToString(B);
  finally
    M.Free;
  end;
end;

四、短信控件需要引用的 Delphi 单元

uses
  System.Hash,
  system.DateUtils,
  system.JSON,
  System.Net.HttpClientComponent, {TNetHttpClient}
  System.NetEncoding,
  
  System.SysUtils, 
  System.Classes;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
修改说明: ================================================================================== 1 原版只支持Delphi XE,本版改为可以支持Delphi6/7,在Delphi6下编译运行通过 2 修正了原版无法支持中文名称的BUG 使用示例: ================================================================================== ossTemp := TAliOssFileSystem.Create(OSS_ACCESS_ID, OSS_ASSCESS_KEY, OSS_HOSTNAME); ossTemp.ChangeVolumn(sBucketName); ossTemp.UploadFile(sLocalFileName, sOSSFileName); ossTemp.Free; 原版说明: ================================================================================== 该SDK使用Delphi/Object Pascal编程语言编写,完整实现了阿里云OSS API的全部功能,并提 供了两套API:第一套API(类名:TAliOss)仿照OSS PHP SDK实现了全部函数,第二套API( 类名:TAliOssFileSystem)封装了TAliOss,并在其的基础上实现了类似于文件系统的API, 实现了包括“卷”、“文件夹”、“文件”等抽象概念,并提供相应的功能函数。 两套API面向的应用场景不同:TAliOssFileSystem适合于将OSS服务看作是一种文件系统的应 用,开发人员不必了解OSS API的内部参数及XML定义,可提高编程效率,使用方便;TAliOSS 适合于其他类型的应用,当编程人员需要更加定制化的调用或者需要更加灵活的参数设置时, 可以直接使用该SDK操作调用参数和返回值。两套API互不干扰,可以在项目中同时使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海纳老吴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值