第三方API——Spring Boot 集成阿里云短信发送功能

目录

一. 创建阿里云OSS服务并获取密钥,开通短信服务

1.1 注册阿里云服务器

 1.2 开通短信服务

1.3 创建对象存储OSS服务

1.4 RAM用户授权短信权限

1.5 新增用户并授权用户短信权限

1.6 获取 AccessKey ID 和 AccessKey Secret

二. 创建项目集成短信发送

2.1 引入依赖

2.2 修改 yml 文件

2.3 创建阿里云短信配置类

2.4 编写 SmsService  短信发送模板业务类

2.5 在业务中调用短信发送的方法


一. 创建阿里云OSS服务并获取密钥,开通短信服务

1.1 注册阿里云服务器

点击链接,直接选择一种登录方式注册登陆即可。

阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台

 1.2 开通短信服务

搜索短信服务,点击跳转然后有免费开通。

如下页面,简单过一遍"快速学习与测试"

 走完上面的流程,我们点击"国内消息",然后如右侧页面所示,需要去申请"资质",只要是项目集成都需要申请"资质",资质申请审核完毕;到签名页面添加签名,签名会需要使用到申请的资质,签名创建完毕后,添加我们的短信模板,自行选择即可,也可以自定义模板。

创建完毕之后,一定要把"签名","短信模板Code码"记下来,一会在代码中会用到

这里以我的为例,签名是"aliyunSM666"。

短信模板Code为"SMS_481015005"

 

1.3 创建对象存储OSS服务

左上角搜索输入"对象存储",即可找到对象存储OSS服务,点击跳转。

 然后来到如下页面,点击 Bucket——>创建Bucket 一步步操作即可。

这里需要记一个点,如果创建的地域是北京,那么下面在配置 yml 文件时,aliyun.regionId 的值就是 cn-beijing;如果是杭州,就是 cn-hangzhou;如果是上海,就是cn-shanghai。

1.4 RAM用户授权短信权限

创建完毕 Bucket 完毕后,点击创建的 Bucket 进入详情页。

然后前往RAM控制台

1.5 新增用户并授权用户短信权限

来到RAM控制台,先新增一名用户,然后点击添加权限

在权限策略中输入短信即可搜索到,直接授权给用户即可。 

如果之前已经创建过用户,直接授权即可,也可以像下图所示,到授权页面选择指定用户授权不能

1.6 获取 AccessKey ID 和 AccessKey Secret

点击右上角用户头像

跳转到 AccessKey 详情页,如果没有则新建一个即可,

注意!!!AssessKey Secret 新建后不会再展示,首次新建请保存,如果遗忘只需禁用现有的AssessKey,再新建一个即可。

二. 创建项目集成短信发送

2.1 引入依赖
    <!-- 阿里云核心 SDK --><dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-core</artifactId><version>4.5.16</version></dependency><!-- 短信服务 SDK --><dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-dysmsapi</artifactId><version>2.1.0</version></dependency><!-- OSS SDK --><dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.15.1</version></dependency>

2.2 修改 yml 文件

如下图所示,修改项目的 yml 文件,在 yml 文件中添加 aliyun 配置。

assessKeyId 就是上面第一步提到的 AccessKey ID;

accessKeySecret 就是上面提到的 AccessKey Secret;

regionId 激素hi上面提到的 cn-shanghai;根据自己创建的 Bucket 区域而定。

2.3 创建阿里云短信配置类

在下面配置类中,首先获取 yml 配置文件中设置的值,然后编写返回实例的方法并将值赋值给新建实例。

然后,使用短信客户端实例调用 API 接口发送短信,这里写为一个方法,传递手机号,签名,短信模板Code值,然后再其他业务类型,注入此配置类的实例,调用 sendSms 方法,根据业务需求传递不同的短信Code发送不同的短信。

