【金融项目】尚融宝项目(五)

9、阿里云短信

9.1、阿里云短信服务

9.1.1、使用RAM子用户

9.1.1.1、进入子用户管理页面

在这里插入图片描述

在这里插入图片描述

9.1.1.2、添加用户

在这里插入图片描述

9.1.1.3、获取子用户key

AccessKeyId, AccessKeySecret

9.1.1.4、设置用户权限

授权:AliyunDysmsFullAccess

在这里插入图片描述

9.1.2、开通短信服务

9.1.2.1、开通

在这里插入图片描述

在这里插入图片描述

9.1.2.2、添加签名

在这里插入图片描述

9.1.2.3、添加模板

在这里插入图片描述

在这里插入图片描述

9.1.2.4、套餐

free.aliyun.com

在这里插入图片描述

9.1.2.5、快速学习

在这里插入图片描述

9.1.3、测试短信发送

9.1.3.1、查找使用示例

在这里插入图片描述

9.1.3.2、测试短信发送

在这里插入图片描述

在这里插入图片描述

9.1.3.3、查看发送结果

短信服务->业务统计->发送记录查询

9.2、创建短信微服务

9.2.1、需求

在这里插入图片描述

在这里插入图片描述

9.2.2、创建项目

9.2.2.1、创建模块

service-sms

9.2.2.2、配置 pom.xml
<dependencies>
    <dependency>
        <groupId>com.atguigu</groupId>
        <artifactId>service-base</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--lombok用来简化实体类:需要安装lombok插件-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <!--阿里云短信-->
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-core</artifactId>
    </dependency>
</dependencies>
9.2.2.3、application.yml

resources目录下创建文件

server:
  port: 8120 # 服务端口
spring:
  profiles:
    active: dev # 环境设置
  application:
    name: service-sms # 服务名
  #spring:
  redis:
    host: 192.168.100.100
    port: 6379
    database: 0
    password: 123456 #默认为空
    timeout: 3000ms #最大等待时间,超时则抛出异常,否则请求一直等待
    lettuce:
      pool:
        max-active: 20  #最大连接数,负值表示没有限制,默认8
        max-wait: -1    #最大阻塞等待时间,负值表示没限制,默认-1
        max-idle: 8     #最大空闲连接,默认8
        min-idle: 0     #最小空闲连接,默认0
#阿里云短信
aliyun:
  sms:
    region-id: cn-hangzhou
    key-id: 你的keyid
    key-secret: 你的keysecret
    template-code: 你的短信模板code
    sign-name: 你的短信模板签名
9.2.2.4、logback-spring.xml
9.2.2.5、创建SpringBoot启动类
package com.atguigu.srb.sms;
@SpringBootApplication
@ComponentScan({"com.atguigu.srb", "com.atguigu.common"})
public class ServiceSmsApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(ServiceSmsApplication.class, args);
    }
}

9.2.3、自定义配置

9.2.3.1、从配置文件读取常量

创建常量读取工具类:SmsProperties.java

package com.atguigu.srb.sms.util;

@Setter
@Getter //idea2020.2.3版配置文件自动提示需要这个
@Component
//注意prefix要写到最后一个 "." 符号之前
//调用setter为成员赋值
@ConfigurationProperties(prefix = "aliyun.sms")
public class SmsProperties implements InitializingBean {
    private String regionId;
    private String keyId;
    private String keySecret;
    private String templateCode;
    private String signName;
    public static String REGION_Id;
    public static String KEY_ID;
    public static String KEY_SECRET;
    public static String TEMPLATE_CODE;
    public static String SIGN_NAME;
    //当私有成员被赋值后,此方法自动被调用,从而初始化常量
    @Override
    public void afterPropertiesSet() throws Exception {
        REGION_Id = regionId;
        KEY_ID = keyId;
        KEY_SECRET = keySecret;
        TEMPLATE_CODE = templateCode;
        SIGN_NAME = signName;
    }
}

