|
|
@@ -0,0 +1,283 @@
|
|
|
+package com.zd.base.message.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.http.HttpUtil;
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.zd.base.message.domain.UserOpenId;
|
|
|
+import com.zd.base.message.properties.WeChatProperties;
|
|
|
+import com.zd.base.message.service.IUserOpenIdService;
|
|
|
+import com.zd.base.message.service.IWechatMsgSendService;
|
|
|
+import com.zd.common.core.exception.ServiceException;
|
|
|
+import com.zd.common.core.template.Template;
|
|
|
+import com.zd.common.core.template.TemplateParam;
|
|
|
+import com.zd.common.core.template.TemplateResult;
|
|
|
+import com.zd.common.core.template.WxUserInfo;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.data.redis.core.BoundValueOperations;
|
|
|
+import org.springframework.data.redis.core.RedisTemplate;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 向微信小程序推送私密消息
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class WechatMsgSendServiceImpl implements IWechatMsgSendService {
|
|
|
+
|
|
|
+ @Resource(name = "redisTemplate")
|
|
|
+ protected RedisTemplate<String, String> redisTemplate;
|
|
|
+ @Autowired
|
|
|
+ private WeChatProperties weChatProperties;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private IUserOpenIdService openIdService;
|
|
|
+
|
|
|
+ private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 微信获取openId的返回值
|
|
|
+ */
|
|
|
+ private static final Map<Integer, String> messageOpenIdMap = new HashMap<>();
|
|
|
+
|
|
|
+ static {
|
|
|
+ messageOpenIdMap.put(-1, "系统繁忙,此时请开发者稍候再试");
|
|
|
+ messageOpenIdMap.put(0, "请求成功");
|
|
|
+ messageOpenIdMap.put(40029, "code 无效");
|
|
|
+ messageOpenIdMap.put(45011, "频率限制,每个用户每分钟100次");
|
|
|
+ messageOpenIdMap.put(40226, "高风险等级用户,小程序登录拦截 。风险等级详见用户安全解方案");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 微信发送模板消息的返回值
|
|
|
+ */
|
|
|
+ private static final Map<Integer, String> sendMessageResultMap = new HashMap<>();
|
|
|
+
|
|
|
+ static {
|
|
|
+ sendMessageResultMap.put(40003, "openid 为空或者不正确");
|
|
|
+ sendMessageResultMap.put(40037, "订阅模板 id 为空不正确");
|
|
|
+ sendMessageResultMap.put(43101, "用户拒绝接受消息,如果用户之前曾经订阅过,则表示用户取消了订阅关系");
|
|
|
+ sendMessageResultMap.put(47003, "模板参数不准确,可能为空或者不满足规则");//errmsg会提示具体是哪个字段出错
|
|
|
+ sendMessageResultMap.put(41030, "page路径不正确,需要保证在现网版本小程序中存在,与 app.json 保持一致");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 资格申请、用气申请通知发送(跳转页面:资格申请-资格详情、用气申请-申请详情)
|
|
|
+ *
|
|
|
+ * @param userId 用户ID
|
|
|
+ * @param checkType 审核类型 1:资格申请 2:用气申请
|
|
|
+ * @param checkStatus 审核状态
|
|
|
+ * @param checkTime 审核时间
|
|
|
+ * @param taskId 任务ID
|
|
|
+ * @return TemplateResult 通知发送结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public TemplateResult sendCheckResult(Long userId, Integer checkType, Integer checkStatus, Date checkTime, Long taskId) {
|
|
|
+ // checkType 双端页面不一致,判断跳转页面地址写入
|
|
|
+ String page = null;
|
|
|
+ if (checkType == 2) {
|
|
|
+ page = weChatProperties.getAirCheckUrl();
|
|
|
+ }
|
|
|
+ if (checkType == 1) {
|
|
|
+ page = weChatProperties.getQualificationCheckUrl();
|
|
|
+ }
|
|
|
+ return getTemplateResult(userId, checkType, checkStatus, checkTime, taskId, page);
|
|
|
+ }
|
|
|
+
|
|
|
+ private TemplateResult getTemplateResult(Long userId, Integer checkType, Integer checkStatus, Date checkTime, Long taskId, String page) {
|
|
|
+ page = page + "?id=" + taskId;
|
|
|
+ List<TemplateParam> paras = new ArrayList<>();
|
|
|
+ paras.add(new TemplateParam("thing39", checkType == 1 ? "资格申请" : "用气申请"));//申请事项
|
|
|
+ paras.add(new TemplateParam("phrase5", checkStatus == 1 ? "成功" : "失败"));//审核结果
|
|
|
+ paras.add(new TemplateParam("time24", dateFormat.format(checkTime)));//审核时间
|
|
|
+ return sendMessage(userId, weChatProperties.getCheckTemplateId(), page, paras);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 待办事项通知发送
|
|
|
+ *
|
|
|
+ * @param userId 用户ID
|
|
|
+ * @param backlogName 待办事项名称
|
|
|
+ * @param remark 备注
|
|
|
+ * @return TemplateResult 通知发送结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public TemplateResult sendBacklogResult(Long userId, String backlogName, String remark) {
|
|
|
+ Template template = new Template();
|
|
|
+ String openId = getOpenId(userId);
|
|
|
+ template.setToUser(openId);
|
|
|
+ template.setTemplateId(weChatProperties.getBacklogTemplateId());
|
|
|
+ // 供应商端-待办事项-需求明细
|
|
|
+ template.setPage(weChatProperties.getBacklogUrl());
|
|
|
+
|
|
|
+ List<TemplateParam> paras = new ArrayList<>();
|
|
|
+ paras.add(new TemplateParam("thing3", backlogName));//待办事项
|
|
|
+ paras.add(new TemplateParam("time5", dateFormat.format(Calendar.getInstance().getTime())));//通知时间
|
|
|
+ paras.add(new TemplateParam("thing6", remark));//备注
|
|
|
+ template.setData(paras);
|
|
|
+ return sendMsgService(template);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<String> getList() {
|
|
|
+ return weChatProperties.getTemplateIds();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public TemplateResult sendStuCheckResult(Long userId, Integer checkType, Integer checkStatus, Date checkTime, Long taskId) {
|
|
|
+ // checkType 双端页面不一致,判断跳转页面地址写入
|
|
|
+ String page = null;
|
|
|
+ if (checkType == 2) {
|
|
|
+ page = weChatProperties.getStuAirCheckUrl();
|
|
|
+ }
|
|
|
+ if (checkType == 1) {
|
|
|
+ page = weChatProperties.getStuQualificationCheckUrl();
|
|
|
+ }
|
|
|
+ return getTemplateResult(userId, checkType, checkStatus, checkTime, taskId, page);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public TemplateResult sendAlarm(List<Long> userIds, String address) {
|
|
|
+ List<TemplateParam> paras = new ArrayList<>();
|
|
|
+ paras.add(new TemplateParam("thing1", address));//报警位置
|
|
|
+ paras.add(new TemplateParam("time3", dateFormat.format(Calendar.getInstance().getTime())));//上报时间
|
|
|
+ paras.add(new TemplateParam("thing2", "气瓶超出范围报警"));//报警原因
|
|
|
+ userIds.forEach(id -> sendMessage(id, weChatProperties.getDeviceAlarmTemplateId(), weChatProperties.getInitPage(), paras));
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private TemplateResult sendMessage(Long userId, String weChatProperties, String page, List<TemplateParam> paras) {
|
|
|
+ Template template = getTemplate(userId, weChatProperties, page);
|
|
|
+ if (template==null){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ template.setData(paras);
|
|
|
+ return sendMsgService(template);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 资格申请、用气申请管理端待审核通知发送
|
|
|
+ *
|
|
|
+ * @param userId 用户ID
|
|
|
+ * @param checkType 审核类型 1:资格申请 2:用气申请
|
|
|
+ * @param name 申请人
|
|
|
+ * @param applyTime 申请时间
|
|
|
+ * @return TemplateResult 通知发送结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public TemplateResult sendWaitCheckResult(Long userId, Integer checkType, String name, Date applyTime) {
|
|
|
+ String page = weChatProperties.getWaitCheckUrl();
|
|
|
+ List<TemplateParam> paras = new ArrayList<>();
|
|
|
+ paras.add(new TemplateParam("name1", name));//申请事项
|
|
|
+ paras.add(new TemplateParam("thing3", checkType == 1 ? "资格申请" : "用气申请"));//审核结果
|
|
|
+ paras.add(new TemplateParam("time2", dateFormat.format(applyTime)));//审核时间
|
|
|
+ return sendMessage(userId, weChatProperties.getWaitCheckTemplateId(), page, paras);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Template getTemplate(Long userId, String templateId, String page) {
|
|
|
+ Template template = new Template();
|
|
|
+ String openId = getOpenId(userId);
|
|
|
+ if (openId != null) {
|
|
|
+ template.setToUser(openId);
|
|
|
+ template.setTemplateId(templateId);
|
|
|
+ template.setPage(page);
|
|
|
+ return template;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 出库确认通知
|
|
|
+ *
|
|
|
+ * @param userId 用户ID
|
|
|
+ * @param outType 出库类型
|
|
|
+ * @param outTime 出库时间
|
|
|
+ * @return TemplateResult 通知发送结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public TemplateResult sendStorageOutResult(Long userId, String outType, Date outTime) {
|
|
|
+ Template template = new Template();
|
|
|
+ String openId = getOpenId(userId);
|
|
|
+ template.setToUser(openId);
|
|
|
+ template.setTemplateId(weChatProperties.getStorageOutTemplateId());
|
|
|
+ List<TemplateParam> paras = new ArrayList<>();
|
|
|
+ paras.add(new TemplateParam("thing2", outType));//出库类型
|
|
|
+ paras.add(new TemplateParam("time9", dateFormat.format(outTime)));//出库时间
|
|
|
+ template.setData(paras);
|
|
|
+ return sendMsgService(template);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getOpenId(Long userId) {
|
|
|
+ UserOpenId userOpenId = openIdService.getByUserId(userId);
|
|
|
+ if (userOpenId == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return userOpenId.getOpenId();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String getOpenId(String code) {
|
|
|
+ String openIdUrl = weChatProperties.getOpenIdUrl().replace("APPID", weChatProperties.getAppId())
|
|
|
+ .replace("SECRET", weChatProperties.getSecret())
|
|
|
+ .replace("JSCODE", code);
|
|
|
+ String post = HttpUtil.get(openIdUrl);
|
|
|
+ JSONObject jsonObject = JSON.parseObject(post);
|
|
|
+ WxUserInfo wxUserInfo = JSON.toJavaObject(jsonObject, WxUserInfo.class);
|
|
|
+ if (wxUserInfo.getErrcode() != 0) {
|
|
|
+ String errMsg;
|
|
|
+ int errCode = wxUserInfo.getErrcode();
|
|
|
+ if (errCode == 40029) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (messageOpenIdMap.containsKey(errCode)) {
|
|
|
+ errMsg = messageOpenIdMap.get(errCode);
|
|
|
+ throw new ServiceException(errMsg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return wxUserInfo.getOpenid();
|
|
|
+ }
|
|
|
+
|
|
|
+ private TemplateResult sendMsgService(Template template) {
|
|
|
+ String url = weChatProperties.getUrl().replace("ACCESS_TOKEN", getAccessToken());
|
|
|
+ String post = HttpUtil.post(url, template.toJSON());
|
|
|
+ JSONObject jsonObject = JSON.parseObject(post);
|
|
|
+ TemplateResult result = JSON.toJavaObject(jsonObject, TemplateResult.class);
|
|
|
+ int errCode = result.getErrcode();
|
|
|
+ if (errCode == 47003) {
|
|
|
+ result.setErrmsg(sendMessageResultMap.get(errCode) + ":" + result.getErrmsg());
|
|
|
+ } else if (sendMessageResultMap.containsKey(errCode)) {
|
|
|
+ result.setErrmsg(sendMessageResultMap.get(errCode));
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getAccessToken() {
|
|
|
+ String accessToken = null;
|
|
|
+ try {
|
|
|
+ //查询是否还有缓存
|
|
|
+ BoundValueOperations<String, String> ops = redisTemplate.boundValueOps("account_token");
|
|
|
+ //缓存时长
|
|
|
+ if (StringUtils.isBlank(ops.get())) {
|
|
|
+ Map<String, Object> params = new HashMap<>();
|
|
|
+ params.put("grant_type", "client_credential");
|
|
|
+ params.put("appid", weChatProperties.getAppId());
|
|
|
+ params.put("secret", weChatProperties.getSecret());
|
|
|
+ String respData = HttpUtil.get(weChatProperties.getTokenUrl(), params);
|
|
|
+ log.info("get access_token=====\n{}", respData);
|
|
|
+ JSONObject json = JSON.parseObject(respData);
|
|
|
+ ops.set(json.getString("access_token"));
|
|
|
+ ops.expire(7100, TimeUnit.SECONDS);
|
|
|
+ }
|
|
|
+ accessToken = ops.get();
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return accessToken;
|
|
|
+ }
|
|
|
+}
|