|
|
|
|
package com.ynxbd.push.helper;
|
|
|
|
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
import com.ynxbd.push.config.IniConfig;
|
|
|
|
|
import com.ynxbd.push.entity.*;
|
|
|
|
|
import com.ynxbd.push.entity.enums.MsgParamEnum;
|
|
|
|
|
import com.ynxbd.push.entity.response.ResponseResult;
|
|
|
|
|
import com.ynxbd.push.entity.tencent.*;
|
|
|
|
|
import com.ynxbd.push.httpRequest.tencent.WeChatDataRequest;
|
|
|
|
|
import com.ynxbd.push.httpRequest.xbd.wx.WxCacheRequest;
|
|
|
|
|
import com.ynxbd.push.thread.ThreadConfig;
|
|
|
|
|
import lombok.SneakyThrows;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
import org.apache.http.Header;
|
|
|
|
|
import org.apache.http.HttpResponse;
|
|
|
|
|
import org.apache.http.client.methods.HttpUriRequest;
|
|
|
|
|
import org.apache.http.client.methods.RequestBuilder;
|
|
|
|
|
import org.apache.http.concurrent.FutureCallback;
|
|
|
|
|
import org.apache.http.entity.StringEntity;
|
|
|
|
|
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
|
|
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
|
|
import org.springframework.util.ObjectUtils;
|
|
|
|
|
import org.springframework.web.util.UriUtils;
|
|
|
|
|
import weixin.popular.api.API;
|
|
|
|
|
import weixin.popular.api.MessageAPI;
|
|
|
|
|
import weixin.popular.api.UserAPI;
|
|
|
|
|
import weixin.popular.bean.message.MessageSendResult;
|
|
|
|
|
import weixin.popular.bean.message.massmessage.Filter;
|
|
|
|
|
import weixin.popular.bean.message.massmessage.MassTextMessage;
|
|
|
|
|
import weixin.popular.bean.user.Group;
|
|
|
|
|
import weixin.popular.client.LocalHttpClient;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.concurrent.CountDownLatch;
|
|
|
|
|
import java.util.concurrent.ThreadPoolExecutor;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 所有消息发送的工厂类
|
|
|
|
|
*
|
|
|
|
|
* @Project WebApi
|
|
|
|
|
* @Name MessageApiHelper
|
|
|
|
|
* @Author 李进才
|
|
|
|
|
* @Date 2020/5/25
|
|
|
|
|
* @Version v1.0.0
|
|
|
|
|
* @Copyright @ 2017 云南新八达科技有限公司 All rights reserved.
|
|
|
|
|
*/
|
|
|
|
|
@Slf4j
|
|
|
|
|
public class MessageApiHelper {
|
|
|
|
|
|
|
|
|
|
protected static Header jsonHeader;
|
|
|
|
|
|
|
|
|
|
public static final Integer EVERY_OPENID_COUNT = 10000;
|
|
|
|
|
|
|
|
|
|
public static final String MESSAGE_RESULT_ERROR_CODE = "4002";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 三层调用,第一层,传输SendMessageTemplate对象(减少controller代码量)
|
|
|
|
|
*
|
|
|
|
|
* @param template
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public static MessageSendResult templateMessageSend(SendMessageTemplate template) {
|
|
|
|
|
MessageSendResult messageSendResult = templateMessage(template);
|
|
|
|
|
log.info("消息发送状态:腾讯返回-{},messageId-{},openId-{}", messageSendResult.getErrcode(), template.getMessage_id(), template.getOpenId());
|
|
|
|
|
return messageSendResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 三层调用第二层,转换实体对象为json对象
|
|
|
|
|
*
|
|
|
|
|
* @param sendMessageTemplate 模版数据
|
|
|
|
|
* @return 请求接口返回的状态码等信息
|
|
|
|
|
*/
|
|
|
|
|
public static MessageSendResult templateMessage(SendMessageTemplate sendMessageTemplate) {
|
|
|
|
|
try {
|
|
|
|
|
sendMessageTemplate.setUrl(UriUtils.decode(sendMessageTemplate.getUrl(), StandardCharsets.UTF_8.toString()));
|
|
|
|
|
String jsonMessage = TemplateSelectHelper.select(sendMessageTemplate);
|
|
|
|
|
jsonMessage = jsonMessage.replaceAll("\\\\\\\\r", "\\\\r");
|
|
|
|
|
jsonMessage = jsonMessage.replaceAll("\\\\\\\\n", "\\\\n");
|
|
|
|
|
log.info("SendTenCentJson:{}", jsonMessage);
|
|
|
|
|
return templateMessageSend(jsonMessage);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
return ResponseResult.MESSAGE_RESULT_ERROR_CODE.toMessResult();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 三层调用最后一层,调起http发送模版消息
|
|
|
|
|
*
|
|
|
|
|
* @param messageJson json字符串
|
|
|
|
|
*/
|
|
|
|
|
private static MessageSendResult templateMessageSend(String messageJson) {
|
|
|
|
|
HttpUriRequest httpUriRequest = RequestBuilder.post().setHeader(jsonHeader).setUri("https://api.weixin.qq.com/cgi-bin/message/template/send").addParameter("access_token", API.accessToken(WxCacheRequest.getAccessToken())).setEntity(new StringEntity(messageJson, StandardCharsets.UTF_8)).build();
|
|
|
|
|
MessageSendResult result = LocalHttpClient.executeJsonResult(httpUriRequest, MessageSendResult.class);
|
|
|
|
|
|
|
|
|
|
String errCode = result.getErrcode();
|
|
|
|
|
if (ResponseResult.CODE_INVALIDATION.ERR_CODE.equals(errCode) || ResponseResult.CODE_EXPIRED.ERR_CODE.equals(errCode)) {
|
|
|
|
|
String errMsg = result.getErrmsg();
|
|
|
|
|
log.error("[推送]请求失败 errCode={}, errMsg={}", errCode, errMsg);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 群发消息给用户
|
|
|
|
|
*
|
|
|
|
|
* @param content 发送消息的内容
|
|
|
|
|
* @return 请求接口返回的状态码等信息
|
|
|
|
|
*/
|
|
|
|
|
public static MessageSendResult group(String content) {
|
|
|
|
|
try {
|
|
|
|
|
String accessToken = WxCacheRequest.getAccessToken();
|
|
|
|
|
Group group = UserAPI.groupsGet(accessToken);
|
|
|
|
|
String gid = group.getGroups().get(0).getId();
|
|
|
|
|
MassTextMessage textMessage = new MassTextMessage(content);
|
|
|
|
|
textMessage.setFilter(new Filter(false, gid));
|
|
|
|
|
return MessageAPI.messageMassSendall(accessToken, textMessage);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.info(e.getMessage());
|
|
|
|
|
return ResponseResult.MESSAGE_RESULT_ERROR_CODE.toMessResult();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据openid用客服接口发送信息,最多每次发送二十条,每当用户回复自己可以再发送二十条
|
|
|
|
|
*
|
|
|
|
|
* @param openid 用户在该微信公众号的唯一id,也就是需要发送给哪个用户
|
|
|
|
|
* @param content 需要发送给用户的内容
|
|
|
|
|
* @return 请求接口返回的状态码等信息
|
|
|
|
|
*/
|
|
|
|
|
public static MessageSendResult sendTextForOpenId(String openid, String content) {
|
|
|
|
|
try {
|
|
|
|
|
TestMessage testMessage = new TestMessage();
|
|
|
|
|
testMessage.setMsgtype("text");
|
|
|
|
|
testMessage.setTouser(openid);
|
|
|
|
|
Map<String, Object> map = new HashMap<>();
|
|
|
|
|
map.put("content", content);
|
|
|
|
|
testMessage.setText(map);
|
|
|
|
|
|
|
|
|
|
String jsonTestMessage = new ObjectMapper().writeValueAsString(testMessage);
|
|
|
|
|
return messageMassSend(jsonTestMessage);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
return ResponseResult.MESSAGE_RESULT_ERROR_CODE.toMessResult();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据患者ID或者医生ID推送模版消息
|
|
|
|
|
*
|
|
|
|
|
* @param organizeName
|
|
|
|
|
* @param idCard
|
|
|
|
|
* @param title
|
|
|
|
|
* @param patientId
|
|
|
|
|
* @param doctorCode
|
|
|
|
|
* @param first
|
|
|
|
|
* @param keyword1
|
|
|
|
|
* @param keyword2
|
|
|
|
|
* @param keyword3
|
|
|
|
|
* @param keyword4
|
|
|
|
|
* @param keyword5
|
|
|
|
|
* @param remark
|
|
|
|
|
* @param url
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public static MessageSendResult TemplateMessageForCode(String organizeName, String code, String idCard, String title, String patientId, String doctorCode, String first, String keyword1, String keyword2, String keyword3, String keyword4, String keyword5, String remark, String url, String messageId) {
|
|
|
|
|
if (patientId == null && idCard == null && doctorCode == null) {
|
|
|
|
|
log.info("[{}]参数无效", title);
|
|
|
|
|
return ResponseResult.PARAMETER_IS_NULL.toMessResult();
|
|
|
|
|
}
|
|
|
|
|
if (DesEncryptHelper.deCode(organizeName).equals("error:null")) {
|
|
|
|
|
log.info("[{}]组织机构代码无效,organizeName-{}", title, organizeName);
|
|
|
|
|
return ResponseResult.ORGANIZE_IS_NULL.toMessResult();
|
|
|
|
|
}
|
|
|
|
|
String reportTemplateId = WeChatDataRequest.getTemplateId(title);
|
|
|
|
|
if ("绑定通知".equals(title) && reportTemplateId == null) {
|
|
|
|
|
reportTemplateId = WeChatDataRequest.getTemplateId("医院通知");
|
|
|
|
|
}
|
|
|
|
|
if (IniConfig.getInstance("templateVersion") == null) {
|
|
|
|
|
code = "";
|
|
|
|
|
}
|
|
|
|
|
if (doctorCode != null) {
|
|
|
|
|
List<String> allDoctorCodeList = WeChatDataRequest.getAllOpenIdForDoctorCode(doctorCode);
|
|
|
|
|
if (allDoctorCodeList.isEmpty()) {
|
|
|
|
|
log.info("[{}]{}未绑定微官网,doctorCode:{}", title, DesEncryptHelper.deCode(organizeName), doctorCode);
|
|
|
|
|
return ResponseResult.NOT_FIND_DATA.toMessResult();
|
|
|
|
|
}
|
|
|
|
|
for (String interfaceOpenId : allDoctorCodeList) {
|
|
|
|
|
String openId = AesCodeHelper.deCode(interfaceOpenId);
|
|
|
|
|
SendMessageTemplate sendMessageTemplate = SendMessageTemplate.builder()
|
|
|
|
|
.template_id(reportTemplateId)
|
|
|
|
|
.first(first)
|
|
|
|
|
.code(code)
|
|
|
|
|
.message_id(messageId)
|
|
|
|
|
.keyword1(keyword1)
|
|
|
|
|
.keyword2(keyword2)
|
|
|
|
|
.keyword3(keyword3)
|
|
|
|
|
.keyword4(keyword4)
|
|
|
|
|
.keyword5(keyword5)
|
|
|
|
|
.remark(remark)
|
|
|
|
|
.openId(openId)
|
|
|
|
|
.url(url)
|
|
|
|
|
.build();
|
|
|
|
|
MessageSendResult messageSendResult = templateMessageSend(sendMessageTemplate);
|
|
|
|
|
log.info("[{}]{}医生账号消息推送,推送结果代码-{},推送结果-{}", title, DesEncryptHelper.deCode(organizeName), messageSendResult.getErrcode(), messageSendResult.getErrmsg());
|
|
|
|
|
}
|
|
|
|
|
return ResponseResult.JOIN_QUEUE.toMessResult();
|
|
|
|
|
}
|
|
|
|
|
log.info("[外部组织对接推送]" + DesEncryptHelper.deCode(organizeName) + "发送" + title + "消息");
|
|
|
|
|
String weChatUrl = "http://127.0.0.1/wx/";
|
|
|
|
|
HttpUriRequest httpUriRequest = RequestBuilder
|
|
|
|
|
.get()
|
|
|
|
|
.setHeader(jsonHeader)
|
|
|
|
|
.setUri(new StringBuilder()
|
|
|
|
|
.append(weChatUrl)
|
|
|
|
|
.append(patientId != null ? "patient/getOpenIdsByPatientId.do" : "patient/getOpenIdsByCardNo.do").toString())
|
|
|
|
|
.addParameter(patientId != null ? "patientId" : "cardNo", patientId != null ? patientId : idCard)
|
|
|
|
|
.addParameter("algorithm", "des")
|
|
|
|
|
.addParameter("isEncryptComma", "false")
|
|
|
|
|
.addParameter("isLastBind", "true")
|
|
|
|
|
.build();
|
|
|
|
|
WeChatResponse weChatResponse = LocalHttpClient.executeJsonResult(httpUriRequest, WeChatResponse.class);
|
|
|
|
|
if (weChatResponse.getData() == null) {
|
|
|
|
|
return ResponseResult.NOT_FIND_DATA.toMessResult();
|
|
|
|
|
}
|
|
|
|
|
String openId = DesEncryptHelper.deCode(weChatResponse.getData().get(0));
|
|
|
|
|
SendMessageTemplate sendMessageTemplate = SendMessageTemplate.builder()
|
|
|
|
|
.template_id(reportTemplateId)
|
|
|
|
|
.first(first)
|
|
|
|
|
.code(code)
|
|
|
|
|
.keyword1(keyword1)
|
|
|
|
|
.message_id(messageId)
|
|
|
|
|
.keyword2(keyword2)
|
|
|
|
|
.keyword3(keyword3)
|
|
|
|
|
.keyword4(keyword4)
|
|
|
|
|
.keyword5(keyword5)
|
|
|
|
|
.remark(remark)
|
|
|
|
|
.openId(openId)
|
|
|
|
|
.url(url)
|
|
|
|
|
.build();
|
|
|
|
|
return templateMessageSend(sendMessageTemplate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 通过客服的方式发送链接信息给用户
|
|
|
|
|
*
|
|
|
|
|
* @param openid 用户在该微信公众号的唯一id,也就是需要发送给哪个用户
|
|
|
|
|
* @param title 标题内容
|
|
|
|
|
* @param description 描述
|
|
|
|
|
* @param url 跳转链接
|
|
|
|
|
* @param thumb_url 图片链接
|
|
|
|
|
* @return 请求接口返回的状态码等信息
|
|
|
|
|
*/
|
|
|
|
|
public static MessageSendResult sendLinkForOpenId(String openid, String title, String description, String url, String thumb_url) {
|
|
|
|
|
try {
|
|
|
|
|
LinkMessage linkMessage = new LinkMessage();
|
|
|
|
|
linkMessage.setMsgtype("link");
|
|
|
|
|
linkMessage.setTouser(openid);
|
|
|
|
|
Map<String, Object> map = new HashMap<>();
|
|
|
|
|
map.put("title", title);
|
|
|
|
|
map.put("description", description);
|
|
|
|
|
map.put("url", url);
|
|
|
|
|
map.put("thumb_url", thumb_url);
|
|
|
|
|
linkMessage.setLink(map);
|
|
|
|
|
String jsonTestMessage = new ObjectMapper().writeValueAsString(linkMessage);
|
|
|
|
|
return messageMassSend(jsonTestMessage);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
return ResponseResult.MESSAGE_RESULT_ERROR_CODE.toMessResult();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 一次性订阅消息发送,因为每家都一样全部都在一个类封装好了,不像模版消息调了好多层解偶
|
|
|
|
|
*
|
|
|
|
|
* @param subscribe
|
|
|
|
|
* @return
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
public static MessageSendResult subscribeMessage(Subscribe subscribe) throws JsonProcessingException {
|
|
|
|
|
Map<String, Object> miniProgram = new HashMap<>();
|
|
|
|
|
miniProgram.put("appid", subscribe.getAppid());
|
|
|
|
|
miniProgram.put("pagepath", subscribe.getPagepath());
|
|
|
|
|
|
|
|
|
|
Map<String, Object> data = new HashMap<>();
|
|
|
|
|
data.put("content", TemplateJsonValue.builder().value(subscribe.getContent()).color("#173177").build());
|
|
|
|
|
TemplateJson templateJson = TemplateJson.builder()
|
|
|
|
|
.template_id(subscribe.getTemplate_id())
|
|
|
|
|
.miniprogram(miniProgram)
|
|
|
|
|
.url(subscribe.getUrl())
|
|
|
|
|
.scene(subscribe.getScene())
|
|
|
|
|
.title(subscribe.getTitle())
|
|
|
|
|
.data(data)
|
|
|
|
|
.touser(subscribe.getTouser())
|
|
|
|
|
.build();
|
|
|
|
|
ObjectMapper objectMapper = new ObjectMapper();
|
|
|
|
|
String messageJson = objectMapper.writeValueAsString(templateJson);
|
|
|
|
|
HttpUriRequest httpUriRequest = RequestBuilder.post().setHeader(jsonHeader).setUri("https://api.weixin.qq.com/cgi-bin/message/template/subscribe").addParameter("access_token", API.accessToken(WxCacheRequest.getAccessToken())).setEntity(new StringEntity(messageJson, StandardCharsets.UTF_8)).build();
|
|
|
|
|
return LocalHttpClient.executeJsonResult(httpUriRequest, MessageSendResult.class);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 发送文本消息
|
|
|
|
|
*
|
|
|
|
|
* @param messageJson messageJson
|
|
|
|
|
* @return MessageSendResult
|
|
|
|
|
*/
|
|
|
|
|
private static MessageSendResult messageMassSend(String messageJson) {
|
|
|
|
|
HttpUriRequest httpUriRequest = RequestBuilder.post().setHeader(jsonHeader).setUri("https://api.weixin.qq.com/cgi-bin/message/custom/send").addParameter("access_token", API.accessToken(WxCacheRequest.getAccessToken())).setEntity(new StringEntity(messageJson, StandardCharsets.UTF_8)).build();
|
|
|
|
|
return LocalHttpClient.executeJsonResult(httpUriRequest, MessageSendResult.class);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取该公众号下所有用户的openId
|
|
|
|
|
*
|
|
|
|
|
* @param next_openid next_openid
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public static AllUser getAllUser(String next_openid) {
|
|
|
|
|
try {
|
|
|
|
|
HttpUriRequest httpUriRequest = RequestBuilder.get().setHeader(jsonHeader).setUri("https://api.weixin.qq.com/cgi-bin/user/get").addParameter("access_token", API.accessToken(WxCacheRequest.getAccessToken())).addParameter("next_openid", next_openid).build();
|
|
|
|
|
AllUser messageSendResult = LocalHttpClient.executeJsonResult(httpUriRequest, AllUser.class);
|
|
|
|
|
messageSendResult.setErrcode("0");
|
|
|
|
|
return messageSendResult;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
AllUser allUser = new AllUser();
|
|
|
|
|
allUser.setErrcode(MESSAGE_RESULT_ERROR_CODE);
|
|
|
|
|
return allUser;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 群发模版消息入口(包括多线程组装)
|
|
|
|
|
*
|
|
|
|
|
* @param sendMessageTemplate
|
|
|
|
|
* @return
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
public static CompleteThreadCount groupTemplateSend(SendMessageTemplate sendMessageTemplate) throws IOException, InterruptedException {
|
|
|
|
|
final CompleteThreadCount completeThreadCount = CompleteThreadCount.builder().completed(0).failed(0).cancelled(0).build();
|
|
|
|
|
final OpenIdList openIdList = getAllUserList();
|
|
|
|
|
ThreadPoolExecutor threadPoolExecutor = ThreadConfig.getExecutor(15, 20);
|
|
|
|
|
log.info("所有用户总数:" + openIdList.getCount());
|
|
|
|
|
|
|
|
|
|
final CloseableHttpAsyncClient httpClient = HttpAsyncClientHelper.getHttpAsyncClient();
|
|
|
|
|
final CountDownLatch latch = new CountDownLatch(openIdList.getCount());
|
|
|
|
|
httpClient.start();
|
|
|
|
|
for (List<String> openIds : openIdList.getOpenIds()) {
|
|
|
|
|
try {
|
|
|
|
|
threadPoolExecutor.execute(() -> groupSendTemplateMessage(httpClient, openIds, sendMessageTemplate, completeThreadCount, latch));
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("主线程循环过程中出现错误:{}", e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log.info("---执行完成-线程未停止!----完成数:{}, 失败数{}", completeThreadCount.getCompleted(), completeThreadCount.getFailed() + "取消数:" + completeThreadCount.getCancelled());
|
|
|
|
|
latch.await();
|
|
|
|
|
httpClient.close();
|
|
|
|
|
|
|
|
|
|
List<Runnable> notStopRunnable = threadPoolExecutor.shutdownNow();
|
|
|
|
|
for (Runnable runnable : notStopRunnable) {
|
|
|
|
|
log.error("未停止任务:{}", runnable.toString());
|
|
|
|
|
}
|
|
|
|
|
log.info("线程是否结束:{}, 异步是否结束:{}", threadPoolExecutor.isShutdown(), httpClient.isRunning());
|
|
|
|
|
log.info("---执行完成-线程已停止!!---完成数:{}, 失败数:{}", completeThreadCount.getCompleted(), completeThreadCount.getFailed() + "取消数:" + completeThreadCount.getCancelled());
|
|
|
|
|
return completeThreadCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 发送一组openid的模版消息(任务分包,将openid分散然后由异步发送)
|
|
|
|
|
*
|
|
|
|
|
* @param completeThreadCount
|
|
|
|
|
* @param openIds
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
private static void groupSendTemplateMessage(CloseableHttpAsyncClient httpClient, List<String> openIds, SendMessageTemplate sendMessageTemplate, CompleteThreadCount completeThreadCount, CountDownLatch latch) {
|
|
|
|
|
//将一万条请求任务逐次加入线程
|
|
|
|
|
for (String openId : openIds) {
|
|
|
|
|
try {
|
|
|
|
|
SendMessageTemplate singleSendMessageTemplate = SendMessageTemplate.builder().build();
|
|
|
|
|
BeanUtils.copyProperties(sendMessageTemplate, singleSendMessageTemplate);
|
|
|
|
|
singleSendMessageTemplate.setOpenId(openId);
|
|
|
|
|
Thread.sleep(Integer.parseInt(IniConfig.getInstance("speed")));
|
|
|
|
|
asyncTemplateMessageSend(httpClient, completeThreadCount, RequestBuilder
|
|
|
|
|
.post()
|
|
|
|
|
.setHeader(jsonHeader)
|
|
|
|
|
.setUri("https://api.weixin.qq.com/cgi-bin/message/template/send")
|
|
|
|
|
.addParameter("access_token", API.accessToken(Objects.requireNonNull(WxCacheRequest.getAccessToken())))
|
|
|
|
|
.addParameter("time_stamp", String.valueOf(System.currentTimeMillis()))
|
|
|
|
|
.setEntity(new StringEntity(TemplateSelectHelper.select(singleSendMessageTemplate), StandardCharsets.UTF_8))
|
|
|
|
|
.build(), latch);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("httpClient异步线程执行中出现错误:{}", e.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 异步发送网络请求(实际调起http的地方,异步调用)
|
|
|
|
|
*
|
|
|
|
|
* @param httpclient
|
|
|
|
|
* @param request
|
|
|
|
|
*/
|
|
|
|
|
private static void asyncTemplateMessageSend(final CloseableHttpAsyncClient httpclient, final CompleteThreadCount completeThreadCount, final HttpUriRequest request, final CountDownLatch latch) throws IOException {
|
|
|
|
|
httpclient.execute(request, new FutureCallback<HttpResponse>() {
|
|
|
|
|
@SneakyThrows
|
|
|
|
|
@Override
|
|
|
|
|
public void completed(HttpResponse response) {
|
|
|
|
|
completeThreadCount.setCompleted(completeThreadCount.getCompleted() + 1);
|
|
|
|
|
latch.countDown();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SneakyThrows
|
|
|
|
|
@Override
|
|
|
|
|
public void failed(Exception ex) {
|
|
|
|
|
log.error("回调过程中出现错误:" + ex.toString());
|
|
|
|
|
completeThreadCount.setFailed(completeThreadCount.getFailed() + 1);
|
|
|
|
|
latch.countDown();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SneakyThrows
|
|
|
|
|
@Override
|
|
|
|
|
public void cancelled() {
|
|
|
|
|
completeThreadCount.setCancelled(completeThreadCount.getCancelled() + 1);
|
|
|
|
|
latch.countDown();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取所有用户列表的集合(1W个用户为一组)
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
private static OpenIdList getAllUserList() {
|
|
|
|
|
List<List<String>> openIds = new ArrayList<>();
|
|
|
|
|
List<String> nextOpenIds = new ArrayList<>();
|
|
|
|
|
AllUser userList = getAllUser(null);
|
|
|
|
|
String nextOpenId = userList.getNext_openid();
|
|
|
|
|
nextOpenIds.add(nextOpenId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Integer count = ((List<String>) userList.getData().get("openid")).size();
|
|
|
|
|
openIds.add((List<String>) userList.getData().get("openid"));
|
|
|
|
|
for (int i = 0; i < Math.floor(userList.getTotal() / EVERY_OPENID_COUNT); i++) {
|
|
|
|
|
try {
|
|
|
|
|
if (nextOpenId == null || nextOpenId.isEmpty()) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
userList = getAllUser(nextOpenId);
|
|
|
|
|
if (userList.getData().get("openid") == null) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
nextOpenId = userList.getNext_openid();
|
|
|
|
|
nextOpenIds.add(nextOpenId);
|
|
|
|
|
count += ((List<String>) userList.getData().get("openid")).size();
|
|
|
|
|
openIds.add((List<String>) userList.getData().get("openid"));
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("请求列表过程中出现错误:next_openid:" + nextOpenId + "错误:" + e.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return OpenIdList.builder().openIds(openIds).count(count).build();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// /**
|
|
|
|
|
// * 将所有openId组装成SendMessageTemplate集合
|
|
|
|
|
// * @param openIdList
|
|
|
|
|
// * @param sendMessageTemplate
|
|
|
|
|
// * @return
|
|
|
|
|
// */
|
|
|
|
|
// private List<List<SendMessageTemplate>> GetAllSendMessageTemplate(OpenIdList openIdList, SendMessageTemplate sendMessageTemplate){
|
|
|
|
|
// List<List<SendMessageTemplate>> allSendMessageTemplate = new ArrayList<>();
|
|
|
|
|
// for (List<String> openList : openIdList.getOpenIds()) {
|
|
|
|
|
// allSendMessageTemplate.add(GetGroupSendMessageTemplate(openList,sendMessageTemplate));
|
|
|
|
|
// }
|
|
|
|
|
// return allSendMessageTemplate;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /**
|
|
|
|
|
// * 单组openId组装成SendMessageTemplate哈希集合,防止重复
|
|
|
|
|
// * @param groupOpenId
|
|
|
|
|
// * @param sendMessageTemplate
|
|
|
|
|
// * @return
|
|
|
|
|
// */
|
|
|
|
|
// private List<SendMessageTemplate> GetGroupSendMessageTemplate(List<String> groupOpenId, SendMessageTemplate sendMessageTemplate){
|
|
|
|
|
// List<SendMessageTemplate> groupSendMessageTemplate = new ArrayList<>();
|
|
|
|
|
// for(String openId: groupOpenId){
|
|
|
|
|
// SendMessageTemplate newSendMessageTemplate =SendMessageTemplate.builder().build();
|
|
|
|
|
// BeanUtils.copyProperties(sendMessageTemplate,newSendMessageTemplate);
|
|
|
|
|
// newSendMessageTemplate.setOpenId(openId);
|
|
|
|
|
// groupSendMessageTemplate.add(newSendMessageTemplate);
|
|
|
|
|
// }
|
|
|
|
|
// return groupSendMessageTemplate;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 请求微信获取openId
|
|
|
|
|
*
|
|
|
|
|
* @param title 标题
|
|
|
|
|
* @param patientId 患者ID
|
|
|
|
|
* @param cardNo 身份证号码
|
|
|
|
|
* @return openId
|
|
|
|
|
*/
|
|
|
|
|
public static String reqWxOpenId(String title, String patientId, String cardNo) throws Exception {
|
|
|
|
|
log.info("[外部组织对接推送]发送{}消息", title);
|
|
|
|
|
String weChatUrl = "http://127.0.0.1/wx/";
|
|
|
|
|
HttpUriRequest httpUriRequest = RequestBuilder
|
|
|
|
|
.get()
|
|
|
|
|
.setHeader(jsonHeader)
|
|
|
|
|
.setUri(new StringBuilder()
|
|
|
|
|
.append(weChatUrl)
|
|
|
|
|
.append(patientId != null ? "patient/getOpenIdsByPatientId.do" : "patient/getOpenIdsByCardNo.do").toString())
|
|
|
|
|
.addParameter(patientId != null ? "patientId" : "cardNo", !ObjectUtils.isEmpty(patientId) ? patientId : cardNo)
|
|
|
|
|
.addParameter("algorithm", "des")
|
|
|
|
|
.addParameter("isEncryptComma", "false")
|
|
|
|
|
.addParameter("isLastBind", "true")
|
|
|
|
|
.build();
|
|
|
|
|
WeChatResponse weChatResponse = LocalHttpClient.executeJsonResult(httpUriRequest, WeChatResponse.class);
|
|
|
|
|
if (weChatResponse.getData() == null) {
|
|
|
|
|
throw new Exception(ResponseResult.NOT_FIND_DATA.ERR_MSG);
|
|
|
|
|
}
|
|
|
|
|
String openId = DesEncryptHelper.deCode(weChatResponse.getData().get(0));
|
|
|
|
|
if (ObjectUtils.isEmpty(openId)) {
|
|
|
|
|
throw new Exception("[推送]未找到openId");
|
|
|
|
|
}
|
|
|
|
|
return openId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 根据患者ID或者医生ID推送模版消息
|
|
|
|
|
*/
|
|
|
|
|
public static MessageSendResult templateMessageForMap(Map<String, String> strTemp) {
|
|
|
|
|
String code = strTemp.get("tip");
|
|
|
|
|
String messageId = strTemp.get("message_id");
|
|
|
|
|
|
|
|
|
|
if (IniConfig.getInstance("templateVersion") == null) {
|
|
|
|
|
code = ""; // tip
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String url = strTemp.get(MsgParamEnum.URL.CODE);
|
|
|
|
|
String title = strTemp.get(MsgParamEnum.TITLE.CODE);
|
|
|
|
|
String templateId = strTemp.get(MsgParamEnum.TEMPLATE_ID.CODE);
|
|
|
|
|
String doctorCode = strTemp.get("doctorCode");
|
|
|
|
|
String patientId = strTemp.get("patientId");
|
|
|
|
|
String cardNo = strTemp.get("cardNo");
|
|
|
|
|
|
|
|
|
|
Map<String, Object> temp = MapHelper.strMapToObjMap(strTemp);
|
|
|
|
|
|
|
|
|
|
if (doctorCode != null) {
|
|
|
|
|
List<String> allDoctorCodeList = WeChatDataRequest.getAllOpenIdForDoctorCode(doctorCode);
|
|
|
|
|
if (allDoctorCodeList.isEmpty()) {
|
|
|
|
|
log.info("[{}]未绑定微官网,doctorCode:{}", title, doctorCode);
|
|
|
|
|
return ResponseResult.NOT_FIND_DATA.toMessResult();
|
|
|
|
|
}
|
|
|
|
|
for (String interfaceOpenId : allDoctorCodeList) {
|
|
|
|
|
String openId = AesCodeHelper.deCode(interfaceOpenId);
|
|
|
|
|
SendTemplate sendTemplate = SendTemplate.builder()
|
|
|
|
|
.template_id(templateId)
|
|
|
|
|
.message_id(messageId)
|
|
|
|
|
.touser(openId)
|
|
|
|
|
.code(code)
|
|
|
|
|
.url(url)
|
|
|
|
|
.data(temp)
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
MessageSendResult messageSendResult = templateMessageSend(JSONObject.toJSONString(sendTemplate));
|
|
|
|
|
log.info("[{}]医生账号消息推送,推送结果代码-{},推送结果-{}", title, messageSendResult.getErrcode(), messageSendResult.getErrmsg());
|
|
|
|
|
}
|
|
|
|
|
return ResponseResult.JOIN_QUEUE.toMessResult();
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
String openId = reqWxOpenId(title, patientId, cardNo);
|
|
|
|
|
SendTemplate sendTemplate = SendTemplate.builder()
|
|
|
|
|
.template_id(templateId)
|
|
|
|
|
.message_id(messageId)
|
|
|
|
|
.touser(openId)
|
|
|
|
|
.code(code)
|
|
|
|
|
.url(url)
|
|
|
|
|
.data(temp)
|
|
|
|
|
.build();
|
|
|
|
|
log.info("组合数据[{}]", JSONObject.toJSONString(sendTemplate));
|
|
|
|
|
return templateMessageSend(JSONObject.toJSONString(sendTemplate));
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
return ResponseResult.NOT_FIND_DATA.toMessResult();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|