Blog接入腾讯云短信

2022-10-27 17:00:10 浏览数 (1)

这个网站搭建也快有两年了,这两年虽然没有什么产出,但是经过两年的积累也算是收益颇丰。因为一开始只是打算用来做一些笔记,并没有考虑网站本身的交互性,评论几乎都是置之不理,前几天突然心血来潮查了一下评论表,居然收获了上百条的评论,然而这些评论中的绝大多数我都是第一次见,其中不乏一些加油以及对知识点提出疑问的评论,我要在这里向留下评论的你们表示感谢。但是光是感谢是不够的,我要提高网站的交互性,对于这些评论我要第一时间知道,如何第一时间知道?想必脑海中冒出来的第一个念头就是短信了吧,打开腾讯云搜索短信,我又打开了一片新世界。

腾讯云短信平台

短信签名和短信模板被驳回了2次。。。我也是醉了,不过结果还好审核通过了,并发现了一个小惊喜,腾讯云个人认证账户每个月可以白嫖100条的免费短信,very good.点开开发者指南去学习如何引入SDK发短信就好啦,中文的文档不会还有人看不懂吧,不会吧不会吧。。

引入SDK 腾讯云短信接入文档 我把文档看完了,在这里做个小总结,首先你需要把SDK的依赖引入到工程的POM中,想要发短信的话还需要实例化一个认证对象,入参需要传入腾讯云账户密钥对 secretId 和 secretKey: 还需要实例化一个发短信的客户端:

最后还需要将短信的详细信息封装到一个对象中

最后使用短信客户端把短信的详细信息发送出去就好了吧,就这样**client.SendSms(req)**嗖的一下就发出去了。

引入依赖

代码语言:javascript复制
<!-- https://mvnrepository.com/artifact/com.tencentcloudapi/tencentcloud-sdk-java -->
<dependency>
	<groupId>com.tencentcloudapi</groupId>
	<artifactId>tencentcloud-sdk-java</artifactId>
	<version>4.0.11</version>
</dependency>

创建对象

emm,认证对象只要传入两个固定的参数就好啦非常ESAY,所以就把他交给Spring管理就好啦,这个客户端对象一个系统也有一个就可以啦,那就单例模式搞一个,emm~~短信对象创建起来有点复杂,而且要根据不同的评论进行定制,所以工厂模式安排!

注入IOC容器
代码语言:javascript复制
package com.jmy.config;

import com.jmy.factory.SmsClientBeanFactory;
import com.jmy.util.SmsUtils;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.sms.v20190711.SmsClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SmsConfig {

    @Bean
    public Credential credential(){
        return new Credential(SmsUtils.SECRETID, SmsUtils.SECRETKEY);
    }

    @Bean
    public SmsClient smsClient(Credential credential){
        return SmsClientBeanFactory.getSmsClientInstance(credential);
    }

}

单例模式创建SmsClient
代码语言:javascript复制
package com.jmy.config;

import com.jmy.factory.SmsClientBeanFactory;
import com.jmy.util.SmsUtils;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.sms.v20190711.SmsClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SmsConfig {

    @Bean
    public Credential credential(){
        return new Credential(SmsUtils.SECRETID, SmsUtils.SECRETKEY);
    }

    @Bean
    public SmsClient smsClient(Credential credential){
        return SmsClientBeanFactory.getSmsClientInstance(credential);
    }

}
工厂模式创建SendSmsRequestBeanFactory
代码语言:javascript复制
package com.jmy.factory;

import com.jmy.util.SmsUtils;
import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest;

public class SendSmsRequestBeanFactory{

    public static SendSmsRequest getInstance() {
        SendSmsRequest req = new SendSmsRequest();
        req.setSmsSdkAppid(SmsUtils.APPID);
        req.setSign(SmsUtils.SIGN);
        req.setSenderId(SmsUtils.SENDERID);
        req.setTemplateID(SmsUtils.TEMPLATEID);
        req.setPhoneNumberSet(SmsUtils.PHONENUMBERS);
        return req;
    }
}

编写切面接入短信功能

评论发送短信通知博主,这功能一听就是与评论业务无关只是对评论功能单纯的一个增强,这不正是面向切面编程的意义所在吗?心动不如行动,还在有犹豫什么呢,快去编写发送短信的切面吧。

后置通知发送短信

代码语言:javascript复制
/**
 * Created by jmy on 2021/4/29.
 */

@Aspect
@Component
public class SmsAspect {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private SmsClient smsClient;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Pointcut("@annotation(com.jmy.aspect.SendMessage)")
    public void sendMessage(){}

    @After("sendMessage()")
    public void doAfter(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        Comment comment = (Comment) args[];

        // 发送短信
        SendSmsRequest req = SendSmsRequestBeanFactory.getInstance();
        /* 模板参数: 若无模板参数,则设置为空*/
        String title = comment.getBlog().getTitle();
        String[] templateParams = {title.length() >  ? title.substring(,):title};
        req.setTemplateParamSet(templateParams);
        HttpServletRequest request = RepeatCommentInterceptor.threadLocal.get();
        String tll = RepeatCommentInterceptor.TLL.get();
        String remoteAddr = request.getRemoteAddr();
        new Thread(() -> {
            try {
                String boo = redisTemplate.opsForValue().get("comment:ip:"   remoteAddr);
                if (!StringUtils.isEmpty(boo) && tll.equals(boo)) {
                    smsClient.SendSms(req);
                }
            } catch (TencentCloudSDKException e) {
                logger.error(e.getMessage());
            }
        }).start();

    }
}

切面写好了怎么通知到我们的评论功能呢?当然是按照我们编写好的切入规则@Pointcut(“@annotation(com.jmy.aspect.SendMessage)”),在评论的方法上加上我们自定义的SendMessage注解就好啦。

不讲武德,耗子尾汁

短信通知的功能倒是实现啦,但是我眉头一紧突然意识到一个严重的问题,如果有不讲武德的小伙子刷评论我这白嫖的100条短信不是很快就没了吗,所以要小小的改造一下加个拦截器将请求的IP地址放到Redis中保存一小段时间用来校验是否刷评论就可以了,如何在拦截器中注入Spring管理的对象以及如何在切面中如何使用Request对象,这些都是不可忽视的小细节哦.

代码语言:javascript复制
/**
 * Created by jmy on 2021/4/30.
 * 重复评论短信拦截器
 */

public class RepeatCommentInterceptor implements HandlerInterceptor {

    public static ThreadLocal<HttpServletRequest> threadLocal = new ThreadLocal<>();
    public static ThreadLocal<String> TLL = new ThreadLocal<>();
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        threadLocal.set(httpServletRequest);
        String remoteAddr = httpServletRequest.getRemoteAddr();
        String tll = UUID.randomUUID().toString();
        TLL.set(tll);
        redisTemplate.opsForValue().setIfAbsent("comment:ip:"   remoteAddr, tll);
        redisTemplate.expire("comment:ip:"   remoteAddr,,TimeUnit.MINUTES);
        return true;
    }
代码语言:javascript复制
/**
 * Created by jmy on 2021/4/30.
 */
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Bean
    public RepeatCommentInterceptor repeatCommentInterceptor(){
        return new RepeatCommentInterceptor();
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/admin/**")
                .excludePathPatterns("/admin")
                .excludePathPatterns("/admin/login");

        registry.addInterceptor(repeatCommentInterceptor())
                .addPathPatterns("/comments");
    }
}

0 人点赞