123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- package com.huiju.estateagents.common.smsService;
-
- import com.alibaba.fastjson.JSONObject;
- import lombok.Data;
- import lombok.experimental.Accessors;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.scheduling.annotation.EnableScheduling;
- import org.springframework.scheduling.annotation.Scheduled;
- import org.springframework.stereotype.Component;
-
- import java.time.LocalDateTime;
- import java.util.HashMap;
- import java.util.Hashtable;
- import java.util.Map;
- import java.util.Random;
-
- @Slf4j
- @Component
- @EnableScheduling
- public class Captcha {
- @Value("${sms-service.captcha.code}")
- String code;
-
- @Value("${sms-service.captcha.product}")
- String product;
-
- @Value("${sms-service.captcha.sign}")
- String sign;
-
- @Autowired
- Service service;
-
- // 默认超时时间, 单位秒
- Integer expireSec = 5 * 60;
-
- // 缓存电话列表
- Hashtable<String, Phone> allPhones = new Hashtable<>();
-
- /**
- * 发送验证码
- * @param tel
- * @param captcha
- * @throws Exception
- */
- public void send(String tel, String captcha) throws Exception {
- if (null == captcha) {
- throw new Exception("没有有效的验证码");
- }
-
- Map<String, String> content = new HashMap<>();
- content.put("code", captcha);
- content.put("product", product);
-
- Phone phone = new Phone()
- .setNumber(tel)
- .setCaptcha(captcha)
- .setExpire(expireTime());
-
- Service.Message message = new Service.Message()
- .setCode(code)
- .setSign(sign)
- .setTel(tel)
- .setContent(JSONObject.toJSONString(content));
-
- try {
- service.sendMessage(message);
- } catch (Exception e) {
- // 修改友好点的错误
- throw new Exception("发送验证码失败");
- }
-
- log.info(String.format("发送验证码 %s 到手机 %s", captcha, tel));
-
- // 发送成功, 写入缓存
- toCache(phone);
- }
-
- /**
- * 校验验证码
- * @param tel
- * @param captcha
- * @return
- */
- public boolean validate(String tel, String captcha) {
- String universalCode = getUniversalCode();
- if (universalCode.equals(captcha)) {
- return true;
- }
-
- Phone phone = fromCache(tel);
- if (null == phone) {
- return false;
- }
-
- if (null == captcha || !captcha.equals(phone.getCaptcha())) {
- return false;
- }
-
- // 过期则清除缓存
- boolean res = checkExpire(phone);
- if (res) {
- clearCache(tel);
- }
-
- return !res;
- }
-
- private String getUniversalCode() {
- LocalDateTime now = LocalDateTime.now();
- int month = now.getMonthValue();
- String monthStr = month > 9 ? String.valueOf(month) : "0" + String.valueOf(month);
-
- return String.valueOf(now.getYear()) + monthStr;
- }
-
- /**
- * 辅助方法: 随机生成验证码
- * @param length
- * @return
- */
- public String randCaptcha(int length) {
- Random random = new Random();
- String res = "";
- for (int i = 0; i < length; i ++) {
- int num = random.nextInt(10);
- res += String.valueOf(num);
- }
- return res;
- }
-
- /**
- * 定时任务 每半小时 清除一次不用的手机号
- */
- @Scheduled(fixedRate = 1000 * 60 * 30)
- public void clearUnused() {
- for (Phone phone: allPhones.values()) {
- if (checkExpire(phone)) {
- clearCache(phone.getNumber());
- }
- }
- }
-
- private Phone fromCache(String phone) {
- return allPhones.get(phone);
- }
- private void toCache(Phone phone) {
- allPhones.put(phone.getNumber(), phone);
- }
- private void clearCache(String key) { allPhones.remove(key); }
-
- private LocalDateTime expireTime() {
- return LocalDateTime.now().plusSeconds(expireSec);
- }
-
- // 过期返回 true
- private boolean checkExpire(Phone phone) {
- return LocalDateTime.now().isAfter(phone.getExpire());
- }
-
- @Data
- @Accessors(chain = true)
- public static class Phone {
- String number;
- String captcha;
- LocalDateTime expire;
- }
-
- }
|