Idea报告如下错误信息(不影响程序的编译和运行):
在这里插入图片描述

解决方案参考文档:

在这里插入图片描述

解决步骤:

  • step1:添加依赖
<!--  配置文件处理器  -->
<!--让自定义的配置在application.yaml进行自动提示-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
  • step2:启动processor

在这里插入图片描述

  • step3:重新编译模块

  • step4:这样就可以在yml文件中有自定义配置的提示信息啦

9.2.3.2、测试工具类

创建测试类 UtilsTests,测试配置信息是否能正常获取

package com.atguigu.srb.sms;
@SpringBootTest
@RunWith(SpringRunner.class)
public class UtilsTests {
    @Test
    public void testProperties(){
        System.out.println(SmsProperties.KEY_ID);
        System.out.println(SmsProperties.KEY_SECRET);
        System.out.println(SmsProperties.REGION_Id);
    }
}

9.2.4、发送短信

9.2.4.1、短信发送业务

接口:创建 SmsService

package com.atguigu.srb.sms.service;

public interface SmsService {
    void send(String mobile, String templateCode, Map<String,Object> param);
}

实现:创建 SmsServiceImpl

package com.atguigu.srb.sms.service.impl;

@Service
@Slf4j
public class SmsServiceImpl implements SmsService {
    @Override
    public void send(String mobile, String templateCode, Map<String,Object> param) {
        //创建远程连接客户端对象
        DefaultProfile profile = DefaultProfile.getProfile(
                SmsProperties.REGION_Id,
                SmsProperties.KEY_ID,
                SmsProperties.KEY_SECRET);
        IAcsClient client = new DefaultAcsClient(profile);
        //创建远程连接的请求参数
        CommonRequest request = new CommonRequest();
        request.setSysMethod(MethodType.POST);
        request.setSysDomain("dysmsapi.aliyuncs.com");
        request.setSysVersion("2017-05-25");
        request.setSysAction("SendSms");
        request.putQueryParameter("RegionId", SmsProperties.REGION_Id);
        request.putQueryParameter("PhoneNumbers", mobile);
        request.putQueryParameter("SignName", SmsProperties.SIGN_NAME);
        request.putQueryParameter("TemplateCode", templateCode);
        Gson gson = new Gson();
        String json = gson.toJson(param);
        request.putQueryParameter("TemplateParam", json);
        try {
            //使用客户端对象携带请求对象发送请求并得到响应结果
            CommonResponse response = client.getCommonResponse(request);
            boolean success = response.getHttpResponse().isSuccess();
            //ALIYUN_RESPONSE_FAIL(-501, "阿里云响应失败"),
            Assert.isTrue(success, ResponseEnum.ALIYUN_RESPONSE_FAIL);
            String data = response.getData();
            HashMap<String, String> resultMap = gson.fromJson(data, HashMap.class);
            String code = resultMap.get("Code");
            String message = resultMap.get("Message");
            log.info("阿里云短信发送响应结果:");
            log.info("code:" + code);
            log.info("message:" + message);
            //ALIYUN_SMS_LIMIT_CONTROL_ERROR(-502, "短信发送过于频繁"),//业务限流
            Assert.notEquals("isv.BUSINESS_LIMIT_CONTROL", code, ResponseEnum.ALIYUN_SMS_LIMIT_CONTROL_ERROR);
            //ALIYUN_SMS_ERROR(-503, "短信发送失败"),//其他失败
            Assert.equals("OK", code, ResponseEnum.ALIYUN_SMS_ERROR);
        } catch (ServerException e) {
            log.error("阿里云短信发送SDK调用失败:");
            log.error("ErrorCode=" + e.getErrCode());
            log.error("ErrorMessage=" + e.getErrMsg());
            throw new BusinessException(ResponseEnum.ALIYUN_SMS_ERROR , e);
        } catch (ClientException e) {
            log.error("阿里云短信发送SDK调用失败:");
            log.error("ErrorCode=" + e.getErrCode());
            log.error("ErrorMessage=" + e.getErrMsg());
            throw new BusinessException(ResponseEnum.ALIYUN_SMS_ERROR , e);
        }
    }
}
9.2.4.2、引入工具类

