Spring Cloud微服务项目搭建系列文章(三):公共模块之阿里云OSS,VOD,SMS相关功能封装

上一篇外层项目构建我们讲解如何构建一个外层项目,现在开始我们讲解的是Com模块的相关功能

Com模块是一个starter包,至于什么事starter包,后面我会单独来讲解。

项目源码:源码地址

背景说明

这一篇是公共模块中阿里云相关功能讲解,在日常开发中其实我们跟阿里云的接触是相当的频繁的。而且阿里云的产品确实也非常好用,这里就介绍三个功能的集成:

  1. OSS文件存储
  2. VOD视频点播
  3. 短信相关

首先,在我们构建的项目上新建一个module:new->module,这里和创建项目一样也是一个POM,大家如果忘记了可以看上一篇文章。

阿里云模块构建

OK,com模块建立好之后,我们在Com模块的基础上构建阿里云模块和api模块。唯一区别于上面外层项目构建就是这里选择的是quickstart。

有人可能问为啥要新建api模块,主要是在部分业务场景减少不必要的全量引入。

Spring Cloud微服务项目搭建系列文章(三):公共模块之阿里云OSS,VOD,SMS相关功能封装_第1张图片

 

构建完毕的项目结构如下:Spring Cloud微服务项目搭建系列文章(三):公共模块之阿里云OSS,VOD,SMS相关功能封装_第2张图片

在aliyun模块引入api模块


    com-aliyun-service

    
        
            com.clark
            com-api-service
            1.0-SNAPSHOT
        
    

 OK到这里基本的项目构建完成。

业务实现

引入相关的jar包以及单元测试相关jar

 
            com.aliyun
            aliyun-java-sdk-core
            3.3.1
        
        
            com.aliyun
            aliyun-java-sdk-dysmsapi
            1.0.0
        
        
            com.aliyun.oss
            aliyun-sdk-oss
            2.8.2
        
        
            com.aliyun
            aliyun-java-sdk-vod
            2.15.2
        
        
            com.aliyun
            aliyun-java-vod-upload
            1.3.2
        
        
            org.springframework.boot
            spring-boot-configuration-processor
            true
        
        
        
            junit
            junit
            4.12
            test
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        

这里需要注意点版本关联,阿里云的各个SDK的版本关联有点乱。

配置抽象

/**
 * oss配置类
 * @author 大仙
 */
@Data
@ConfigurationProperties(prefix = "edu.aliyun.oss")
public class OssProperties implements Serializable {

    /**
     * 站点
     */
    private String point;
    /**
     * keyId
     */
    private String key;
    /**
     * key密码
     */
    private String secret;
    /**
     * bucket名称
     */
    private String buckName;
    /**
     * 访问路径
     */
    private String baseUrl;
    /**
     * 角色管理获得
     */
    private String roleArn;
    /**
     * session名称
     */
    private String roleSessionName;
}
/**
 * 短信配置类
 * @author 大仙
 */
@Data
@ConfigurationProperties(prefix = "edu.aliyun.sms")
public class SmsProperties implements Serializable {
    /**
     * 短信API产品名称(短信产品名固定,无需修改)
     */
    private String  product;
    /**
     * 短信API产品域名(接口地址固定,无需修改)
     */
    private String domain;
    /**
     * 签名名称
     */
    private String  signName;
    /**
     * 断点
     */
    private String endpoint;
    /**
     * key:单独授权
     */
    private String key;
    /**
     * secret: 单独授权
     */
    private String secret;
}
/**
 * 视频配置类
 * @author 大仙
 */
@Data
@ConfigurationProperties(prefix = "edu.aliyun.vod")
public class VodProperties implements Serializable {
    /**
     * key:单独权限
     */
    private String key;
    /**
     * secret: 单独权限
     */
    private String secret;
    /**
     * 区域
     */
    private String region;
    /**
     * 用户ID
     */
    private String uid;
    /**
     * 图片前缀
     */
    private String coverUrl;
    /**
     * 模板组
     */
    private String templateMode;

}

功能实现

功能实现的相关接口,需要抽象到API模块里面,这里就不详细说了。

/**
 * OSS业务实现
 * @author 大仙
 */
