当前位置: 首页 > news >正文

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服务获取密钥,开通短信服务)

这里我们就从申请注册短信模板0基础开始,方便小白同学也能快速上手,如果你已经准备好了短信发送的账户密钥等信息,直接跳至第二部分项目实战。

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 就是上面提到的 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; // 创建并初始化阿里云短信服务的客户端实例 @Bean public IAcsClient acsClient() { DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret); return new DefaultAcsClient(profile); } // 发送短信的核心逻辑,通过 IAcsClient 调用阿里云短信服务 API public 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 { @Autowired private 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); @Autowired private UserMapper userMapper; @Autowired private SmsService smsService; @Autowired private StringRedisTemplate stringRedisTemplate; // 方法一: 根据用户名查询用户是否已存在 @Override public 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. 将验证码存入Redis stringRedisTemplate.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.jsqmd.com/news/1207713/

相关文章:

  • 微信聊天记录三格式导出方案:WeChatMsg技术实现与数据主权实践
  • 家里打印机故障码:5B00,5B02,5B04,P07,E08,1700,1702,1704别急着维修店,维修店坑你几百都可能,其实这个故障自己在家就可以修好,3分钟完美修复了,TS3380,亲测完美
  • 2026年成都塑身内衣怎么选不踩雷?5家实测对比与产后恢复避坑推荐 - 中国华商产业观察网
  • CANN/asc-devkit:FreeTensor函数API
  • 天津收的顶黄金回收品牌介绍,深耕行业三十余年正规老牌机构 - 日常比对手册
  • 萧邦中国官方售后服务体系全解析|最新网点地址及官网热线权威公布(2026年7月最新) - 萧邦官方维修中心
  • Cursor日志报错总在凌晨3点爆发?揭秘底层LogBridge架构缺陷与7步黄金修复流程
  • 苹果起诉OpenAI窃取硬件机密 前员工超400人入职引发诉讼
  • 智能诊断与一键修复:猫抓浏览器资源嗅探扩展的现代化解决方案
  • 洁净实验室装修公司设计施工哪家靠谱 - 洁净室推广助手
  • OpenCV在macOS上的完整安装与实战指南:从零开始掌握计算机视觉开发
  • 为什么PyTorch Elastic是分布式训练的未来:3大核心优势解析
  • Relude依赖管理:如何保持轻量级的同时提供强大功能
  • 上海黄金回收门店推荐【收的顶】——全国连锁深耕沪上,16区103店实体可查,现场结款秒到账 - 日常比对手册
  • 3步优化鼠标体验:Mac Mouse Fix完全使用指南
  • ## 郑州二七名表回收不压价,爱彼万国积家实时行情估价 - 逸程奢侈品回收中心
  • 贴牌GEO系统会不会和别人共用数据
  • 【小程序课程设计/毕业设计】基于数字化技术的传统戏曲传承推广系统 轻量化戏曲文化传播服务小程序的设计与实现【附源码、数据库、万字文档】
  • 南充黄金回收市场实地深度调研|顺庆高坪嘉陵本地变现陷阱拆解,2026 年 7 月六家正规门店完整测评 - 不晚生活号
  • FunClip:革命性AI视频剪辑工具,如何让传统剪辑效率提升300%
  • 布局全面升级!2026 年 7 月萧邦大中华区腕表维修网点调整,全渠道联络信息更新 - 萧邦官方维修中心
  • 前端常用数组操作函数
  • SillyTavern终极指南:5步打造栩栩如生的AI角色对话体验
  • 北京化工大学/宁波大学/湖南科技大学Nano Letters:400 °C 2 min焦耳加热去配体 Au15纳米簇实现木质素醇99%芳香酮选择性
  • 购物防踩坑 | 2026 乌鲁木齐大巴扎新疆特产店推荐:伴手礼这样买最划算!避开游客专坑路线 - 速递信息
  • Transformer大模型入门指南:小白也能学会的AI新架构(收藏版)
  • GEO OEM贴牌周期大概多久
  • 如何3步完成Obsidian附件管理革命:告别混乱的终极解决方案
  • 2026年7月最新——苏州高温梅雨季防水攻略:老房/高层/滨湖房三种漏法 - 吉林同城获客
  • 2026广州留学机构排名前五的全国连锁品牌,各自擅长的申请方向及3项核心文书服务质量对比 - 资讯快报