guigu-common中创建util包,引入工具类:
RandomUtils.java:生成四位或六位的验证码
RegexValidateUtils.java:常用正则表达式验证,这里提供了手机号码验证

9.2.4.3、创建controller

创建controller.api包,创建类ApiSmsController

package com.atguigu.srb.sms.controller.api;

@RestController
@RequestMapping("/api/sms")
@Api(tags = "短信管理")
@CrossOrigin //跨域
@Slf4j
public class ApiSmsController {
    @Resource
    private SmsService smsService;
    @Resource
    private RedisTemplate redisTemplate;
    @ApiOperation("获取验证码")
    @GetMapping("/send/{mobile}")
    public R send(
            @ApiParam(value = "手机号", required = true)
            @PathVariable String mobile){
        //MOBILE_NULL_ERROR(-202, "手机号不能为空"),
        Assert.notEmpty(mobile, ResponseEnum.MOBILE_NULL_ERROR);
        //MOBILE_ERROR(-203, "手机号不正确"),
        Assert.isTrue(RegexValidateUtils.checkCellphone(mobile), ResponseEnum.MOBILE_ERROR);
        //生成验证码
        String code = RandomUtils.getFourBitRandom();
        //组装短信模板参数
        Map<String,Object> param = new HashMap<>();
        param.put("code", code);
        //发送短信
        smsService.send(mobile, SmsProperties.TEMPLATE_CODE, param);
        //将验证码存入redis
        redisTemplate.opsForValue().set("srb:sms:code:" + mobile, code, 5, TimeUnit.MINUTES);
        return R.ok().message("短信发送成功");
    }
}

9.2.5、配置Swagger

9.2.5.1、添加配置

service-base中添加网站端api的配置

    @Bean
    public Docket apiConfig(){
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("api")
                .apiInfo(apiInfo())
                .select()
                //只显示admin路径下的页面
                .paths(Predicates.and(PathSelectors.regex("/api/.*")))
                .build();
    }
    private ApiInfo apiInfo(){
        return new ApiInfoBuilder()
                .title("尚融宝-API文档")
                .description("本文档描述了尚融宝接口")
                .version("1.0")
                .contact(new Contact("Helen", "http://atguigu.com", "55317332@qq.com"))
                .build();
    }
9.2.5.2、测试

测试正确发送

测试手机号码不正确

测试业务限流

10、分布式文件系统-阿里云OSS

10.1、阿里云存储OSS

10.1.1、开通“对象存储OSS”服务

为了解决海量数据存储与弹性扩容,项目中我们采用云存储的解决方案- 阿里云OSS。

10.1.1.1、开通“对象存储OSS”服务

在这里插入图片描述

在这里插入图片描述

10.1.1.2、进入管理控制台

在这里插入图片描述

10.1.2、控制台使用

10.1.2.1、创建Bucket

命名:srb-file

读写权限:公共读

10.1.2.2、上传默认头像

创建文件夹avatar,上传默认的用户头像

在这里插入图片描述

10.1.3、使用RAM子用户

10.1.3.1、进入子用户管理页面

在这里插入图片描述

在这里插入图片描述

10.1.3.2、添加用户

在这里插入图片描述

10.1.3.3、获取子用户key

AccessKeyId, AccessKeySecret

10.1.3.4、设置用户权限

AliyunOSSFullAccess

在这里插入图片描述

10.2、使用SDK访问OSS

10.2.1、使用SDK

在OSS的概览页右下角找到“Bucket管理”,点击“OSS学习路径”

在这里插入图片描述

点击“Java SDK”进入SDK开发文档