@Slf4j
public class OssServiceImpl implements OssService {


    private OssProperties ossProperties;

    @Override
    public String uploadByte(byte[] content, String key) {
        String bucket_resource = ossProperties.getBuckName();
        // 初始化OSSClient
        OSSClient client = new OSSClient(ossProperties.getPoint(), ossProperties.getKey(), ossProperties.getSecret());
        // 上传Object.
        try {
            client.putObject(bucket_resource, key, new ByteArrayInputStream(content));
        } catch (Exception e) {
            log.error("OSSUtils upload Exception", e);
            throw new AliyunException(e.getMessage());
        } finally {
            client.shutdown();
        }
        return ossProperties.getBaseUrl() + "/" + key;
    }

    @Override
    public String upload(String key, InputStream inputStream) {
        OSSClient ossClient = new OSSClient(ossProperties.getPoint(), ossProperties.getKey(), ossProperties.getSecret());
        try {
            ossClient.putObject(ossProperties.getBuckName(),  key, inputStream);
        } catch (Exception e) {
            log.error("OSSUtils upload Exception", e);
            throw new AliyunException(e.getMessage());
        } finally {
            ossClient.shutdown();
        }
        return ossProperties.getBaseUrl() + "/" +  key;
    }



    @Override
    public JSONObject getToken(String key) {
        JSONObject result = new JSONObject();
        Map tokenMessage = getSTSToken();
        if (tokenMessage.size() == 0) {
            log.info("没有查询到数据");
            return null;
        }
        result.put("Expiration", tokenMessage.get("Expiration"));
        result.put("AccessKey", tokenMessage.get("AccessKey"));
        result.put("AccessKeySecret", tokenMessage.get("AccessKeySecret"));
        result.put("SecurityToken", tokenMessage.get("SecurityToken"));
        result.put("endpoint", ossProperties.getPoint());
        result.put("bucket", ossProperties.getBuckName());
        result.put("key", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")).toString() +key);
        return result;
    }


    /**
     * 获取TOKEN
     * @param source
     * @param userId
     * @return
     */
    /**
     * 获取STStoken
     *
     * @return
     */
    private Map getSTSToken() {
        Map tokenMessage = new HashMap();
        String policy = null;
        try {
            // 添加endpoint(直接使用STS endpoint,前两个参数留空,无需添加region ID)
            DefaultProfile.addEndpoint("", "", "Sts", ossProperties.getPoint());
            // 构造default profile(参数留空,无需添加region ID)
            IClientProfile profile = DefaultProfile.getProfile("cn-beijing", ossProperties.getKey(), ossProperties.getSecret());
            // 用profile构造client
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setMethod(MethodType.POST);
            request.setRoleArn(ossProperties.getRoleArn());
            request.setRoleSessionName(ossProperties.getRoleSessionName());
            request.setPolicy(policy); // Optional
            request.setDurationSeconds(900L);
            final AssumeRoleResponse response = client.getAcsResponse(request);
            tokenMessage.put("Expiration", response.getCredentials().getExpiration());
            tokenMessage.put("AccessKey", response.getCredentials().getAccessKeyId());
            tokenMessage.put("AccessKeySecret", response.getCredentials().getAccessKeySecret());
            tokenMessage.put("SecurityToken", response.getCredentials().getSecurityToken());
            tokenMessage.put("RequestId", response.getRequestId());
        } catch (ClientException e) {
            log.error("Error code: ", e.getErrCode());
            log.error("Error message: ", e.getErrMsg());
            log.error("RequestId: ", e.getRequestId());
            throw new AliyunException(e.getMessage());
        }
        return tokenMessage;
    }

    public void setOssProperties(OssProperties ossProperties) {
        this.ossProperties = ossProperties;
    }

}
/**
 * 短信实现
 * @author 大仙
 */
@Slf4j
public class SmsServiceImpl implements SmsService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private SmsProperties smsProperties;


