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

发布于:2025-04-15 ⋅ 阅读:(22) ⋅ 点赞:(0)

目录

一. 创建阿里云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;

    // 创建并初始化阿里云短信服务的客户端实例
    @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");
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到