微服务进阶整合学习第三方应用篇--第三方接口的调用

微服务进阶整合学习第三方应用篇--第三方接口的调用

阿里云文件存储

  • JAVA SKD上传指南

  • 采用服务端签名后直传的方式,不将图片传给服务端,而是从服务端获取签名,绕过服务端直接上传到OSS阿里云服务器,具体实例操作如下:

  • 第一步,引入阿里云OSS上传坐标,配置上传所需的accesskey等信息:

<dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
</dependency>
spring:
  application:
    name: mall-product
    alicloud:
      # 这里填写获取的access-key,secret-key信息,这一步建议新增一个Access用户专门管理文件上传模块。
      access-key: xxx
      secret-key: xxx
      oss:
      	# 这里填写你选择的OSS服务地址,即所选在哪个区
        endpoint: oss-cn-guangzhou.aliyuncs.com
        bucket: xxx
  • 第二步,编写获取签名的接口,供前端访问该接口并获取签名。
@RestController
public class OssController {

    @Autowired
    OSS ossClient;

    @Value("${spring.cloud.alicloud.oss.endpoint}")
    private String endPoint;

    @Value("${spring.cloud.alicloud.oss.bucket}")
    private String bucket;

    @Value("${spring.cloud.alicloud.access-key}")
    private String accessId;

    @Value("${spring.cloud.alicloud.secret-key}")
    private String accessKeySecret;

    @RequestMapping("/oss/policy")
    public R policy() {

        //https://gulimall-clouds.oss-cn-beijing.aliyuncs.com/iqiyi.png

        // Endpoint以杭州为例,其它Region请按实际情况填写。

        String host = "https://" + bucket + "." + endPoint; // host的格式为 bucketname.endpoint
        // callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
        //String callbackUrl = "http://88.88.88.88:8888";

        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String dir = format + "/"; // 用户上传文件时指定的前缀。

        // 创建OSSClient实例。
        //OSS ossClient = new OSSClientBuilder().build(endPoint, accessId, accessKeySecret);
        Map<String, String> respMap = null;
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            respMap = new LinkedHashMap<String, String>();
            respMap.put("accessid", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));

        } catch (Exception e) {
            // Assert.fail(e.getMessage());
            System.out.println(e.getMessage());
        } finally {
            ossClient.shutdown();
        }
        return R.ok().put("data",respMap);
    }

}
  • 第三步:如果是单体应用,则无需配置网关分发。如果配置了,需要在网关配置一下网关信息。这里图像上传是没有经过Nginx的,直接访问网关,由网关进行分发的。

  • 第四步:elementUI有个上传组件upload,提供上传前的方法,我们可以在上传图片之前请求服务器获取签名凭证,如下所示:

beforeUpload(file) {
      let _self = this;
      return new Promise((resolve, reject) => {
        policy()
          .then(response => {
            _self.dataObj.policy = response.data.policy;
            _self.dataObj.signature = response.data.signature;
            _self.dataObj.ossaccessKeyId = response.data.accessid;
            _self.dataObj.key = response.data.dir +getUUID()+"_${filename}";
            _self.dataObj.dir = response.data.dir;
            _self.dataObj.host = response.data.host;
            resolve(true);
          })
          .catch(err => {
            console.log("出错了...",err)
            reject(false);
          });
      });
    },
  • 第五步,在阿里云服务器开启允许跨域请求。

腾讯云短信发送

  • 第一步,毫无疑问肯定是开通短信服务,申请签名以及模板啦。不知道是不是审核的就是慢还是周六日的原因,说是两个小时审核,我等了5,6个小时,最后是咨询客服去审核的。
  • 第二步,审核通过后,就可以开始使用腾讯云的短信接口了,参考其Java SDK文档进行配置即可。
#导入maven坐标
<dependency>
     <groupId>com.tencentcloudapi</groupId>
     <artifactId>tencentcloud-sdk-java</artifactId>
     <version>3.1.270</version><!-- 注:这里只是示例版本号(可直接使用),可获取并替换为 最新的版本号,注意不要使用4.0.x版本(非最新版本) -->

#发送短信的核心代码 
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
//导入可选配置类
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
// 导入对应SMS模块的client
import com.tencentcloudapi.sms.v20210111.SmsClient;
// 导入要请求接口对应的request response类
import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
/**
 * Tencent Cloud Sms Sendsms
 * */
