Quellcode durchsuchen

1.重构短信发送模块代码
2.新加获取试卷结构接口
3.添加多学号支持
4.违纪列表添加学习中心字段
5.添加获取试卷结构信息的RPC接口

lideyin vor 6 Jahren
Ursprung
Commit
ca16ac3a86

+ 8 - 4
examcloud-exchange-inner-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/inner/api/provider/SendSmsProvider.java

@@ -1,3 +1,4 @@
+/*
 package cn.com.qmth.examcloud.exchange.inner.api.provider;
 
 import org.apache.commons.lang3.StringUtils;
@@ -15,7 +16,7 @@ import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.exchange.inner.api.SendSmsCloudService;
 import cn.com.qmth.examcloud.exchange.inner.api.request.CaptureFailedAlarmReq;
 import cn.com.qmth.examcloud.exchange.inner.api.request.CheckSmsCodeReq;
-import cn.com.qmth.examcloud.exchange.inner.api.request.SendSmsReq;
+import cn.com.qmth.examcloud.exchange.inner.api.request.SendSmsReq1;
 import cn.com.qmth.examcloud.exchange.inner.api.response.CheckIdentifyingCodeResp;
 import cn.com.qmth.examcloud.exchange.inner.api.response.SendSmsResp;
 import cn.com.qmth.examcloud.exchange.inner.service.SendSmsService;
@@ -23,13 +24,15 @@ import cn.com.qmth.examcloud.exchange.inner.service.bean.CaptureFailedAlarmInfo;
 import cn.com.qmth.examcloud.exchange.inner.service.bean.SendSmsInfo;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
 
+*/
 /**
  * 
  * @author chenken
  * @date 2018年7月3日 下午4:03:59
  * @company QMTH
  * @description SendSmsProvider.java
- */
+ *//*
+
 @RestController
 @RequestMapping("${$rmp.cloud.exchange.inner}" + "/sendSms")
 public class SendSmsProvider extends ControllerSupport implements SendSmsCloudService {
@@ -41,7 +44,7 @@ public class SendSmsProvider extends ControllerSupport implements SendSmsCloudSe
 
 	@Override
 	@RequestMapping(method = RequestMethod.POST, value = "/sendIdentifyingCode")
-	public SendSmsResp sendIdentifyingCode(@RequestBody SendSmsReq sendSmsReq){
+	public SendSmsResp sendIdentifyingCode(@RequestBody SendSmsReq1 sendSmsReq){
 		checkSendSmsReq(sendSmsReq);
 		SendSmsInfo sendSmsInfo = new SendSmsInfo();
 		sendSmsInfo.setPhone(sendSmsReq.getPhone());
@@ -79,7 +82,7 @@ public class SendSmsProvider extends ControllerSupport implements SendSmsCloudSe
 		return resp;
 	}
 
-	private void checkSendSmsReq(SendSmsReq sendSmsReq){
+	private void checkSendSmsReq(SendSmsReq1 sendSmsReq){
 		if(StringUtils.isBlank(sendSmsReq.getPhone())){
 			throw new StatusException("SendSmsProvider-001", "手机号码不能为空");
 		}
@@ -123,3 +126,4 @@ public class SendSmsProvider extends ControllerSupport implements SendSmsCloudSe
 	}
 	
 }
+*/

+ 99 - 0
examcloud-exchange-inner-api-provider/src/main/java/cn/com/qmth/examcloud/exchange/inner/api/provider/SmsProvider.java

@@ -0,0 +1,99 @@
+package cn.com.qmth.examcloud.exchange.inner.api.provider;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.exchange.inner.api.SmsCloudService;
+import cn.com.qmth.examcloud.exchange.inner.api.request.CaptureFailedAlarmReq;
+import cn.com.qmth.examcloud.exchange.inner.api.request.CheckSmsCodeReq;
+import cn.com.qmth.examcloud.exchange.inner.api.request.SendSmsCodeReq;
+import cn.com.qmth.examcloud.exchange.inner.api.request.SendSmsReq;
+import cn.com.qmth.examcloud.exchange.inner.api.response.CheckIdentifyingCodeResp;
+import cn.com.qmth.examcloud.exchange.inner.api.response.SendSmsCodeResp;
+import cn.com.qmth.examcloud.exchange.inner.api.response.SendSmsResp;
+import cn.com.qmth.examcloud.exchange.inner.service.SmsService;
+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.support.ControllerSupport;
+import io.swagger.annotations.ApiParam;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 短信发送
+ */
+@RestController
+@RequestMapping("${$rmp.cloud.exchange.inner}" + "/sms")
+public class SmsProvider extends ControllerSupport implements SmsCloudService {
+
+    private static final long serialVersionUID = -1497756895732370672L;
+
+    @Autowired
+    private SmsService smsService;
+
+    @Override
+    @RequestMapping(method = RequestMethod.POST, value = "/sendSms")
+    public SendSmsResp sendSms(@RequestBody @Valid @ApiParam(required = true) SendSmsReq req) {
+        String smsAssemblyCode = req.getSmsAssemblyCode();
+        List<String> phoneList = req.getPhoneList();
+        Map<String, String> params = req.getParams();
+
+        //获取短信配置信息
+        SmsAssemblyCacheBean assemblyCacheBean = CacheHelper.getSmsAssembly(smsAssemblyCode);
+
+        boolean virtualEnable = PropertyHolder.getBoolean("sms.virtual.enable",
+                false);
+
+        if (!virtualEnable) {
+            try {
+                smsService.sendSms(assemblyCacheBean, phoneList, params);
+            } catch (Exception e) {
+                // ignore
+            }
+        }
+
+        SendSmsResp resp = new SendSmsResp();
+        return resp;
+    }
+
+    @Override
+    @RequestMapping(method = RequestMethod.POST, value = "/sendIdentifyingCode")
+    public SendSmsCodeResp sendIdentifyingCode(@RequestBody @Valid @ApiParam(required = true) SendSmsCodeReq req) {
+
+        SendSmsCodeResp sendSmsResp = new SendSmsCodeResp();
+        try {
+            smsService.sendSmsSecurityCode(req.getPhone(), req.getCode());
+            sendSmsResp.setSuccess(true);
+            sendSmsResp.setReturnMsg("发送成功");
+        } catch (StatusException exception) {
+            exception.printStackTrace();
+            sendSmsResp.setSuccess(false);
+            sendSmsResp.setReturnMsg(exception.getDesc());
+        }
+        return sendSmsResp;
+    }
+
+    @Override
+    @RequestMapping(method = RequestMethod.POST, value = "/checkIdentifyingCode")
+    public CheckIdentifyingCodeResp checkIdentifyingCode(@RequestBody @Valid @ApiParam(required = true) CheckSmsCodeReq req) {
+        CheckIdentifyingCodeResp resp = new CheckIdentifyingCodeResp();
+        try {
+            smsService.validateSmsSecurityCode(req.getPhone(), req.getCode());
+            resp.setSuccess(true);
+            resp.setReturnMsg("校验成功");
+        } catch (StatusException exception) {
+            exception.printStackTrace();
+            resp.setSuccess(false);
+            resp.setReturnMsg(exception.getDesc());
+        }
+        return resp;
+    }
+
+}

+ 38 - 0
examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/SmsService.java

@@ -0,0 +1,38 @@
+package cn.com.qmth.examcloud.exchange.inner.service;
+
+import cn.com.qmth.examcloud.support.cache.bean.SmsAssemblyCacheBean;
+
+import java.util.List;
+import java.util.Map;
+
+public interface SmsService {
+    /**
+     * 验证码配置代码
+     */
+    String YZM_SMS_ASSEMBLY_CODE="YZM";
+
+    /**
+     * 发送短信
+     *
+     * @param smsAssembly
+     * @param phoneList
+     * @param params
+     */
+    void sendSms(SmsAssemblyCacheBean smsAssembly, List<String> phoneList, Map<String, String> params);
+
+    /**
+     * 发送短信验证码
+     *
+     * @param phone 手机号
+     * @param code 验证码
+     */
+    void sendSmsSecurityCode(String phone, String code);
+
+    /**
+     * 校验短信验证码
+     *
+     * @param phone 手机号
+     * @param code 验证码
+     */
+    void validateSmsSecurityCode(String phone, String code);
+}

+ 78 - 0
examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/bean/ShortMessageInfo.java

@@ -0,0 +1,78 @@
+package cn.com.qmth.examcloud.exchange.inner.service.bean;
+
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public class ShortMessageInfo implements Serializable {
+
+	private static final long serialVersionUID = 6234229280391013286L;
+
+	/**
+	 * 接受短信的手机号
+	 */
+	private String phone;
+
+	/**
+	 * 发送次数
+	 */
+	private Integer times;
+
+	/**
+	 * 最后一次消息
+	 */
+	private String lastMessage;
+
+	/**
+	 * 发送时间
+	 */
+	private List<Date> sendTimeList = new ArrayList<Date>();
+
+	/**
+	 * 创建时间
+	 */
+	private Date creationTime;
+
+	public String getPhone() {
+		return phone;
+	}
+
+	public void setPhone(String phone) {
+		this.phone = phone;
+	}
+
+	public Integer getTimes() {
+		return times;
+	}
+
+	public void setTimes(Integer times) {
+		this.times = times;
+	}
+
+	public String getLastMessage() {
+		return lastMessage;
+	}
+
+	public void setLastMessage(String lastMessage) {
+		this.lastMessage = lastMessage;
+	}
+
+	public List<Date> getSendTimeList() {
+		return sendTimeList;
+	}
+
+	public void setSendTimeList(List<Date> sendTimeList) {
+		this.sendTimeList = sendTimeList;
+	}
+
+	public Date getCreationTime() {
+		return creationTime;
+	}
+
+	public void setCreationTime(Date creationTime) {
+		this.creationTime = creationTime;
+	}
+
+}

+ 273 - 0
examcloud-exchange-inner-service/src/main/java/cn/com/qmth/examcloud/exchange/inner/service/impl/AliyunSmsServiceImpl.java

@@ -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;
+    }
+}