在这里插入图片描述

10.2.2、创建测试项目

10.2.2.1、创建Maven项目

com.atguigu

aliyun-oss

10.2.2.2、配置pom

在这里插入图片描述

<dependencies>
    <!--aliyunOSS-->
    <dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
        <version>3.10.2</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>

10.2.3、测试用例

10.2.3.1、创建Bucket

在这里插入图片描述

package com.atguigu.aliyunoss;

public class OSSTest {
    // Endpoint以杭州为例,其它Region请按实际情况填写。
    String endpoint = "your endpoint";
    // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
    String accessKeyId = "your accessKeyId";
    String accessKeySecret = "your accessKeySecret";
    String bucketName = "srb-file";
    @Test
    public void testCreateBucket() {
        
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 创建存储空间。
        ossClient.createBucket(bucketName);
        // 关闭OSSClient。
        ossClient.shutdown();
    }
}
10.2.3.2、判断bucket是否存在
@Test
public void testExist() {
    // 创建OSSClient实例。
    OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    boolean exists = ossClient.doesBucketExist(bucketName);
    System.out.println(exists);
    // 关闭OSSClient。
    ossClient.shutdown();
}
10.2.3.3、设置bucket访问权限
@Test
public void testAccessControl() {
    // 创建OSSClient实例。
    OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    // 设置存储空间的访问权限为:公共读。
    ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
    // 关闭OSSClient。
    ossClient.shutdown();
}

10.3、创建OSS微服务

10.3.1、新建云存储微服务

10.3.1.1、创建模块

service-oss

10.3.1.2、配置pom.xml
<dependencies>
    <dependency>
        <groupId>com.atguigu</groupId>
        <artifactId>service-base</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!--lombok用来简化实体类:需要安装lombok插件-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <!--aliyunOSS-->
    <dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
    </dependency>
    <!-- 日期工具栏依赖 -->
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
    </dependency>
    <!--让自定义的配置在application.yaml进行自动提示-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>
10.3.1.3、配置application.yml
server:
  port: 8130 # 服务端口
spring:
  profiles:
    active: dev # 环境设置
  application:
    name: service-oss # 服务名
aliyun:
  oss:
    endpoint: 你的endponit
    keyId: 你的阿里云keyid
    keySecret: 你的阿里云keysecret
    bucketName: srb-file
10.3.1.4、logback-spring.xml

修改日志路径为 srb_log/oss

10.3.1.5、创建启动类

创建ServiceOssApplication.java

package com.atguigu.srb.oss;

@SpringBootApplication
@ComponentScan({"com.atguigu.srb", "com.atguigu.common"})
public class ServiceOssApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceOssApplication.class, args);
    }
}
10.3.1.6、启动项目

10.3.2、实现文件上传

10.3.2.1、从配置文件读取常量

创建常量读取工具类:OssProperties.java

package com.atguigu.srb.oss.util;

@Setter
@Getter
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class OssProperties implements InitializingBean {
    private String endpoint;
    private String keyId;
    private String keySecret;
    private String bucketName;
    public static String ENDPOINT;
    public static String KEY_ID;
    public static String KEY_SECRET;
    public static String BUCKET_NAME;
    //当私有成员被赋值后,此方法自动被调用,从而初始化常量
    @Override
    public void afterPropertiesSet() throws Exception {
        ENDPOINT = endpoint;
        KEY_ID = keyId;
        KEY_SECRET = keySecret;
        BUCKET_NAME = bucketName;
    }
}
10.3.2.2、文件上传业务

创建Service接口:FileService.java

package com.atguigu.srb.oss.service;

public interface FileService {
    /**
     * 文件上传至阿里云
     */
    String upload(InputStream inputStream, String module, String fileName);
}

实现:FileServiceImpl.java

参考SDK中的:Java->上传文件->简单上传->流式上传->上传文件流

在这里插入图片描述