public class SendSms
{
  public static void main(String[] args)
  {
      try {
          /* 必要步骤:
           * 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。
           * 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。
           * 你也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人,
           * 以免泄露密钥对危及你的财产安全。
           * CAM密匙查询: https://console.cloud.tencent.com/cam/capi*/
          Credential cred = new Credential("secretId", "secretKey");
           // 实例化一个http选项,可选,没有特殊需求可以跳过
          HttpProfile httpProfile = new HttpProfile();
          // 设置代理
          // httpProfile.setProxyHost("真实代理ip");
          // httpProfile.setProxyPort(真实代理端口);
          /* SDK默认使用POST方法。
           * 如果你一定要使用GET方法,可以在这里设置。GET方法无法处理一些较大的请求 */
          httpProfile.setReqMethod("POST");
          /* SDK有默认的超时时间,非必要请不要进行调整
           * 如有需要请在代码中查阅以获取最新的默认值 */
          httpProfile.setConnTimeout(60);
          /* SDK会自动指定域名。通常是不需要特地指定域名的,但是如果你访问的是金融区的服务
           * 则必须手动指定域名,例如sms的上海金融区域名: sms.ap-shanghai-fsi.tencentcloudapi.com */
          httpProfile.setEndpoint("sms.tencentcloudapi.com");
           /* 非必要步骤:
           * 实例化一个客户端配置对象,可以指定超时时间等配置 */
          ClientProfile clientProfile = new ClientProfile();
          /* SDK默认用TC3-HMAC-SHA256进行签名
           * 非必要请不要修改这个字段 */
          clientProfile.setSignMethod("HmacSHA256");
          clientProfile.setHttpProfile(httpProfile);
          /* 实例化要请求产品(以sms为例)的client对象
           * 第二个参数是地域信息,可以直接填写字符串ap-guangzhou,或者引用预设的常量 */
          SmsClient client = new SmsClient(cred, "ap-guangzhou",clientProfile);
          /* 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数
           * 你可以直接查询SDK源码确定接口有哪些属性可以设置
           * 属性可能是基本类型,也可能引用了另一个数据结构
           * 推荐使用IDE进行开发,可以方便的跳转查阅各个接口和数据结构的文档说明 */
          SendSmsRequest req = new SendSmsRequest();
           /* 填充请求参数,这里request对象的成员变量即对应接口的入参
           * 你可以通过官网接口文档或跳转到request对象的定义处查看请求参数的定义
           * 基本类型的设置:
           * 帮助链接:
           * 短信控制台: https://console.cloud.tencent.com/smsv2
           * sms helper: https://cloud.tencent.com/document/product/382/3773 */
           /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId,示例如1400006666 */
          String sdkAppId = "1400009099";
          req.setSmsSdkAppId(sdkAppId);
           /* 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名,签名信息可登录 [短信控制台] 查看 */
          String signName = "签名内容";
          req.setSignName(signName);
           /* 国际/港澳台短信 SenderId: 国内短信填空,默认未开通,如需开通请联系 [sms helper] */
          String senderid = "";
          req.setSenderId(senderid);
           /* 用户的 session 内容: 可以携带用户侧 ID 等上下文信息,server 会原样返回 */
          String sessionContext = "xxx";
          req.setSessionContext(sessionContext);
           /* 短信号码扩展号: 默认未开通,如需开通请联系 [sms helper] */
          String extendCode = "";
          req.setExtendCode(extendCode);
           /* 模板 ID: 必须填写已审核通过的模板 ID。模板ID可登录 [短信控制台] 查看 */
          String templateId = "400000";
          req.setTemplateId(templateId);
           /* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]
           * 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号 */
          String[] phoneNumberSet = {"+8621212313123", "+8612345678902", "+8612345678903"};
          req.setPhoneNumberSet(phoneNumberSet);
           /* 模板参数: 若无模板参数,则设置为空 */
          String[] templateParamSet = {"5678"};
          req.setTemplateParamSet(templateParamSet);
           /* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的
           * 返回的 res 是一个 SendSmsResponse 类的实例,与请求对象对应 */
          SendSmsResponse res = client.SendSms(req);
           // 输出json格式的字符串回包
          System.out.println(SendSmsResponse.toJsonString(res));
           // 也可以取出单个值,你可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义
          System.out.println(res.getRequestId());
       } catch (TencentCloudSDKException e) {
          e.printStackTrace();
      }
  }
}
</dependency>
  • 第三步,为了方便使用,我们可以将该接口抽取为一个组件,其具体的参数我们可以通过放在yml文件统一配置更改。只需要通过ConfigurationProperties(prefix="")指定yml中相关配置所在的位置,通过@Data,@Component即可自动注入,如下所示。不过值得注意的是,腾讯云发送短信的方法setPhoneNumberSet默认参数是个数组,封装成接口的话得注意一下这里,不要只穿字符串类型,得把它变成数组类型。