@Configuration
public class AliyunSmsConfig {// 1.阿里云账号的accessKeyId@Value("${aliyun.assessKeyId}")private String accessKeyId;// 2.阿里云账号的accessKeySecret@Value("${aliyun.assessKeySecret}")private String accessKeySecret;// 3.阿里云账号的regionId@Value("${aliyun.regionId}")private String regionId;// 创建并初始化阿里云短信服务的客户端实例@Beanpublic IAcsClient acsClient() {DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);return new DefaultAcsClient(profile);}// 发送短信的核心逻辑,通过 IAcsClient 调用阿里云短信服务 APIpublic SendSmsResponse sendSms(String phoneNumber, String signName, String templateCode, String templateParam) throws Exception {IAcsClient client = acsClient();SendSmsRequest request = new SendSmsRequest();request.setPhoneNumbers(phoneNumber);request.setSignName(signName);request.setTemplateCode(templateCode);request.setTemplateParam(templateParam);return client.getAcsResponse(request);}
}

2.4 编写 SmsService  短信发送模板业务类

在上面,我们已经定义好了发送短信的方法,按道理来说,直接 @Autowired 注入 配置的 Bean 实例就可以了,但是我们观察上方方法,其实还不够简洁,因为 sendSms 方法中,只有 phone 手机号一个参数是需要用户传递的,其他的参数是不需要的。

因此,我们最好再进行一层抽取,将每一种发送短信验证码的方法写成一个 Service 业务类,这样一来其他类当要发送短信的时候,直接调用封装好的 Service 中的方法即可,优化了原本的业务类代码。

如下代码所示,

定义一个发送登录验证码的方法 "sendLoginVerificationCode",还可以定义发送修改密码的验证码 "sendUpdatePasswordVerificationCode",还可以定义付钱的验证码方法 "sendPayMoneyVerificationCode"。

当然啦,这里只是举个例子,实际业务项目中,需要发送的短信验证码肯定也是多种多样的,可以定义多个方法,也可以定义一个通用方法,都是可以的,小编这里就采用这种常用写法啦。

@Service
@Slf4j
public class SmsService {@Autowiredprivate AliyunSmsConfig aliyunSmsConfig;public boolean sendLoginVerificationCode(String phoneNumber, String code) {try {SendSmsResponse response = aliyunSmsConfig.sendSms(phoneNumber,"aliyunSMS666","SMS_481015005","{\"code\":\"" + code + "\"}");log.info(response.getCode());return "OK".equals(response.getCode());} catch (Exception e) {e.printStackTrace();return false;}}public boolean sendUpdatePasswordVerificationCode(String phoneNumber, String code) {try {SendSmsResponse response = aliyunSmsConfig.sendSms(phoneNumber,"aliyunSMS666","SMS_481015005","{\"code\":\"" + code + "\"}");log.info(response.getCode());return "OK".equals(response.getCode());} catch (Exception e) {e.printStackTrace();return false;}}public boolean sendPayMoneyVerificationCode(String phoneNumber, String code) {......}
}

2.5 在业务中调用短信发送的方法

上面的工作都做完之后,我们就可以进入到真正的业务层了,如下代码,其实非常简单,这里小编定义了五个方法,其实这里的 sendCode 方法是可以不用要的,毕竟代码不多,也可以直接将代码写入到 login 登陆方法中。

"selectByUsername" 查询用户方法;

"sendCode"发送短信方法;

"login" 登陆方法;

"createUser" 创建新用户方法;

"generateTokenByUid" 生成用户 token 方法;

