SpringBoot 整合阿里云短信
1. pom.xml Maven依赖
<dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.5.17</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-dysmsapi</artifactId> <version>2.1.0</version> </dependency>
2. application.yml 配置文件
sms: common: code-length: 6 code-period: 300 aliyun: access-key-id: LTAISDdmjBtCU1CQ access-key-secret: beutUXdEqZCaaeKzwlXD79WSdsG243 template: sign-name: dcy # 登录模板 code-login: SMS_209131746 # 重置密码模板 code-reset-password: SMS_202631506 error-code: isv: RAM_PERMISSION_DENY: RAM权限DENY OUT_OF_SERVICE: 业务停机 PRODUCT_UN_SUBSCRIPT: 未开通云通信产品的阿里云客户 PRODUCT_UNSUBSCRIBE: 产品未开通 ACCOUNT_NOT_EXISTS: 账户不存在 ACCOUNT_ABNORMAL: 账户异常 SMS_TEMPLATE_ILLEGAL: 短信模板不合法 SMS_SIGNATURE_ILLEGAL: 短信签名不合法 INVALID_PARAMETERS: 参数异常 SYSTEM_ERROR: 系统错误 MOBILE_NUMBER_ILLEGAL: 非法手机号 MOBILE_COUNT_OVER_LIMIT: 手机号码数量超过限制 TEMPLATE_MISSING_PARAMETERS: 模板缺少变量 BUSINESS_LIMIT_CONTROL: 业务限流 INVALID_JSON_PARAM: JSON参数不合法,只接受字符串值 BLACK_KEY_CONTROL_LIMIT: 黑名单管控 PARAM_LENGTH_LIMIT: 参数超出长度限制 PARAM_NOT_SUPPORT_URL: 不支持URL AMOUNT_NOT_ENOUGH: 账户余额不足
3. 配置类
package com.ruhuanxingyun.dcy.service.manage.config; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.IClientProfile; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.Map; /** * @description: 阿里云短信 * @author: ruphie * @date: Create in 2021/4/17 9:24 * @company: ruhuanxingyun */ @Configuration @ConfigurationProperties(prefix = "sms") @Data public class AliyunSmsProvider { /** * 公共信息 */ private Common common = new Common(); /** * 阿里云短信 */ private Aliyun aliyun = new Aliyun(); @Data public class Common { /** * 验证码长度 */ private int codeLength; /** * 验证码有限期 */ private long codePeriod; } @Data public class Aliyun { /** * accessKeyId */ private String accessKeyId; /** * accessKeySecret */ private String accessKeySecret; /** * 模板 */ private Template template = new Template(); /** * 错误码 */ private Map<String, String> errorCode; @Data public class Template { /** * 签名 */ private String signName; /** * 登录模板 */ private String codeLogin; /** * 重置密码模板 */ private String codeResetPassword; } } @Bean public IAcsClient acsClient() { // 设置超时时间 System.setProperty("sun.net.client.defaultConnectTimeout", "5000"); System.setProperty("sun.net.client.defaultReadTimeout", "5000"); // 初始化ascClient IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", aliyun.getAccessKeyId(), aliyun.getAccessKeySecret()); DefaultProfile.addEndpoint("cn-hangzhou", "Dysmsapi", "dysmsapi.aliyuncs.com"); return new DefaultAcsClient(profile); } }
4. 服务层
package com.ruhuanxingyun.dcy.service.manage.service; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSONObject; import com.aliyuncs.IAcsClient; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest; import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse; import com.ruhuanxingyun.dcy.service.manage.config.AliyunSmsProvider; import com.ruhuanxingyun.dcy.service.manage.constant.RedisConstants; import com.ruhuanxingyun.dcy.service.manage.constant.UserConstants; import com.ruhuanxingyun.dcy.service.manage.enums.CodeEnum; import com.ruhuanxingyun.dcy.service.manage.enums.StatusEnum; import com.ruhuanxingyun.dcy.service.manage.model.dto.SmsDTO; import com.ruhuanxingyun.dcy.service.manage.model.entity.system.User; import com.ruhuanxingyun.dcy.service.manage.service.system.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; /** * @description: 短信 服务层 * @author: ruphie * @date: Create in 2021/4/17 9:45 * @company: ruhuanxingyun */ @Slf4j @Service public class SmsService { @Autowired private UserService userService; @Autowired private AliyunSmsProvider aliyunSmsProvider; @Autowired private IAcsClient acsClient; @Autowired private StringRedisTemplate stringRedisTemplate; /** * 发送短信验证码 * * @param smsDTO 短信信息 * @return 状态 */ public String sendSmsCode(SmsDTO smsDTO) { String phone = smsDTO.getPhone(); // 校验手机号 String result = this.verifyPhone(phone); if (StrUtil.isNotBlank(result)) { return result; } AliyunSmsProvider.Common common = aliyunSmsProvider.getCommon(); StringBuilder code = new StringBuilder(); // 生成验证码 for (int i = 0, len = common.getCodeLength(); i < len; i++) { code.append((int) (Math.random() * 10)); } // 获取短信配置 AliyunSmsProvider.Aliyun aliyun = aliyunSmsProvider.getAliyun(); AliyunSmsProvider.Aliyun.Template template = aliyun.getTemplate(); String templateCode; String codeType = smsDTO.getCodeType(); if (StrUtil.equals("login", codeType)) { templateCode = template.getCodeLogin(); } else if (StrUtil.equals("resetPwd", codeType)) { templateCode = template.getCodeResetPassword(); } else { log.warn("手机号【{}】发送短信的验证码类型{}不存在", phone, codeType); return "验证码类型不存在"; } // 组装请求对象 SendSmsRequest request = new SendSmsRequest(); request.setPhoneNumbers(phone); // 短信签名 request.setSignName(template.getSignName()); // 短信模板 request.setTemplateCode(templateCode); Map<String, String> params = new HashMap<>(2); params.put("code", code.toString()); // 变量替换 request.setTemplateParam(JSONObject.toJSONString(params)); try { // 执行请求 SendSmsResponse response = acsClient.getAcsResponse(request); String smsCode = response.getCode(); if (StrUtil.equals(HttpStatus.OK.getReasonPhrase(), smsCode)) { // 储存验证码 stringRedisTemplate.opsForValue().set(String.format("dcy:service:manage:sms:%s:%s", codeType, phone), code.toString(), common.getCodePeriod(), TimeUnit.SECONDS); return null; } // 错误信息 return aliyun.getErrorCode().get(smsCode); } catch (Exception e) { log.error("手机号【{}】发送类型【{}】的验证码失败", phone, codeType, e); return "验证码发送失败"; } } /** * 校验手机号 * * @param phone 手机号 * @return 校验状态 */ private String verifyPhone(String phone) { User user = userService.lambdaQuery() .select(User::getIsDisabled) .eq(User::getPhone, phone) .one(); if (ObjectUtil.isNull(user)) { return "账号不存在"; } if (user.getIsDisabled() == 1) { return "账号已禁用"; } return null; } }
可参考:阿里云短信服务
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