    @Override
    public void sendSMS(String phoneNum, SMSTemplate templateCode, String params) {
        send(phoneNum, templateCode.toString(), params);
    }
    /**
     * 发送短信
     * @param phoneNum    接收短信内容
     * @param templateCode
     * @param param
     * @return
     * @throws ClientException
     * @throws LimitExceededException
     */
    private boolean send(String phoneNum, String templateCode, String param) {
        try {
            //初始化ascClient,暂时不支持多region(请勿修改)
            IClientProfile profile = DefaultProfile.getProfile(smsProperties.getEndpoint(), smsProperties.getKey(),
                    smsProperties.getSecret());
            DefaultProfile.addEndpoint(smsProperties.getEndpoint(), smsProperties.getEndpoint(), smsProperties.getProduct(), smsProperties.getDomain());
            IAcsClient acsClient = new DefaultAcsClient(profile);
            //组装请求对象
            SendSmsRequest request = new SendSmsRequest();
            request.setConnectTimeout(3000);
            request.setReadTimeout(10000);
            //使用post提交
            request.setMethod(MethodType.POST);
            //必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式
            request.setPhoneNumbers(phoneNum);
            //必填:短信签名-可在短信控制台中找到
            request.setSignName(smsProperties.getSignName());
            //必填:短信模板-可在短信控制台中找到
            request.setTemplateCode(templateCode);
            //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
            //友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
            request.setTemplateParam(param);
            //可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段)
            //request.setSmsUpExtendCode("90997");
            //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
//        request.setOutId("yourOutId");
            //请求失败这里会抛ClientException异常
            SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
            logger.info("发送短信结果:" + JSONObject.toJSONString(sendSmsResponse));
            if (sendSmsResponse.getCode() != null) {
                if (sendSmsResponse.getCode().equals("OK")) {
                    return true;
                }
                if (sendSmsResponse.getCode().equals("isv.BUSINESS_LIMIT_CONTROL")) {
                    throw new AliyunException("短信服务限流");
                }
            }
        }catch (Exception e){
            throw new AliyunException(e.getMessage());
        }
        return false;

    }

    public void setSmsProperties(SmsProperties smsProperties) {
        this.smsProperties = smsProperties;
    }
}
/**
 * 视频点播业务
 * @author 大仙
 */
@Slf4j
public class VodServiceImpl implements VodService {

    private Logger logger = LoggerFactory.getLogger(getClass());
    /**
     * 正常
     */
    private static final String STATUS = "Normal";

    private VodProperties vodProperties;

    public void setVodProperties(VodProperties vodProperties) {
        this.vodProperties = vodProperties;
    }

    @Override
    public JSONObject getVideoPlayAuth(String vid) {
        DefaultProfile profile = DefaultProfile.getProfile(vodProperties.getRegion(), vodProperties.getKey(), vodProperties.getSecret());
        DefaultAcsClient client = new DefaultAcsClient(profile);
        GetVideoPlayAuthRequest request = new GetVideoPlayAuthRequest();
        request.setVideoId(vid);
        request.setAuthInfoTimeout(3000L);
        GetVideoPlayAuthResponse response = null;
        try {
            response = client.getAcsResponse(request);
        } catch (ServerException e) {
            throw new RuntimeException("GetVideoPlayAuthRequest Server failed");
        } catch (ClientException e) {
            throw new RuntimeException("GetVideoPlayAuthRequest Client failed");
        }
        JSONObject result = new JSONObject();
        result.put("status", false);
        try {
            if (STATUS.equals(response.getVideoMeta().getStatus())) {
                result.put("status", true);
            }
            result.put("playAuth", response.getPlayAuth()); // 播放凭证
        } catch (Exception e) {
            logger.error("获取播放凭证出错");
        }
        return result;
    }