package com.atguigu.srb.oss.service.impl;

@Service
public class FileServiceImpl implements FileService {
    /**
     * 文件上传至阿里云
     */
    @Override
    public String upload(InputStream inputStream, String module, String fileName) {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(
                OssProperties.ENDPOINT,
                OssProperties.KEY_ID,
                OssProperties.KEY_SECRET);
        //判断oss实例是否存在:如果不存在则创建,如果存在则获取
        if(!ossClient.doesBucketExist(OssProperties.BUCKET_NAME)){
            //创建bucket
            ossClient.createBucket(OssProperties.BUCKET_NAME);
            //设置oss实例的访问权限:公共读
            ossClient.setBucketAcl(OssProperties.BUCKET_NAME, CannedAccessControlList.PublicRead);
        }
        //构建日期路径:avatar/2019/02/26/文件名
        String folder = new DateTime().toString("yyyy/MM/dd");
        //文件名:uuid.扩展名
        fileName = UUID.randomUUID().toString() + fileName.substring(fileName.lastIndexOf("."));
        //文件根路径
        String key = module + "/" + folder + "/" + fileName;
        //文件上传至阿里云
        ossClient.putObject(OssProperties.BUCKET_NAME, key, inputStream);
        // 关闭OSSClient。
        ossClient.shutdown();
        //阿里云文件绝对路径
        return "https://" + OssProperties.BUCKET_NAME + "." + OssProperties.ENDPOINT + "/" + key;
    }
}
10.3.2.3、控制层

创建controller.api:FileController.java

package com.atguigu.srb.oss.controller.api;

@Api(tags = "阿里云文件管理")
@CrossOrigin //跨域
@RestController
@RequestMapping("/api/oss/file")
public class FileController {
    @Resource
    private FileService fileService;
    /**
     * 文件上传
     */
    @ApiOperation("文件上传")
    @PostMapping("/upload")
    public R upload(
            @ApiParam(value = "文件", required = true)
            @RequestParam("file") MultipartFile file,
            @ApiParam(value = "模块", required = true)
            @RequestParam("module") String module)  {
        try {
            InputStream inputStream = file.getInputStream();
            String originalFilename = file.getOriginalFilename();
            String uploadUrl = fileService.upload(inputStream, module, originalFilename);
            //返回r对象
            return R.ok().message("文件上传成功").data("url", uploadUrl);
        } catch (IOException e) {
            throw new BusinessException(ResponseEnum.UPLOAD_ERROR, e);
        }
    }
}
10.3.2.4、Swagger测试

10.3.3、实现文件删除

10.3.3.1、业务层

Service接口:FileService.java

/**
     * 根据路径删除文件
     * @param url
     */
void removeFile(String url);

实现:FileServiceImpl.java

/**
     * 根据路径删除文件
     * @param url
     */
@Override
public void removeFile(String url) {
    // 创建OSSClient实例。
    OSS ossClient = new OSSClientBuilder().build(
        OssProperties.ENDPOINT,
        OssProperties.KEY_ID,
        OssProperties.KEY_SECRET);
    //文件名(服务器上的文件路径)
    String host = "https://" + OssProperties.BUCKET_NAME + "." + OssProperties.ENDPOINT + "/";
    String objectName = url.substring(host.length());
    // 删除文件。
    ossClient.deleteObject(OssProperties.BUCKET_NAME, objectName);
    // 关闭OSSClient。
    ossClient.shutdown();
}
10.3.3.2、控制层
@ApiOperation("删除OSS文件")
@DeleteMapping("/remove")
public R remove(
    @ApiParam(value = "要删除的文件路径", required = true)
    @RequestParam("url") String url) {
    fileService.removeFile(url);
    return R.ok().message("删除成功");
}

本文章参考B站 尚硅谷《尚融宝》Java微服务分布式金融项目,仅供个人学习使用,部分内容为本人自己见解,与尚硅谷无关。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值