前言:
而今我们对“腾讯云sms服务”大概比较珍视,看官们都想要了解一些“腾讯云sms服务”的相关文章。那么小编在网上网罗了一些有关“腾讯云sms服务””的相关文章,希望看官们能喜欢,朋友们快快来学习一下吧!签名申请
在开始之前,需要事前申请签名和创建短信模板,后面代码中会用到,地址在这里 腾讯云->申请签名,申请完等待审核通过即可。
申请签名创建模板等待审核代码实现pom.xml
首先要安装下腾讯云的包
<dependency> <groupId>com.tencentcloudapi</groupId> <artifactId>tencentcloud-sdk-java</artifactId> <version>3.1.62</version> <scope>compile</scope></dependency>application.yml
把代码中需要用到的一些重要信息配置到yml中。
sms: # 腾讯云中的secretId secretId: AKIDb3MYaQ2QjvwmOnyukOq24vc7EWSCVcXE # 腾讯云中的secretKey secretKey: VpzyjIjy0oNjv0ywthXCiDXcVEkJewer # 腾讯云中的appid,在应用列表那里 appid: 1400795322 # 签名管理中的前面内容 signName: 若依页面分层工具网 # 使用的端点,腾讯云默认sms.tencentcloudapi.com endpoint: sms.tencentcloudapi.com # 地区 region: ap-shanghaisms配置类
通过@ConfigurationProperties读取配置信息并与 bean 绑定,在后面的业务代码中会读取这些配置信息。
@Data@Component@ConfigurationProperties(prefix = "sms")public class MessageConfig { /** 腾讯云中的secretId */ private String secretId; /** 腾讯云中的secretKey */ private String secretKey; /** 腾讯云中的appid */ private String appid; /** 签名 */ private String signName; /** 使用的端点 */ private String endpoint; /** 地区 */ private String region;}sms短信实现
使用redis缓存每次发送的验证码,过期时间为10mins;表单提交时,做验证码的有效性和正确性判断。
下面这些代码是获取验证码的主要部分,后面在实现类中直接调该方法即可!
@Servicepublic class Message { @Autowired private MessageConfig messageConfig; @Autowired private RedisCache redisCache; public SendSmsResponse smsClient(String phone) throws TencentCloudSDKException { /* 必要步骤: * 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。 * 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。 * 你也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人, * 以免泄露密钥对危及你的财产安全。 * CAM密匙查询: */ Credential cred = new Credential(messageConfig.getSecretId(), messageConfig.getSecretKey()); // 实例化一个http选项,可选,没有特殊需求可以跳过 HttpProfile httpProfile = new HttpProfile(); /* SDK默认使用POST方法。 * 如果你一定要使用GET方法,可以在这里设置。GET方法无法处理一些较大的请求 */ httpProfile.setReqMethod("POST"); /* SDK有默认的超时时间,非必要请不要进行调整 * 如有需要请在代码中查阅以获取最新的默认值 */ httpProfile.setConnTimeout(60); /* SDK会自动指定域名。通常是不需要特地指定域名的,但是如果你访问的是金融区的服务 * 则必须手动指定域名,例如sms的上海金融区域名: sms.ap-shanghai-fsi.tencentcloudapi.com */ httpProfile.setEndpoint(messageConfig.getEndpoint()); /* 非必要步骤: * 实例化一个客户端配置对象,可以指定超时时间等配置 */ ClientProfile clientProfile = new ClientProfile(); /* SDK 默认用 TC3-HMAC-SHA256 进行签名 * 非必要请不要修改该字段 */ clientProfile.setSignMethod("HmacSHA256"); clientProfile.setHttpProfile(httpProfile); SmsClient client = new SmsClient(cred, messageConfig.getRegion(), clientProfile); /* 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数 * 你可以直接查询SDK源码确定接口有哪些属性可以设置 * 属性可能是基本类型,也可能引用了另一个数据结构 * 推荐使用IDE进行开发,可以方便的跳转查阅各个接口和数据结构的文档说明 */ SendSmsRequest req = new SendSmsRequest(); /* 填充请求参数,这里request对象的成员变量即对应接口的入参 * 你可以通过官网接口文档或跳转到request对象的定义处查看请求参数的定义 * 基本类型的设置: * 帮助链接: * 短信控制台: * sms helper: */ /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId,示例如1400006666 */ String sdkAppId = messageConfig.getAppid(); req.setSmsSdkAppid(sdkAppId); /* 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名,签名信息可登录 [短信控制台] 查看 */ String signName = messageConfig.getSignName(); req.setSign(signName); /* 国际/港澳台短信 SenderId: 国内短信填空,默认未开通,如需开通请联系 [sms helper] */ String senderid = ""; req.setSenderId(senderid); /* 用户的 session 内容: 可以携带用户侧 ID 等上下文信息,server 会原样返回 */ String sessionContext = SecurityUtils.getUsername(); req.setSessionContext(sessionContext); /* 短信号码扩展号: 默认未开通,如需开通请联系 [sms helper] */ String extendCode = ""; req.setExtendCode(extendCode); /* 模板 ID: 必须填写已审核通过的模板 ID。模板ID可登录 [短信控制台] 查看 */ String templateId = "1771557"; req.setTemplateID(templateId); /* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号] * 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号 */ String[] phoneNumberSet = {"+86" + phone}; req.setPhoneNumberSet(phoneNumberSet); /* 模板参数: 若无模板参数,则设置为空 */ int code = (int) ((Math.random() * 9 + 1) * 1000); //生成6位随机数字 String[] templateParamSet = {String.valueOf(code)}; req.setTemplateParamSet(templateParamSet); // redis缓存手机号对应的验证码,这里的code要存入字符串类型,要和前端传入的code类型保持一致! redisCache.setCacheObject(Constants.SMS_CODE_KEY + phone, String.valueOf(code), Constants.SMS_EXPIRATION, TimeUnit.MINUTES); /* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的 * 返回的 res 是一个 SendSmsResponse 类的实例,与请求对象对应 */ SendSmsResponse res = client.SendSms(req); return res; }}
Constants类
public class Constants{ /** * sms有效期 */ public static final Integer SMS_EXPIRATION = 10; /** * 短信sms redis key */ public static final String SMS_CODE_KEY = "sms_codes:"; }redis配置添加依赖
<!-- redis 缓存操作 --><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency>修改配置
# Spring配置spring: redis: # 地址 host: xxx.xx.xx.xx # 端口,默认为6379 port: 6379 # 数据库索引 database: 0 # 密码 password: root # 连接超时时间 timeout: 10s lettuce: pool: # 连接池中的最小空闲连接 min-idle: 0 # 连接池中的最大空闲连接 max-idle: 8 # 连接池的最大数据库连接数 max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms序列化和反序列化redis的key值
序列化
狭义的层面:将对象转换为字节广义的层面:将对象转换为指定格式的字符串
反序列化
狭义的层面:将字节转换为对象广义的层面:将指定格式的字符串转换为对象
序列化和反序列化代码
/** * redis配置 */@Configuration@EnableCachingpublic class RedisConfig extends CachingConfigurerSupport{ @Bean @SuppressWarnings(value = { "unchecked", "rawtypes" }) public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); serializer.setObjectMapper(mapper); // 使用StringRedisSerializer来序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(serializer); // Hash的key也采用StringRedisSerializer的序列化方式 template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(serializer); template.afterPropertiesSet(); return template;}@Beanpublic DefaultRedisScript<Long> limitScript(){ DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); redisScript.setScriptText(limitScriptText()); redisScript.setResultType(Long.class); return redisScript;}/** * 限流脚本 */private String limitScriptText(){ return "local key = KEYS[1]\n" + "local count = tonumber(ARGV[1])\n" + "local time = tonumber(ARGV[2])\n" + "local current = redis.call('get', key);\n" + "if current and tonumber(current) > count then\n" + " return tonumber(current);\n" + "end\n" + "current = redis.call('incr', key)\n" + "if tonumber(current) == 1 then\n" + " redis.call('expire', key, time)\n" + "end\n" + "return tonumber(current);";}}复制代码}增加工具类
redis工具类
@Componentpublic class RedisCache{ @Autowired public RedisTemplate redisTemplate;/** * 缓存基本的对象,Integer、String、实体类等 * * @param key 缓存的键值 * @param value 缓存的值 */public <T> void setCacheObject(final String key, final T value){ redisTemplate.opsForValue().set(key, value);}/** * 缓存基本的对象,Integer、String、实体类等 * * @param key 缓存的键值 * @param value 缓存的值 * @param timeout 时间 * @param timeUnit 时间颗粒度 */public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit){ redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}/** * 设置有效时间 * * @param key Redis键 * @param timeout 超时时间 * @return true=设置成功;false=设置失败 */public boolean expire(final String key, final long timeout){ return expire(key, timeout, TimeUnit.SECONDS);}/** * 设置有效时间 * * @param key Redis键 * @param timeout 超时时间 * @param unit 时间单位 * @return true=设置成功;false=设置失败 */public boolean expire(final String key, final long timeout, final TimeUnit unit){ return redisTemplate.expire(key, timeout, unit);}/** * 获得缓存的基本对象。 * * @param key 缓存键值 * @return 缓存键值对应的数据 */public <T> T getCacheObject(final String key){ ValueOperations<String, T> operation = redisTemplate.opsForValue(); return operation.get(key);}/** * 删除单个对象 * * @param key */public boolean deleteObject(final String key){ return redisTemplate.delete(key);}/** * 删除集合对象 * * @param collection 多个对象 * @return */public long deleteObject(final Collection collection){ return redisTemplate.delete(collection);}/** * 缓存List数据 * * @param key 缓存的键值 * @param dataList 待缓存的List数据 * @return 缓存的对象 */public <T> long setCacheList(final String key, final List<T> dataList){ Long count = redisTemplate.opsForList().rightPushAll(key, dataList); return count == null ? 0 : count;}/** * 获得缓存的list对象 * * @param key 缓存的键值 * @return 缓存键值对应的数据 */public <T> List<T> getCacheList(final String key){ return redisTemplate.opsForList().range(key, 0, -1);}/** * 缓存Set * * @param key 缓存键值 * @param dataSet 缓存的数据 * @return 缓存数据的对象 */public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet){ BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key); Iterator<T> it = dataSet.iterator(); while (it.hasNext()) { setOperation.add(it.next()); } return setOperation;}/** * 获得缓存的set * * @param key * @return */public <T> Set<T> getCacheSet(final String key){ return redisTemplate.opsForSet().members(key);}/** * 缓存Map * * @param key * @param dataMap */public <T> void setCacheMap(final String key, final Map<String, T> dataMap){ if (dataMap != null) { redisTemplate.opsForHash().putAll(key, dataMap); }}/** * 获得缓存的Map * * @param key * @return */public <T> Map<String, T> getCacheMap(final String key){ return redisTemplate.opsForHash().entries(key);}/** * 往Hash中存入数据 * * @param key Redis键 * @param hKey Hash键 * @param value 值 */public <T> void setCacheMapValue(final String key, final String hKey, final T value){ redisTemplate.opsForHash().put(key, hKey, value);}/** * 获取Hash中的数据 * * @param key Redis键 * @param hKey Hash键 * @return Hash中的对象 */public <T> T getCacheMapValue(final String key, final String hKey){ HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash(); return opsForHash.get(key, hKey);}/** * 删除Hash中的数据 * * @param key * @param mapkey */public void delCacheMapValue(final String key, final String hkey){ HashOperations hashOperations = redisTemplate.opsForHash(); hashOperations.delete(key, hkey);}/** * 获取多个Hash中的数据 * * @param key Redis键 * @param hKeys Hash键集合 * @return Hash对象集合 */public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys){ return redisTemplate.opsForHash().multiGet(key, hKeys);}/** * 获得缓存的基本对象列表 * * @param pattern 字符串前缀 * @return 对象列表 */public Collection<String> keys(final String pattern){ return redisTemplate.keys(pattern);}}复制代码}接口Controller
get请求,传递一个手机号码即可。
@RestController@RequestMapping("/msg")public class SmsMessage { @Autowired private ISmsService ISmsService; //发送短信 @GetMapping("/sendMsg") public SendSmsResponse sendMessage(String phone) throws TencentCloudSDKException { return ISmsService.sendLoginVeryCodeMessage(phone); }}Service
public interface ISmsService { public SendSmsResponse sendLoginVeryCodeMessage(String phone) throws TencentCloudSDKException; }impl
只需要在实现类中调用封装好的sms业务代码即可!
@Servicepublic class SmsServiceImpl implements ISmsService { @Autowired private Message message; public SendSmsResponse sendLoginVeryCodeMessage(String phone) throws TencentCloudSDKException { return message.smsClient(phone); }}验证码校验
此时此刻,已经通过前端页面请求获取到验证码,并且填写至表单中,提交的时候需要对当前的提交的验证码进行校验。之前发送验证码的时候,已经把验证码的内容保存到了redis中;此时只需要把redis缓存中的数据取出来,提交信息中的电话号码为redis的key,根据这个key获取对应的验证码,比对和提交的验证码是否一致即可!
@PostMappingpublic AjaxResult add(@RequestBody MerApply merApply) { // 获取提交的手机号码 String smsCode = Constants.SMS_CODE_KEY + merApply.getPhone(); // 根据手机号码获取redis缓存中的value String code = redisCache.getCacheObject(smsCode); if (code == null) { return error("验证码已失效"); } if (!merApply.getCode().equals(code)) { return error("验证码校验不通过"); } merApply.setCreateBy(getUsername()); return toAjax(this.merApplyService.insert(merApply));}案例
去往案例地址>>>
作者:Lakeiedward
链接:
标签: #腾讯云sms服务