    @Override
    public JSONObject uploadVideoToVOD(String source, Long cateId) {
        DefaultProfile profile = DefaultProfile.getProfile(vodProperties.getRegion(), vodProperties.getKey(), vodProperties.getSecret());
        DefaultAcsClient client = new DefaultAcsClient(profile);
        CreateUploadVideoRequest request = new CreateUploadVideoRequest();
        String randomCode = System.currentTimeMillis() + PubUtils.generateRandomFullCode(5);
        String fileName = source + "_" + randomCode + ".mp4";
        //封面图片
        String coverUrl = vodProperties.getCoverUrl() + source + "_" + randomCode + ".jpg";
        String title = fileName;
        request.setFileName(fileName);
        request.setTitle(title);
        request.setCateId(cateId);
        request.setCoverURL(coverUrl);
        request.setTemplateGroupId(vodProperties.getTemplateMode());
        CreateUploadVideoResponse response = null;
        try {
            response = client.getAcsResponse(request);
        } catch (ClientException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        logger.info("result:{}",JSONObject.toJSONString(response));
        /*System.out.print("RequestId=" + response.getRequestId() + "\n");  //请求视频点播服务的请求ID
        System.out.print("VideoId=" + response.getVideoId() + "\n");
        System.out.print("uploadAddress=" + response.getUploadAddress() + "\n");
        System.out.print("uploadAuth=" + response.getUploadAuth() + "\n");*/
        JSONObject result = new JSONObject();
        result.put("videoId", response.getVideoId());
        result.put("uploadAddress", response.getUploadAddress());
        result.put("uploadAuth", response.getUploadAuth());
        result.put("fileName", fileName);
        result.put("region", vodProperties.getRegion());
        result.put("coverUrl", coverUrl);
        result.put("imageFileName", source + "_" + randomCode + ".jpg");
        result.put("uid", vodProperties.getUid());
        return result;
    }

    /**
     * 上传视频
     * @param title
     * @param fileName
     * @param file
     * @return
     */
    @Override
    public String uploadVideoByStream(String title, String fileName, InputStream file) {
        UploadStreamRequest request =  new UploadStreamRequest(vodProperties.getKey(), vodProperties.getSecret(), title, fileName, file);
        request.setCateId(1000066766L);
        UploadVideoImpl uploader = new UploadVideoImpl();
        UploadStreamResponse response = uploader.uploadStream(request);
        System.out.print("RequestId=" + response.getRequestId() + "\n"); //请求视频点播服务的请求ID
        if (response.isSuccess()) {
            System.out.print("VideoId=" + response.getVideoId() + "\n");
        } else {
            /* 如果设置回调URL无效,不影响视频上传,可以返回VideoId同时会返回错误码。其他情况上传失败时,VideoId为空,此时需要根据返回错误码分析具体错误原因 */
            System.out.print("VideoId=" + response.getVideoId() + "\n");
            System.out.print("ErrorCode=" + response.getCode() + "\n");
            System.out.print("ErrorMessage=" + response.getMessage() + "\n");
        }
        return response.getVideoId();
    }
}

配置实例初始

/**
 * OSS config
 * @author 大仙
 */
@EnableConfigurationProperties({ OssProperties.class})
public class OssAutoConfig {

    @Autowired
    OssProperties ossProperties;

    /**
     * 实例化OSS
     * @return
     */
    @Bean
    OssService ossService(){
        OssServiceImpl ossService = new OssServiceImpl();
        ossService.setOssProperties(ossProperties);
        return ossService;
    }

}
@EnableConfigurationProperties({ SmsProperties.class})
public class SmsAutoConfig {

    @Autowired
    SmsProperties smsProperties;

    /**
     * 实例化OSS
     * @return
     */
    @Bean
    SmsService smsService(){
        SmsServiceImpl smsService = new SmsServiceImpl();
        smsService.setSmsProperties(smsProperties);
        return smsService;
    }
}
@EnableConfigurationProperties({ VodProperties.class})
public class VodAutoConfig {

    @Autowired
    private VodProperties vodProperties;

    /**
     * 阿里云视频点播业务
     * @return
     */
    @Bean
    VodService vodService(){
        VodServiceImpl vodService = new VodServiceImpl();
        vodService.setVodProperties(vodProperties);
        return vodService;
    }
}

注解控制

/**
 * 阿里云Oss的启动注解
 * @author 大仙
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(OssAutoConfig.class)
public @interface EnableAliOss {
}
/**
 * 阿里云启动短信注解
 * @author 大仙
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(SmsAutoConfig.class)
public @interface EnableAliSms {
}
/**
 * 阿里云启动视频注解
 * @author 大仙
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(VodAutoConfig.class)
public @interface EnableAliVod {

}

OK到这里,基本上常用的阿里云的接口功能都封装完毕了

你可能感兴趣的:(spring,cloud)