逻辑很简单,都有注释,大家一步一步看即可。

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {// 添加类顶部声明private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);@Autowiredprivate UserMapper userMapper;@Autowiredprivate SmsService smsService;@Autowiredprivate StringRedisTemplate stringRedisTemplate;// 方法一: 根据用户名查询用户是否已存在@Overridepublic Boolean selectByUsername(String username) {return !userMapper.selectByUserName(username).isEmpty();}/* 方法二: 发送短信方法 */public Boolean sendCode(String phone) {// 1. 生成6位随机数作为验证码SecureRandom secureRandom = new SecureRandom();String code = String.valueOf(100000 + secureRandom.nextInt(900000));// 2. 将验证码存入RedisstringRedisTemplate.opsForValue().set(phone,String.valueOf(code),5, java.util.concurrent.TimeUnit.MINUTES);// 3. 发送验证码try {logger.info("准备发送验证码,手机号:{},验证码:{}",phone,code);return smsService.sendLoginVerificationCode(phone, code);} catch (Exception e) {logger.error("短信发送失败,手机号:{},错误信息:{}", phone, e.getMessage(), e);return false;}}/* 方法三:用户登录+注册接口综合方法 */public Result<Boolean> login(LoginDto loginDto, HttpServletRequest request, HttpServletResponse response){Result<Boolean> result = new Result<>();// 1. 登陆方式一: 手机号+短信登录if (loginDto.getPhone() != null && loginDto.getCode() != null){List<User> users = userMapper.selectUserByPhone(loginDto.getPhone());if (users.isEmpty()){createUser(loginDto);}String code = stringRedisTemplate.opsForValue().get(loginDto.getPhone());if (code != null && code.equals(loginDto.getCode())){generateTokenByUid(users.get(0).getId(), request, response);result.setCode(200);result.setData(true);result.setMsg("success");}else{result.setCode(999);result.setMsg("验证码错误");result.setData(false);}return result;}// 2. 登陆方式二:手机号+密码登录else if (loginDto.getUsername() != null && loginDto.getPassword() != null){User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", loginDto.getUsername()));if (user != null && MD5Utils.md5HashWithSalt(loginDto.getPassword(), user.getSalt()).equals(user.getPassword())){generateTokenByUid(user.getId(), request, response);result.setCode(200);result.setData(true);result.setMsg("success");}else{result.setCode(999);result.setMsg("密码错误");result.setData(false);}result.setCode(999);result.setMsg("未知错误");result.setData(false);return result;}// 3. 登陆方式三:用户名+密码登录else if (loginDto.getUsername() != null || loginDto.getPassword() != null) {User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", loginDto.getUsername()));if (user != null && MD5Utils.md5HashWithSalt(loginDto.getPassword(), user.getSalt()).equals(user.getPassword())){generateTokenByUid(user.getId(), request, response);result.setCode(200);result.setData(true);result.setMsg("success");}else if (user == null && loginDto.getPassword() != null && loginDto.getPassword2() != null && loginDto.getPassword().equals(loginDto.getPassword2())){User newUser = createUser(loginDto);generateTokenByUid(newUser.getId(), request, response);}else {result.setCode(999);result.setMsg("密码错误");result.setData(false);}}result.setCode(999);result.setMsg("未知错误");result.setData(false);return result;}/* 方法四:创建新用户方法 */public User createUser(LoginDto loginDto){User user = new User();user.setPhone(loginDto.getPhone());user.setStatus(0);if (loginDto.getUsername() != null){user.setUsername(loginDto.getUsername());// 生成随机密码盐值字符串String salt = UUID.randomUUID().toString().replaceAll("-", "");user.setSalt(salt);user.setPassword(MD5Utils.md5HashWithSalt(loginDto.getPassword(), salt));}user.setAvatar("https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg");user.setCreated(LocalDateTime.now());userMapper.insert(user);return user;}/* 方法五:生成 Token 方法*/public void generateTokenByUid(Long uid, HttpServletRequest request, HttpServletResponse response){String token = JwtUtils.generateToken(uid);response.setHeader("Authorization", token);response.setHeader("Access-control-Expose-Headers", "Authorization");}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/77470.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

b站PC网页版视频播放页油猴小插件制作

文章目录 前言需求分析实施观察页面起始渲染编码效果展示 总结 前言 新手上路,欢迎指导 需求分析 想要一个简约干净的界面,需要去除推荐栏和广告部分. 想要自由调节视频播放速率,需要在视频控制栏加一个输入框控制视频倍速 实施 观察页面起始渲染 因为要使用MutationObse…

畅游Diffusion数字人(27):解读字节跳动提出主题定制视频生成技术Phantom

畅游Diffusion数字人(0):专栏文章导航 前言:主题定制视频生成,特别是zero-shot主题定制视频生成,一直是当前领域的一个难点,之前的方法效果很差。字节跳动提出了一个技术主题定制视频生成技术Phantom,效果相比于之前的技术进步非常显著。这篇博客详细解读一下这一工作。 …

ESP8266简单介绍

ESP8266模块图如下 ESP8266的工作模式有三种 ESP8266支持STA、AP、STAAP三种工作模式 ①STA模式 &#xff08;ESP充当设备与路由器相连&#xff09; ②AP模式 &#xff08;ESP充当路由器&#xff09; ③APSTA&#xff08;上述两种模式兼具&#xff09; AT指令介绍 使用安…

DeepSeek-R3、GPT-4o 与 Claude-3.5-Sonnet 全面对比:性能、应用场景与技术解析

随着大模型技术的迅猛发展&#xff0c;国产模型正逐渐崭露头角&#xff0c;尤其是DeepSeek-R3的发布&#xff0c;更是在AI技术社区中引起广泛关注。而与此同时&#xff0c;国际领先的GPT-4o和Claude-3.5-Sonnet也在不断迭代升级&#xff0c;持续刷新业界对AI能力的认知。下文将…

城市街拍暗色电影胶片风格Lr调色教程,手机滤镜PS+Lightroom预设下载!

调色介绍 城市街拍暗色电影胶片风格 Lr 调色&#xff0c;是借助 Adobe Lightroom 软件&#xff0c;为城市街拍的人像或场景照片赋予独特视觉风格的后期处理方式。旨在模拟电影胶片质感&#xff0c;营造出充满故事感与艺术感的暗色氛围&#xff0c;让照片仿佛截取于某部充满张力…

数字后端设计 (一):数字电路设计的「前后端」到底是什么?

—— 想象你在做一道菜——前端设计是写菜谱&#xff0c;后端设计是进厨房真正炒菜。这篇文章帮你搞懂「芯片设计」里这两个阶段到底在干嘛。 1. 前端设计——写一份「理想化」的菜谱 任务&#xff1a;用代码描述芯片的功能。例子&#xff1a;你要做一个自动计算“112”的芯片…

网站301搬家后谷歌一直不收录新页面怎么办?

当网站因更换域名或架构调整启用301重定向后&#xff0c;许多站长发现谷歌迟迟不收录新页面&#xff0c;甚至流量大幅下滑。 例如&#xff0c;301跳转设置错误可能导致权重传递失效&#xff0c;而新站内容与原站高度重复则可能被谷歌判定为“低价值页面”。 即使技术层面无误&a…

WiFi“管家”------hostapd的工作流程

目录 1. 启动与初始化 1.1 解析命令行参数 1.2 读取配置文件 1.3 创建接口和 BSS 数据结构 1.4 初始化驱动程序 2. 认证和关联处理 2.1 监听认证请求 2.2 处理认证请求 2.3 处理关联请求 3. 数据转发 3.1 接收客户端数据 3.2 转发数据 4. 断开连接处理 4.1 处理客…

YOLOv2 快速入门与核心概念:更快、更准的目标检测利器

今天&#xff0c;我们就来聊聊 YOLO 系列的第二代—— YOLOv2&#xff0c;看看它是如何在速度的基础上&#xff0c;进一步提升检测精度的。 目标检测的重要性&#xff1a;让机器“看懂”世界 想象一下&#xff0c;自动驾驶汽车需要实时识别道路上的车辆、行人、交通标志&…

[苍穹外卖 | 项目日记] 第三天

前言 实现了新增菜品接口实现了菜品分页查询接口实现了删除菜品接口实现了根据id查询菜品接口实现了修改菜品接口 今日收获&#xff1a; 今日的这几个接口其实和之前写的对员工的操作是一样的&#xff0c;都是一整套Curd操作&#xff0c;所以今天在技术层面上并没有…

Go语言入门到入土——三、处理并返回异常

Go语言入门到入土——三、处理并返回异常 文章目录 Go语言入门到入土——三、处理并返回异常1. 在greetings.go中添加异常处理代码2. 在hello.go中添加日志记录代码3. 运行 1. 在greetings.go中添加异常处理代码 处理空输入的异常&#xff0c;代码如下&#xff1a; package g…

创维E900V20C-国科GK6323V100C-rtl8822cs-安卓9.0-短接强刷卡刷固件包

创维E900V20C&#xff0f;创维E900V20D-国科GK6323V100C-安卓9.0-强刷卡刷固件包 创维E900V20C 刷机说明&#xff1a; 1、用个老款4G&#xff0c;2.0的U盘&#xff0c;fat32&#xff0c;2048块单分区格式化&#xff0c; 5个文件复制到根目录&#xff0c;插盒子靠网口U口&…

视频分析设备平台EasyCVR安防视频管理系统,打造电石生产智能视频监控新体系

一、背景介绍 电石生产中的出炉工序是整个生产流程中最为繁重且危险的环节。在开堵炉眼的过程中&#xff0c;电石极易发生飞溅现象&#xff0c;尤其在进行吹氧操作时&#xff0c;人员灼伤的风险极高。鉴于此&#xff0c;该工序正逐步由传统的人工操作模式向智能化方向转变。然…

Verilog的整数除法

1、可变系数除法实现----利用除法的本质 timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2025/04/15 13:45:39 // Design Name: // Module Name: divide_1 // Project Name: // Target Devices: // Tool Versions: // Description: // // Depe…

UniApp + Cursor + Devbox 全栏平台开发教程:从0到完整项目打造

本文基于B站热门教程《一口气学会小程序 / App / H5开发:UniApp教程 + Cursor + Devbox》,https://www.bilibili.com/video/BV1W7QZYMEus/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=a1428945043b2df41c1896acb90d942a,进行全面扩展…

ESP32-idf学习(一)搭建环境和点灯

一、前言 先说一下查到的数据&#xff08;不保证准确&#xff09;&#xff1a; 1、连续四年Wi-Fi MCU全球市场份额第一&#xff0c;产品应用于智能家居、工业自动化、医疗健康等泛IoT领域‌&#xff0c;2024 年营收突破 20 亿元&#xff08;同比 40%&#xff09;&#xff0c;…

hooker frida版just_trust_me.js 2025升级 支持boringssl unpinning

曾几何时&#xff0c;我翻版了 Xposed 的 just_trust_me.apk&#xff0c; just_trust_me.js 脚本仿佛是一张通行证&#xff0c;让我们在 SSL Pinning 的高墙前轻松穿越。 但时代变了。BoringSSL、Cronet、静态 inline hook、动态 verify callback……一切都变得更加隐蔽和棘手…

通信算法之269 : OFDM信号的循环自相关特性用于无人机图传信号识别

OFDM信号的循环自相关特性是其循环平稳性的核心体现,如下: [相关仿真代码,联系,提供] 一、循环自相关特性来源 ‌循环前缀引入周期性‌ OFDM符号通过添加循环前缀(CP)形成符号周期结构,导致信号具有循环平稳性‌26。每个符号的CP与尾部数据重复,在时延等于FFT长度(N…

vue3环境搭建、nodejs22.x安装、yarn 1全局安装、npm切换yarn 1、yarn 1 切换npm

vue3环境搭建 node.js 安装 验证nodejs是否安装成功 # 检测node.js 是否安装成功----cmd命令提示符中执行 node -v npm -v 设置全局安装包保存路径、全局装包缓存路径 在node.js 安装路径下 创建 node_global 和 node_cache # 设置npm全局安装包保存路径&#xff08;新版本…

基于尚硅谷FreeRTOS视频笔记——6—滴答时钟—上下文切换

FreeRTOS滴答 FreeRTOS需要有一个时钟参照&#xff0c;并且这个时钟不会被轻易打断&#xff0c;所以最好选择systick 为什么需要时间参照 就是在高优先级任务进入阻塞态后&#xff0c;也可以理解为进入delay&#xff08;&#xff09;函数后&#xff0c;需要有一个时间参照&…