|
@@ -0,0 +1,273 @@
|
|
|
+package cn.com.qmth.examcloud.exchange.inner.service.impl;
|
|
|
+
|
|
|
+import cn.com.qmth.examcloud.commons.exception.StatusException;
|
|
|
+import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
|
|
|
+import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
|
|
|
+import cn.com.qmth.examcloud.commons.util.DateUtil;
|
|
|
+import cn.com.qmth.examcloud.commons.util.JsonUtil;
|
|
|
+import cn.com.qmth.examcloud.commons.util.UUID;
|
|
|
+import cn.com.qmth.examcloud.exchange.inner.service.SmsService;
|
|
|
+import cn.com.qmth.examcloud.exchange.inner.service.bean.ShortMessageInfo;
|
|
|
+import cn.com.qmth.examcloud.support.cache.CacheHelper;
|
|
|
+import cn.com.qmth.examcloud.support.cache.bean.SmsAssemblyCacheBean;
|
|
|
+import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
|
|
|
+import cn.com.qmth.examcloud.web.redis.RedisClient;
|
|
|
+import com.aliyuncs.CommonRequest;
|
|
|
+import com.aliyuncs.CommonResponse;
|
|
|
+import com.aliyuncs.DefaultAcsClient;
|
|
|
+import com.aliyuncs.IAcsClient;
|
|
|
+import com.aliyuncs.http.MethodType;
|
|
|
+import com.aliyuncs.http.ProtocolType;
|
|
|
+import com.aliyuncs.profile.DefaultProfile;
|
|
|
+import com.google.common.collect.Maps;
|
|
|
+import com.google.gson.JsonObject;
|
|
|
+import com.google.gson.JsonParser;
|
|
|
+import org.apache.tomcat.util.buf.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * {@link StatusException} 状态码范围:101XXX<br>
|
|
|
+ * <p>
|
|
|
+ * 阿里云短信服务
|
|
|
+ *
|
|
|
+ * @author WANGWEI
|
|
|
+ * @date 2019年3月27日
|
|
|
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class AliyunSmsServiceImpl implements SmsService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ RedisClient redisClient;
|
|
|
+ /**
|
|
|
+ * controller 统一业务日志对象
|
|
|
+ */
|
|
|
+ protected ExamCloudLog log = ExamCloudLogFactory.getLog(this.getClass());
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void sendSms(SmsAssemblyCacheBean smsAssembly, List<String> phoneList,
|
|
|
+ Map<String, String> params) {
|
|
|
+
|
|
|
+ execute(smsAssembly, "SendSms", phoneList, params);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void sendSmsSecurityCode(String phone, String code) {
|
|
|
+ {
|
|
|
+
|
|
|
+ boolean virtualEnable = PropertyHolder
|
|
|
+ .getBoolean("sms.securityCode.virtual.enable", false);
|
|
|
+
|
|
|
+ if (virtualEnable) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ String key = "$_SMS:" + phone;
|
|
|
+ ShortMessageInfo sm = redisClient.get(key, ShortMessageInfo.class);
|
|
|
+ if (null != sm) {
|
|
|
+ Date creationTime = sm.getCreationTime();
|
|
|
+ boolean sameDay = DateUtil.isSameDay(creationTime, new Date());
|
|
|
+ if (!sameDay) {
|
|
|
+ sm = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Date now = new Date();
|
|
|
+
|
|
|
+ if (null == sm) {
|
|
|
+ sm = new ShortMessageInfo();
|
|
|
+ sm.setCreationTime(now);
|
|
|
+ sm.setPhone(phone);
|
|
|
+ sm.setTimes(0);
|
|
|
+ } else {
|
|
|
+ List<Date> sendTimeList = sm.getSendTimeList();
|
|
|
+
|
|
|
+ if (10 <= sendTimeList.size()) {
|
|
|
+ throw new StatusException("102000", "一天内发送次数超过10次");
|
|
|
+ } else if (5 <= sendTimeList.size()) {
|
|
|
+ Date d = sendTimeList.get(sendTimeList.size() - 5);
|
|
|
+ if (now.getTime() - d.getTime() < 1000 * 60 * 60) {
|
|
|
+ throw new StatusException("102000", "一小时内发送次数超过5次");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ Date d = sendTimeList.get(sendTimeList.size() - 1);
|
|
|
+ if (now.getTime() - d.getTime() < 1000 * 60) {
|
|
|
+ throw new StatusException("102000", "一分钟内发送次数超过1次");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取短信配置信息
|
|
|
+ SmsAssemblyCacheBean assemblyCacheBean = CacheHelper.getSmsAssembly(YZM_SMS_ASSEMBLY_CODE);
|
|
|
+ Map<String, String> params = Maps.newHashMap();
|
|
|
+ params.put("code", code);
|
|
|
+ this.sendSms(assemblyCacheBean, Arrays.asList(new String[]{phone}), params);
|
|
|
+
|
|
|
+ sm.getSendTimeList().add(now);
|
|
|
+ sm.setTimes(sm.getSendTimeList().size());
|
|
|
+ sm.setLastMessage(code);
|
|
|
+
|
|
|
+ redisClient.set(key, sm, 60 * 60 * 24);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void validateSmsSecurityCode(String phone, String code) {
|
|
|
+ {
|
|
|
+
|
|
|
+ boolean virtualEnable = PropertyHolder
|
|
|
+ .getBoolean("sms.securityCode.virtual.enable", false);
|
|
|
+
|
|
|
+ if (virtualEnable) {
|
|
|
+ String virtualCode = PropertyHolder
|
|
|
+ .getString("sms.securityCode.virtual.code", "5220");
|
|
|
+ if (!virtualCode.equals(code)) {
|
|
|
+ throw new StatusException("102008", "验证码错误");
|
|
|
+ } else {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ String key = "$_SMS:" + phone;
|
|
|
+ ShortMessageInfo sm = redisClient.get(key, ShortMessageInfo.class);
|
|
|
+
|
|
|
+ if (null == sm) {
|
|
|
+ throw new StatusException("102001", "未发送验证码");
|
|
|
+ }
|
|
|
+ List<Date> sendTimeList = sm.getSendTimeList();
|
|
|
+ Date date = sendTimeList.get(sendTimeList.size() - 1);
|
|
|
+ Date now = new Date();
|
|
|
+
|
|
|
+ if (now.getTime() - date.getTime() > 1000 * 60 * 5) {
|
|
|
+ throw new StatusException("102002", "验证码过期");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!sm.getLastMessage().equals(code)) {
|
|
|
+ throw new StatusException("102003", "验证码错误");
|
|
|
+ } else {
|
|
|
+ sm.setLastMessage(UUID.randomUUID());
|
|
|
+ redisClient.set(key, sm);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行
|
|
|
+ *
|
|
|
+ * @param smsAssembly
|
|
|
+ * @param action
|
|
|
+ * @param phoneList
|
|
|
+ * @param templateParams 短信模板参数
|
|
|
+ * @author WANGWEI
|
|
|
+ */
|
|
|
+ private void execute(SmsAssemblyCacheBean smsAssembly, String action, List<String> phoneList,
|
|
|
+ Map<String, String> templateParams) {
|
|
|
+ String accessKeyId = PropertyHolder.getString("aliyun.sms.accessKeyId");
|
|
|
+ String accessSecret = PropertyHolder.getString("aliyun.sms.accessKeySecret");
|
|
|
+ String signName = smsAssembly.getExt1();
|
|
|
+ String templateCode = smsAssembly.getExt2();
|
|
|
+
|
|
|
+ DefaultProfile profile = DefaultProfile.getProfile("default", accessKeyId, accessSecret);
|
|
|
+ IAcsClient client = new DefaultAcsClient(profile);
|
|
|
+
|
|
|
+ CommonRequest request = new CommonRequest();
|
|
|
+ request.setProtocol(ProtocolType.HTTPS);
|
|
|
+ request.setMethod(MethodType.POST);
|
|
|
+ request.setDomain("dysmsapi.aliyuncs.com");
|
|
|
+ request.setVersion("2017-05-25");
|
|
|
+ request.setAction(action);
|
|
|
+ String phoneNumbers = StringUtils.join(phoneList, ',');
|
|
|
+ request.putQueryParameter("PhoneNumbers", phoneNumbers);
|
|
|
+ request.putQueryParameter("SignName", signName);
|
|
|
+ request.putQueryParameter("TemplateCode", templateCode);
|
|
|
+ request.putQueryParameter("TemplateParam", JsonUtil.toJson(templateParams));
|
|
|
+ try {
|
|
|
+ CommonResponse response = client.getCommonResponse(request);
|
|
|
+ String data = response.getData();
|
|
|
+ JsonParser jp = new JsonParser();
|
|
|
+ JsonObject jsonObj = jp.parse(data).getAsJsonObject();
|
|
|
+ String code = jsonObj.get("Code").getAsString();
|
|
|
+
|
|
|
+ if (!code.equals("OK")) {
|
|
|
+ log.error("aliyun sms response: " + JsonUtil.toJson(response));
|
|
|
+ throw new StatusException("101001", "短信发送失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (StatusException e) {
|
|
|
+ throw e;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("fail to send SMS", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void main(String[] args) {
|
|
|
+ List<UserInfo> userList = new ArrayList<>();
|
|
|
+ userList.add(new UserInfo(3,"33",4));
|
|
|
+ userList.add(new UserInfo(1,"1111",6));
|
|
|
+ userList.add(new UserInfo(5,"555",0));
|
|
|
+ userList.add(new UserInfo(2,"32",8));
|
|
|
+ System.out.println("group by 之前:");
|
|
|
+ userList.forEach(u->{
|
|
|
+ System.out.println("源:u.id="+u.getId()+",u.name="+u.getName()+",u.num="+u.getNum());
|
|
|
+ });
|
|
|
+ System.out.println("group by 之后,且使用HashMap:");
|
|
|
+ Map<String, List<UserInfo>> newUserList = userList.stream().collect(Collectors.groupingBy(UserInfo::getName));
|
|
|
+ newUserList.keySet().forEach(key->{
|
|
|
+ List<UserInfo> userInfos = newUserList.get(key);
|
|
|
+ userInfos.forEach(u->{
|
|
|
+ System.out.println("HashMapLu.id="+u.getId()+",u.name="+u.getName()+",u.num="+u.getNum());
|
|
|
+ });
|
|
|
+ });
|
|
|
+ System.out.println("group by 之后,改为使用LinkedHashMap:");
|
|
|
+ LinkedHashMap<String, List<UserInfo>> newUserList2 = userList.stream().collect(Collectors.groupingBy(UserInfo::getName, LinkedHashMap::new, Collectors.toList()));
|
|
|
+ newUserList2.keySet().forEach(key->{
|
|
|
+ List<UserInfo> userInfos = newUserList2.get(key);
|
|
|
+ userInfos.forEach(u->{
|
|
|
+ System.out.println("LinkedHashMap:u.id="+u.getId()+",u.name="+u.getName()+",u.num="+u.getNum());
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class UserInfo {
|
|
|
+ private int num;
|
|
|
+ private int id;
|
|
|
+ private String name;
|
|
|
+
|
|
|
+ public UserInfo(int id, String name,int num) {
|
|
|
+ this.num=num;
|
|
|
+ this.id = id;
|
|
|
+ this.name = name;
|
|
|
+ }
|
|
|
+
|
|
|
+ public UserInfo(int id) {
|
|
|
+ this.id = id;
|
|
|
+ }
|
|
|
+
|
|
|
+ public int getId() {
|
|
|
+ return id;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setId(int id) {
|
|
|
+ this.id = id;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getName() {
|
|
|
+ return name;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setName(String name) {
|
|
|
+ this.name = name;
|
|
|
+ }
|
|
|
+
|
|
|
+ public int getNum() {
|
|
|
+ return num;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setNum(int num) {
|
|
|
+ this.num = num;
|
|
|
+ }
|
|
|
+}
|