@ConfigurationProperties(prefix = "spring.cloud.txcloud")
@Component
@Data
public class SmsComponent {

    private String secretId;

    private String secretKey;

    private String reqMethod;

    private String endPoint;

    private String sdkAppId;

    private String signName;

    private String templateId;

    private static final String signMethod = "HmacSHA256";

    public void SendMessage(String phone,String code){
        try {
            Credential cred = new Credential(secretId, secretKey);
            HttpProfile httpProfile = new HttpProfile();
            httpProfile.setReqMethod(reqMethod);
            httpProfile.setConnTimeout(60);
            httpProfile.setEndpoint(endPoint);
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setSignMethod(signMethod);
            clientProfile.setHttpProfile(httpProfile);
            SmsClient client = new SmsClient(cred, "ap-guangzhou",clientProfile);
            SendSmsRequest req = new SendSmsRequest();
            req.setSmsSdkAppId(sdkAppId);
            req.setSignName(signName);
            req.setTemplateId(templateId);
            String[] numberSet = new String[1];
            numberSet[0] = "86"+phone;
            req.setPhoneNumberSet(numberSet);
            /* 模板参数: 验证码,可通过UUID生成 */
            //String randomCode = this.getRandomCode();
            String[] codeSet = new String[1];
            codeSet[0] = code.split("_")[0];
            String[] templateParamSet = codeSet;
            req.setTemplateParamSet(templateParamSet);
            /* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的
             * 返回的 res 是一个 SendSmsResponse 类的实例,与请求对象对应 */
            SendSmsResponse res = client.SendSms(req);
            // 输出json格式的字符串回包
            System.out.println(SendSmsResponse.toJsonString(res));
            // 也可以取出单个值,你可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义
            System.out.println(res.getRequestId());
        } catch (TencentCloudSDKException e) {
            e.printStackTrace();
        }
    }
}
  • 第四步,调用接口就可以啦。

后端层面的接口防刷:防止用户多次刷新页面请求接口,造成短信的浪费。可以通过腾讯云的控制台开启发送频率限制,但是这个功能好像只能给企业用户使用,个人用户使用不了。我们就可以通过在redis中,设置用户的手机号码为key,value为短信验证码+时间戳的形式,在发送请求的时候检验redis中该用户的时间戳和当前时间戳之差是否超过60秒,如果超过则允许发送,否则直接返回发送频率过快的信息。整体逻辑代码如下所示:
在这里插入图片描述

@ResponseBody
    @GetMapping("/sms/sendCode")
    public R sendCode(@RequestParam("phone") String phone){

        //1、接口防刷,防止刷新页面之后无限刷
        String s = redisTemplate.opsForValue().get(AuthConstant.SMS_CODE_CACHE_PREFIX + phone);
        if(!StringUtils.isNullOrEmpty(s)){
            long time = Long.parseLong(s.split("_")[1]);
            if(System.currentTimeMillis()-time<60000){
                //60秒内禁止再发
                return R.error(BizCodeEnume.MESSAGE_SEND_EXCEPTION.getCode(),BizCodeEnume.MESSAGE_SEND_EXCEPTION.getMsg());
            }
        }

        //2、验证码缓存校验.key-phone,value-code
        RandomUtils randomUtils = new RandomUtils();
        String randomCode = randomUtils.getRandomCode()+"_"+System.currentTimeMillis();
        redisTemplate.opsForValue().set(AuthConstant.SMS_CODE_CACHE_PREFIX+phone,randomCode,10, TimeUnit.MINUTES);
        //微服务远程调用第三方服务的短信发送接口
        thirdPartyFeignService.sendCode(phone,randomCode);

        return R.ok();

    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值