|
|
package com.yoho.yhmessage.wechat.service.impl;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.google.common.util.concurrent.RateLimiter;
|
|
|
import com.yoho.core.common.utils.DateUtil;
|
|
|
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
|
|
|
import com.yoho.error.exception.ServiceException;
|
|
|
import com.yoho.service.model.msgcenter.wechat.McWechatBO;
|
|
|
import com.yoho.service.model.msgcenter.wechat.WechatCustomMsgBO;
|
|
|
import com.yoho.yhmessage.constants.RedisCacheKeyConstant;
|
|
|
import com.yoho.yhmessage.redis.PushRedisService;
|
|
|
import com.yoho.yhmessage.wechat.common.Consts;
|
|
|
import com.yoho.yhmessage.wechat.service.IWechatService;
|
|
|
import com.yoho.yhmessage.wechat.service.IWeixinAccessTokenService;
|
...
|
...
|
@@ -13,6 +19,12 @@ import org.slf4j.Logger; |
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.apache.commons.collections.CollectionUtils;
|
|
|
import retrofit2.http.PUT;
|
|
|
|
|
|
import javax.print.DocFlavor;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
import java.util.*;
|
|
|
|
|
|
/**
|
|
|
*
|
...
|
...
|
@@ -38,6 +50,16 @@ public class WechatServiceImpl implements IWechatService { |
|
|
@Autowired
|
|
|
private SendWechatRequest sendWechatRequest;
|
|
|
|
|
|
@Autowired
|
|
|
private PushRedisService pushRedisService;
|
|
|
|
|
|
private static final String DATE_ID_FORMAT = "yyyyMMdd";
|
|
|
|
|
|
//1s放10个令牌 100ms频率
|
|
|
private static final RateLimiter rateLimiter = RateLimiter.create(10);
|
|
|
|
|
|
private static final int SEVEN_DAY_HOURS = 168;
|
|
|
|
|
|
@Override
|
|
|
public void sendWechatMsg(McWechatBO wechatBO) throws ServiceException {
|
|
|
logger.info("begin sendTemplateMsg param {}", wechatBO);
|
...
|
...
|
@@ -54,7 +76,7 @@ public class WechatServiceImpl implements IWechatService { |
|
|
logger.warn("sendWechatMsg with accessToken is null, publicCode is {},wechatBO is {}",wechatBO.getPublicNumberCode(),wechatBO);
|
|
|
return;
|
|
|
}
|
|
|
String templateUrl = this.getTemplateUrl(accessToken);
|
|
|
String templateUrl = this.getTemplateUrl(accessToken,Consts.SEND_TEMPLATE_URL);
|
|
|
//针对需要展示微信用户昵称的消息,在这里调用微信api查询一把并替换,避免在其他服务调用微信api的复杂行,微信用户昵称统一用${wechatNickname}表示
|
|
|
String data = this.addUserNickname(wechatBO, accessToken);
|
|
|
// 获取请求参数
|
...
|
...
|
@@ -69,7 +91,7 @@ public class WechatServiceImpl implements IWechatService { |
|
|
logger.warn("send wechat template message error, e is {}", JSONObject.toJSONString(result) );
|
|
|
// 重新调接口获取access token
|
|
|
AccessToken accessTokenNew = weixinAccessTokenService.getAccessTokenFromUrl(wechatBO.getPublicNumberCode());
|
|
|
templateUrl = this.getTemplateUrl(accessTokenNew);
|
|
|
templateUrl = this.getTemplateUrl(accessTokenNew,Consts.SEND_TEMPLATE_URL);
|
|
|
result = sendWechatRequest.sendWechatRequest(wechatBO.getPublicNumberCode(), templateUrl, "POST", sendMsg.toJSONString());
|
|
|
}
|
|
|
sendWechatMsgLog.info("send wechat template message {},result {}, templateUrl is {}", sendMsg.toJSONString(), result, templateUrl);
|
...
|
...
|
@@ -103,12 +125,12 @@ public class WechatServiceImpl implements IWechatService { |
|
|
* @taskId <br>
|
|
|
* @return <br>
|
|
|
*/
|
|
|
private String getTemplateUrl(AccessToken accessToken) {
|
|
|
private String getTemplateUrl(AccessToken accessToken,String url) {
|
|
|
if (null == accessToken) {
|
|
|
return null;
|
|
|
}
|
|
|
logger.info("accessToken is {}", accessToken.getToken());
|
|
|
StringBuffer templateUrl = new StringBuffer(Consts.SEND_TEMPLATE_URL);
|
|
|
StringBuffer templateUrl = new StringBuffer(url);
|
|
|
templateUrl.append(accessToken.getToken());
|
|
|
return templateUrl.toString();
|
|
|
}
|
...
|
...
|
@@ -116,4 +138,80 @@ public class WechatServiceImpl implements IWechatService { |
|
|
private String getQueryUserUrl(String openId, AccessToken accessToken) {
|
|
|
return Consts.QUERY_USER_INFO_URL.replace("ACCESS_TOKEN", accessToken.getToken()).replace("OPENID", openId);
|
|
|
}
|
|
|
|
|
|
|
|
|
@Override
|
|
|
public void sendWechatCustomMsg(WechatCustomMsgBO customMsgBO) throws ServiceException{
|
|
|
logger.info("enter sendWechatCustomMsg with sceneKey is {},msgBO is {}",customMsgBO.getSendKey(),customMsgBO.getSendContent());
|
|
|
|
|
|
if(CollectionUtils.isEmpty(customMsgBO.getOpenIdSet())){
|
|
|
logger.warn("sendWechatCustomMsg with sendOpenIds null, sceneKey is {}",customMsgBO.getSendKey());
|
|
|
return;
|
|
|
}
|
|
|
String sceneKey = customMsgBO.getSendKey();
|
|
|
Set<String> openIdSet = new HashSet<>(customMsgBO.getOpenIdSet());
|
|
|
logger.info("sendWechatCustomMsg with sceneKey is {},send origin size is {}",sceneKey,openIdSet.size());
|
|
|
//根据过滤条件进行过滤
|
|
|
if(customMsgBO.getFilterDays() != 0){
|
|
|
getDaysFilter(customMsgBO,openIdSet);
|
|
|
}
|
|
|
//组装发送
|
|
|
List<String> sendSuccessList = customMsgSend(customMsgBO,openIdSet);
|
|
|
logger.info("end sendWechatCustomMsg with sceneKey is {},successSize is {}",customMsgBO.getSendKey(),sendSuccessList.size());
|
|
|
//成功记录存redis
|
|
|
String redisKeyStr = RedisCacheKeyConstant.WECAHT_CUSTOM_SEND_KEY + customMsgBO.getPublicNumberCode() + '_' + nowDate;
|
|
|
//成功记录存7天
|
|
|
pushRedisService.setListValue(redisKeyStr,sendSuccessList,SEVEN_DAY_HOURS);
|
|
|
}
|
|
|
|
|
|
private void getDaysFilter(WechatCustomMsgBO customMsgBO, Set<String> openIdSet) {
|
|
|
int filterDayReal = customMsgBO.getFilterDays() - 1;
|
|
|
//根据间隔天数计算出需要过滤到的最早的一天
|
|
|
Calendar calendar = Calendar.getInstance();
|
|
|
calendar.add(Calendar.DATE, -filterDayReal);
|
|
|
String startDate = DateUtil.dateToString(calendar.getTime(), DATE_ID_FORMAT);
|
|
|
Date date = DateUtil.stringToDate(startDate,"DATE_ID_FORMAT");
|
|
|
Calendar c = Calendar.getInstance();
|
|
|
c.setTime(date);
|
|
|
int day = c.get(Calendar.DATE);
|
|
|
for (int i = 0; i <= filterDayReal; i++){
|
|
|
//从最早日期开始往后累加到每个日期,每天过滤
|
|
|
c.set(Calendar.DATE, day + i);
|
|
|
String nowDate = new SimpleDateFormat(DATE_ID_FORMAT).format(c.getTime());
|
|
|
//根据日期获取当天发送客服消息的记录
|
|
|
String redisKeyStr = RedisCacheKeyConstant.WECAHT_CUSTOM_SEND_KEY + customMsgBO.getPublicNumberCode() + '_' + nowDate;
|
|
|
pushRedisService.getSetFilter(openIdSet,redisKeyStr);
|
|
|
logger.info("sendWechatCustomMsg with day filter,sceneKey is {},redisKeyStr is {},nowSize is {}",customMsgBO.getSendKey(),redisKeyStr,openIdSet.size());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
private List<String> customMsgSend(WechatCustomMsgBO customMsgBO,Set<String> openIdSet){
|
|
|
logger.info("begin customMsgSend with sceneKey is {},send openId size is {}",customMsgBO.getSendKey(),openIdSet.size());
|
|
|
// 获取token 和接口url
|
|
|
AccessToken accessToken = weixinAccessTokenService.queryWeixinAccessToken(customMsgBO.getPublicNumberCode());
|
|
|
//若仍未获取到 token 则返回
|
|
|
if(accessToken == null){
|
|
|
logger.warn("customMsgSend with accessToken is null,sendKey is {}",customMsgBO.getSendKey());
|
|
|
return new ArrayList<>();
|
|
|
}
|
|
|
List<String> successList = new ArrayList<>();
|
|
|
String templateUrl = this.getTemplateUrl(accessToken, Consts.CUSTOM_MSG_SEND_URL);
|
|
|
//组装消息内容
|
|
|
JSONObject sendDataObject = new JSONObject();
|
|
|
sendDataObject.put("msgtype",customMsgBO.getMsgType());
|
|
|
sendDataObject.put("news",JSONObject.parseObject(customMsgBO.getSendContent()));
|
|
|
openIdSet.forEach(openId -> {
|
|
|
//限制100ms调一次
|
|
|
rateLimiter.acquire();
|
|
|
sendDataObject.put("touser", openId);
|
|
|
JSONObject result = sendWechatRequest.sendWechatRequest(customMsgBO.getPublicNumberCode(), templateUrl, "POST", sendDataObject.toJSONString());
|
|
|
if (result != null && result.getIntValue("errcode") == 0) {
|
|
|
successList.add(openId);
|
|
|
}
|
|
|
sendWechatMsgLog.info("customMsgSend with sceneKey {},openId is {},result {}, content is {}", customMsgBO.getSendKey(), openId, result, sendDataObject.toJSONString());
|
|
|
});
|
|
|
return successList;
|
|
|
}
|
|
|
|
|
|
} |
...
|
...
|
|