Преглед изворни кода

add(backend) [消息处理 1.0]

wangxiao пре 4 година
родитељ
комит
b4251571f0
19 измењених фајлова са 595 додато и 85 уклоњено
  1. 5 1
      operation-backend/src/main/java/com/idiot/operationbackend/controller/WeChatController.java
  2. 13 0
      operation-backend/src/main/java/com/idiot/operationbackend/entity/FansActionStat.java
  3. 88 0
      operation-backend/src/main/java/com/idiot/operationbackend/handler/ScanQrHandler.java
  4. 39 29
      operation-backend/src/main/java/com/idiot/operationbackend/service/facade/AccountFansService.java
  5. 10 1
      operation-backend/src/main/java/com/idiot/operationbackend/service/facade/AccountPushService.java
  6. 15 8
      operation-backend/src/main/java/com/idiot/operationbackend/service/facade/FansActionStatService.java
  7. 11 0
      operation-backend/src/main/java/com/idiot/operationbackend/service/facade/FollowReplyService.java
  8. 41 1
      operation-backend/src/main/java/com/idiot/operationbackend/service/facade/WeChatService.java
  9. 7 2
      operation-backend/src/main/java/com/idiot/operationbackend/service/impl/AccountFansServiceImpl.java
  10. 8 0
      operation-backend/src/main/java/com/idiot/operationbackend/service/impl/AccountPushServiceImpl.java
  11. 1 2
      operation-backend/src/main/java/com/idiot/operationbackend/service/impl/AccountStatServiceImpl.java
  12. 104 24
      operation-backend/src/main/java/com/idiot/operationbackend/service/impl/EventMessageServiceImpl.java
  13. 7 0
      operation-backend/src/main/java/com/idiot/operationbackend/service/impl/FansActionStatServiceImpl.java
  14. 8 1
      operation-backend/src/main/java/com/idiot/operationbackend/service/impl/FollowReplyServiceImpl.java
  15. 56 0
      operation-backend/src/main/java/com/idiot/operationbackend/service/impl/ImageMessageServiceImpl.java
  16. 12 9
      operation-backend/src/main/java/com/idiot/operationbackend/service/impl/TextMessageServiceImpl.java
  17. 109 7
      operation-backend/src/main/java/com/idiot/operationbackend/service/impl/WeChatServiceImpl.java
  18. 1 0
      operation-backend/src/main/java/com/idiot/operationbackend/support/Constants.java
  19. 60 0
      operation-backend/src/main/java/com/idiot/operationbackend/support/ScanQrInfo.java

+ 5 - 1
operation-backend/src/main/java/com/idiot/operationbackend/controller/WeChatController.java

@@ -50,6 +50,9 @@ public class WeChatController {
     @Autowired
     private WeChatService weChatService;
 
+    @Autowired
+    private AccountService accountService;
+
 
     @GetMapping("preAuth")
     @ApiOperation(value = "获取预授权码地址,微信认证公众号")
@@ -164,7 +167,8 @@ public class WeChatController {
         logger.info("接受微信事件回调,postData after decry :{}",postData);
         Map<String,String> xmlMap =  weChatService.xmlToMap(postData);
         String msgType = xmlMap.get("MsgType");
-        xmlMap.put("appId",appid);
+        Account account =  accountService.queryByAppId(appid);
+        xmlMap.put("accountId",account.getId());
         WeChatMessageService messageService = WeChatMessageFactory.getService(msgType);
         if (Objects.isNull(messageService)) {
             logger.error("接受到消息暂无处理类处理:{}",msgType);

+ 13 - 0
operation-backend/src/main/java/com/idiot/operationbackend/entity/FansActionStat.java

@@ -2,6 +2,9 @@ package com.idiot.operationbackend.entity;
 
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.idiot.operationbackend.support.Constants;
+
+import java.time.LocalDateTime;
 
 /**
  * 粉丝动作统计
@@ -61,4 +64,14 @@ public class FansActionStat {
     public void setCreateTime(Long createTime) {
         this.createTime = createTime;
     }
+
+    public FansActionStat() {
+    }
+
+    public FansActionStat(String accountId, String openId, Integer action) {
+        this.accountId = accountId;
+        this.openId = openId;
+        this.action = action;
+        this.createTime = LocalDateTime.now().toEpochSecond(Constants.DEFAULT_ZONE);
+    }
 }

+ 88 - 0
operation-backend/src/main/java/com/idiot/operationbackend/handler/ScanQrHandler.java

@@ -0,0 +1,88 @@
+package com.idiot.operationbackend.handler;
+
+import com.idiot.operationbackend.controller.WeChatController;
+import com.idiot.operationbackend.service.facade.WeChatService;
+import com.idiot.operationbackend.support.ScanQrInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayDeque;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ *  扫描二维码 处理器
+ * @author wangxiao
+ * @date 18:04 2020/9/24
+ */
+@Component
+public class ScanQrHandler implements InitializingBean {
+
+    @Autowired
+    private WeChatService weChatService;
+
+    private final ArrayDeque<ScanQrInfo> SCAN_QUEUE = new ArrayDeque<ScanQrInfo>(16);
+
+    private final Logger logger = LoggerFactory.getLogger(WeChatController.class);
+
+    public  boolean addElement (String accountId,String openId,String qrCodeId,String contents) {
+        ScanQrInfo scanQrInfo = new ScanQrInfo(accountId,openId,qrCodeId,contents);
+        return SCAN_QUEUE.offerFirst(scanQrInfo);
+    }
+    /**
+     *  末尾元素添加
+     * @author wangxiao
+     * @date 18:03 2020/9/24
+     * @return com.idiot.operationbackend.support.ScanQrInfo
+     */
+    public ScanQrInfo getElement (){
+        return SCAN_QUEUE.pollLast();
+    }
+    /**
+     *  是否时空
+     * @author wangxiao
+     * @date 18:04 2020/9/24
+     * @return boolean
+     */
+    public  boolean isEmpty () {
+        return SCAN_QUEUE.isEmpty();
+    }
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        logger.info("扫描二维码推送信息单线程服务---------------->start");
+        Executors.newSingleThreadExecutor().execute(this::expire);
+        logger.info("扫描二维码推送信息单线程服务------------------>end");
+    }
+
+
+
+    private void expire () {
+        while(true) {
+            try {
+                if (isEmpty()) {
+                    TimeUnit.SECONDS.sleep(15);
+                }
+                ScanQrInfo scanQrInfo = getElement();
+                if (Objects.nonNull(scanQrInfo)) {
+                    String openId = scanQrInfo.getOpenId();
+                    String accountId = scanQrInfo.getAccountId();
+                    String qrCodeId = scanQrInfo.getQrCodeId();
+                    String contents = scanQrInfo.getQrContents();
+                    logger.warn("扫描二维码推送信息,qrCodeId:{},openId:{},accountId:{}----->start",qrCodeId,openId,accountId);
+                    weChatService.processScanQrCode(accountId,openId,qrCodeId,contents);
+                    logger.warn("扫描二维码推送信息,qrCodeId:{},openId:{},accountId:{}------>end",qrCodeId,openId,accountId);
+                }
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+                break;
+            }
+        }
+    }
+}

+ 39 - 29
operation-backend/src/main/java/com/idiot/operationbackend/service/facade/AccountFansService.java

@@ -18,8 +18,8 @@ public interface AccountFansService extends IService<AccountFans> {
      *  openId和公众号id  查询用户
      * @author wangxiao
      * @date 18:59 2020/9/14
-     * @param accountId
-     * @param openId
+     * @param accountId accountId
+     * @param openId openId
      * @return com.idiot.operationbackend.entity.AccountFans
      */
     AccountFans queryByAccountIdAndOpenId (String accountId,String openId);
@@ -39,9 +39,9 @@ public interface AccountFansService extends IService<AccountFans> {
      *  查询一段时间内的粉丝
      * @author wangxiao
      * @date 18:39 2020/9/16
-     * @param accountId
-     * @param startDate
-     * @param endDate
+     * @param accountId accountId
+     * @param startDate startDate
+     * @param endDate endDate
      * @return java.util.List<com.idiot.operationbackend.entity.AccountFans>
      */
     List<AccountFans> queryFansByDateAndDate (String accountId,String startDate,String endDate);
@@ -51,9 +51,9 @@ public interface AccountFansService extends IService<AccountFans> {
      *  粉丝属性得统计
      * @author wangxiao
      * @date 11:03 2020/9/17
-     * @param accountId
-     * @param startDate
-     * @param endDate
+     * @param accountId accountId
+     * @param startDate startDate
+     * @param endDate endDate
      * @return java.util.List<com.idiot.operationbackend.vo.NumberStatData>
      */
     List<NumberStatData> statByFansProperty (String accountId,String startDate,String endDate);
@@ -63,16 +63,16 @@ public interface AccountFansService extends IService<AccountFans> {
      *  粉丝列表
      * @author wangxiao
      * @date 19:18 2020/9/17
-     * @param accountId
-     * @param sex
-     * @param city
-     * @param province
-     * @param tagId
-     * @param label
-     * @param startTime
-     * @param endTime
-     * @param page
-     * @param pageSize
+     * @param accountId accountId
+     * @param sex sex
+     * @param city city
+     * @param province province
+     * @param tagId tagId
+     * @param label label
+     * @param startTime startTime
+     * @param endTime endTime
+     * @param page page
+     * @param pageSize pageSize
      * @return com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.idiot.operationbackend.entity.AccountFans>
      */
     Page<AccountFans> pageFans(String accountId,Integer sex, String city,String province,String tagId,String label,String startTime,String endTime ,int page,int pageSize );
@@ -81,9 +81,9 @@ public interface AccountFansService extends IService<AccountFans> {
      *  更新备注
      * @author wangxiao
      * @date 19:42 2020/9/17
-     * @param accountId
-     * @param openId
-     * @param remark
+     * @param accountId accountId
+     * @param openId openId
+     * @param remark remark
      * @return boolean
      */
     boolean updateFansRemark(String accountId, String openId, String remark);
@@ -93,9 +93,9 @@ public interface AccountFansService extends IService<AccountFans> {
      *  用户标签里面 添加元素
      * @author wangxiao
      * @date 9:53 2020/9/18 
-     * @param openIds
-     * @param accountId
-     * @param wxId
+     * @param openIds openIds
+     * @param accountId accountId
+     * @param wxId wxId
      * @return boolean
      */
     boolean addItemForTagList(List<String> openIds,String accountId,int wxId);
@@ -105,9 +105,9 @@ public interface AccountFansService extends IService<AccountFans> {
      *  移除标签
      * @author wangxiao
      * @date 10:07 2020/9/18
-     * @param openIds
-     * @param accountId
-     * @param wxId
+     * @param openIds openIds
+     * @param accountId accountId
+     * @param wxId wxId
      * @return boolean
      */
     boolean removeItemForTagList(List<String> openIds,String accountId,int wxId);
@@ -118,8 +118,8 @@ public interface AccountFansService extends IService<AccountFans> {
      *  查询粉丝
      * @author wangxiao
      * @date 15:26 2020/9/18
-     * @param openIds
-     * @param accountId
+     * @param openIds openIds
+     * @param accountId accountId
      * @return java.util.List<com.idiot.operationbackend.entity.AccountFans>
      */
     List<AccountFans> queryAccountFans(List<String> openIds,String accountId);
@@ -138,4 +138,14 @@ public interface AccountFansService extends IService<AccountFans> {
      * @return java.util.List<com.idiot.operationbackend.entity.AccountFans>
      */
     List<AccountFans> queryAccountFans(String accountId,Integer sex,String province,String city,String tags,String subscribeTime);
+
+
+    /**
+     *  取关
+     * @author wangxiao
+     * @date 20:21 2020/9/24
+     * @param accountId accountId
+     * @param openId openId
+     */
+    void unsubscribe(String accountId,String openId);
 }

+ 10 - 1
operation-backend/src/main/java/com/idiot/operationbackend/service/facade/AccountPushService.java

@@ -15,10 +15,19 @@ public interface AccountPushService extends IService<AccountPush> {
      *  查询公告号推送
      * @author wangxiao
      * @date 17:31 2020/9/18
-     * @param accountIds
+     * @param accountIds accountIds
      * @return java.util.List<com.idiot.operationbackend.entity.AccountPush>
      */
     List<AccountPush> queryAccountPush(List<String> accountIds);
 
 
+
+    /**
+     *  查询智能推送 (理论上只有一条)
+     * @author wangxiao
+     * @date 19:55 2020/9/24
+     * @param accountId accountId
+     * @return com.idiot.operationbackend.entity.AccountPush
+     */
+    AccountPush queryAccountPush (String accountId);
 }

+ 15 - 8
operation-backend/src/main/java/com/idiot/operationbackend/service/facade/FansActionStatService.java

@@ -41,10 +41,9 @@ public interface FansActionStatService extends IService<FansActionStat> {
 
     /**
      * 查询区间内 粉丝活跃数量 (秒级时间戳)
-     *
-     * @param accountId
-     * @param startDate
-     * @param endDate
+     * @param accountId accountId
+     * @param startDate startDate
+     * @param endDate endDate
      * @return int
      * @author wangxiao
      * @date 11:39 2020/9/16
@@ -55,13 +54,21 @@ public interface FansActionStatService extends IService<FansActionStat> {
 
     /**
      * 查询区间内 粉丝活跃数量 (秒级时间戳)
-     *
-     * @param accountId
-     * @param start
-     * @param end
+     * @param accountId accountId
+     * @param start start
+     * @param end end
      * @return int
      * @author wangxiao
      * @date 11:39 2020/9/16
      */
     List<FansActionStat> queryFansActionStat(String accountId, long start, long end);
+
+    /**
+     *  保存多条
+     * @author wangxiao
+     * @date 18:47 2020/9/24
+     * @param params params
+     * @return boolean
+     */
+    boolean saveBatchFansActionStat (FansActionStat ...params);
 }

+ 11 - 0
operation-backend/src/main/java/com/idiot/operationbackend/service/facade/FollowReplyService.java

@@ -19,4 +19,15 @@ public interface FollowReplyService extends IService<FollowReply> {
      * @return java.util.List<com.idiot.operationbackend.entity.FollowReply>
      */
     List<FollowReply> queryFollowReply(List<String> ids);
+
+
+
+    /**
+     * 查询智能回复 (按道理只有一条)
+     * @author wangxiao
+     * @date 19:31 2020/9/24
+     * @param accountId accountId
+     * @return com.idiot.operationbackend.entity.FollowReply
+     */
+    FollowReply queryFollowReplyByAccountId (String accountId);
 }

+ 41 - 1
operation-backend/src/main/java/com/idiot/operationbackend/service/facade/WeChatService.java

@@ -10,9 +10,11 @@ import org.springframework.util.StringUtils;
 
 import java.io.File;
 import java.io.InputStream;
+import java.time.LocalTime;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * 微信处理
@@ -201,7 +203,7 @@ public interface WeChatService {
    * @param startDate  开始日期
    * @return java.lang.String
    */
-  String getFansSunmmary(String accountId,String startDate,String endDate);
+  String getFansSummary(String accountId, String startDate, String endDate);
 
 
   /**
@@ -380,6 +382,44 @@ public interface WeChatService {
    void doCustomerMsgTask (CustomerMsg customerMsg);
 
 
+   /**
+    *  处理扫描二维码
+    * @author wangxiao
+    * @date 18:23 2020/9/24
+    * @param accountId 公众号id
+    * @param openId 用户
+    * @param qrCodeId 二维码id
+    * @param contents 二维码内容
+    */
+   void processScanQrCode (String accountId,String openId,String qrCodeId,String contents);
+
+
+
+   /**
+    *  发送消息
+    * @author wangxiao
+    * @date 19:49 2020/9/24
+    * @param accountId accountId
+    * @param openId openId
+    * @param nikeName  nikeName
+    * @param content content
+    * @return void
+    */
+   void sendMessage (String accountId,String openId,String nikeName,String content);
+
+
+
+   /**
+    *  推送智能推送
+    * @author wangxiao
+    * @date 20:42 2020/9/24
+    * @param accountId accountId
+    * @param openId openId
+    * @param index index
+    */
+   void sendPushMessage(String accountId, String openId, int index);
+
+
   /**
    * 不支持的消息
    * @author wangxiao

+ 7 - 2
operation-backend/src/main/java/com/idiot/operationbackend/service/impl/AccountFansServiceImpl.java

@@ -78,7 +78,7 @@ public class AccountFansServiceImpl extends ServiceImpl<AccountFansMapper, Accou
     public Page<AccountFans> pageFans(String accountId, Integer sex, String city, String province, String tagId, String label, String startTime, String endTime, int page, int pageSize) {
         Page<AccountFans> queryPage = new Page<>(page,pageSize);
         LambdaQueryWrapper<AccountFans> queryWrapper = Wrappers.lambdaQuery();
-        queryWrapper.eq(AccountFans::getAccountId,accountId);
+        queryWrapper.eq(AccountFans::getAccountId,accountId).eq(AccountFans::getState,"1");
         if (Objects.nonNull(sex)) {
             queryWrapper.eq(AccountFans::getSex,sex);
         }
@@ -171,6 +171,7 @@ public class AccountFansServiceImpl extends ServiceImpl<AccountFansMapper, Accou
         }
        return list(Wrappers.<AccountFans>lambdaQuery()
                .eq(AccountFans::getAccountId,accountId)
+               .eq(AccountFans::getState,"1")
                .in(AccountFans::getOpenId,openIds));
     }
 
@@ -214,5 +215,9 @@ public class AccountFansServiceImpl extends ServiceImpl<AccountFansMapper, Accou
     }
 
 
-
+    @Override
+    public void unsubscribe(String accountId, String openId) {
+        update(Wrappers.<AccountFans>lambdaUpdate().set(AccountFans::getState,0)
+                .eq(AccountFans::getAccountId,accountId).eq(AccountFans::getOpenId,openId));
+    }
 }

+ 8 - 0
operation-backend/src/main/java/com/idiot/operationbackend/service/impl/AccountPushServiceImpl.java

@@ -22,4 +22,12 @@ public class AccountPushServiceImpl extends ServiceImpl<AccountPushMapper, Accou
     public List<AccountPush> queryAccountPush(List<String> accountIds) {
         return list(Wrappers.<AccountPush>lambdaQuery().in(AccountPush::getAccountId,accountIds));
     }
+
+
+    @Override
+    public AccountPush queryAccountPush(String accountId) {
+        return getOne(Wrappers.<AccountPush>lambdaQuery()
+                .eq(AccountPush::getAccountId,accountId)
+                .eq(AccountPush::getEnable,1),false);
+    }
 }

+ 1 - 2
operation-backend/src/main/java/com/idiot/operationbackend/service/impl/AccountStatServiceImpl.java

@@ -16,7 +16,6 @@ import org.springframework.stereotype.Service;
 
 import java.time.LocalDate;
 import java.time.LocalDateTime;
-import java.time.LocalTime;
 import java.util.List;
 
 /**
@@ -58,7 +57,7 @@ public class AccountStatServiceImpl extends ServiceImpl<AccountStatMapper, Accou
     public void statAccountFansData(String accountId) {
         String yesterday = Constants.DATE_FORMATTER.format(LocalDate.now().plusDays(-1));
         String beforeDay = Constants.DATE_FORMATTER.format(LocalDate.now().plusDays(-2));
-        String jsonStr = weChatService.getFansSunmmary(accountId,yesterday,yesterday);
+        String jsonStr = weChatService.getFansSummary(accountId,yesterday,yesterday);
         JSONObject jsonObject = JSONObject.parseObject(jsonStr);
         JSONArray jsonArray = jsonObject.getJSONArray("list");
         int size  = jsonArray.size();

+ 104 - 24
operation-backend/src/main/java/com/idiot/operationbackend/service/impl/EventMessageServiceImpl.java

@@ -2,17 +2,24 @@ package com.idiot.operationbackend.service.impl;
 
 
 
+import com.idiot.operationbackend.entity.*;
+import com.idiot.operationbackend.handler.ScanQrHandler;
 import com.idiot.operationbackend.handler.WeChatMessageFactory;
-import com.idiot.operationbackend.service.facade.WeChatMessageService;
+import com.idiot.operationbackend.service.facade.*;
 import com.idiot.operationbackend.support.Constants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 
+import java.time.LocalTime;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.function.Function;
 
 /**
@@ -24,28 +31,28 @@ import java.util.function.Function;
 public class EventMessageServiceImpl implements WeChatMessageService {
 
 
+    private final Logger logger = LoggerFactory.getLogger(EventMessageServiceImpl.class);
 
+    @Autowired
+    private QrCodeService qrCodeService;
 
-    private final Logger logger = LoggerFactory.getLogger(EventMessageServiceImpl.class);
+    @Autowired
+    private ScanQrHandler scanQrHandler;
 
+    @Autowired
+    private FollowReplyService followReplyService;
 
-    @Override
-    public void afterPropertiesSet()  {
+    @Autowired
+    private FansActionStatService fansActionStatService;
 
-        logger.info("微信消息,事件处理类--------------->正在初始化");
-        synchronized (eventMap) {
-            eventMap.put("subscribe",this::subscribeEvent);
-            eventMap.put("SCAN",this::scanEvent);
-            eventMap.put("LOCATION",this::locationEvent);
-            eventMap.put("CLICK",this::clickEvent);
-            eventMap.put("VIEW",this::viewEvent);
-        }
-        logger.info("微信消息,事件处理类--------------->初始化完成");
-        WeChatMessageFactory.addService("event",this);
+    @Autowired
+    private WeChatService weChatService;
 
-    }
 
 
+    @Autowired
+    private AccountFansService fansService;
+
     @Override
     public String processMessage(Map<String, String> param) {
         String eventType = param.get("Event");
@@ -70,14 +77,34 @@ public class EventMessageServiceImpl implements WeChatMessageService {
     private String subscribeEvent (Map<String,String> param) {
         logger.info("********************* param is {}*****************",param.toString());
         String key = param.get("EventKey");
-        if (StringUtils.isEmpty(key)) {
-            param.put("Content","欢迎关注中德智慧教育科技");
-            return unSupportedMessage(param);
+        String accountId = param.get("accountId");
+        String openId = param.get("FromUserName");
+        if (!StringUtils.isEmpty(key)) {
+            logger.info("********************* 扫描二维码 关注 *****************");
+            key = key.replace("qrscene_","");
+            QrCode qrCode = qrCodeService.getById(key);
+            if (Objects.nonNull(qrCode)) {
+                qrCode.setNewNum(qrCode.getNewNum()+1);
+                qrCode.setTotalNum(qrCode.getTotalNum()+1);
+                qrCodeService.updateById(qrCode);
+                scanQrHandler.addElement(accountId,openId,key,qrCode.getContent());
+            }
+            return Constants.SUCCESS;
         }
-        key = key.replace("qrscene_","");
-        logger.info("************** subscribe Received weChat  event key : {} ****************",key);
-
+        FansActionStat var2 = new FansActionStat(accountId,openId,2);
+        fansActionStatService.saveBatchFansActionStat(var2);
+        // 关注事件
+        FollowReply followReply = followReplyService.queryFollowReplyByAccountId(accountId);
+        if (Objects.nonNull(followReply)) {
+           // 设置了关注回复
+            logger.info("********************* 设置了关注回复 *****************");
+            weChatService.sendMessage(accountId,openId,"",followReply.getContents());
+            return Constants.SUCCESS;
+        }
+        // 是否有智能推送
+        weChatService.sendPushMessage(accountId,openId,0);
         return Constants.SUCCESS;
+
     }
 
 
@@ -91,10 +118,17 @@ public class EventMessageServiceImpl implements WeChatMessageService {
      */
     private String scanEvent (Map<String,String> param) {
         String key = param.get("EventKey");
-        if (StringUtils.isEmpty(key)) {
-            return unSupportedMessage(param);
+        String accountId = param.get("accountId");
+        String openId = param.get("FromUserName");
+        if (!StringUtils.isEmpty(key)) {
+            logger.info("************** SCAN Received weChat  event key : {} ****************",key);
+            QrCode qrCode = qrCodeService.getById(key);
+            qrCode.setFollowNum(qrCode.getFollowNum()+1);
+            qrCode.setTotalNum(qrCode.getTotalNum()+1);
+            qrCodeService.updateById(qrCode);
+            scanQrHandler.addElement(accountId,openId,key,qrCode.getContent());
+            return Constants.SUCCESS;
         }
-        logger.info("************** SCAN Received weChat  event key : {} ****************",key);
         return Constants.SUCCESS;
     }
     
@@ -124,6 +158,11 @@ public class EventMessageServiceImpl implements WeChatMessageService {
     private String clickEvent (Map<String,String> param) {
         String key = param.get("EventKey");
         logger.info("************** CLICK Received weChat  event key : {} ****************",key);
+        String accountId = param.get("accountId");
+        String openId = param.get("FromUserName");
+        FansActionStat var2 = new FansActionStat(accountId,openId,5);
+        fansActionStatService.saveBatchFansActionStat(var2);
+        weChatService.sendPushMessage(accountId,openId,2);
         return Constants.SUCCESS;
     }
 
@@ -138,7 +177,48 @@ public class EventMessageServiceImpl implements WeChatMessageService {
     private String viewEvent (Map<String,String> param) {
         String key = param.get("EventKey");
         logger.info("************** VIEW Received weChat  event key : {} ****************",key);
+        String accountId = param.get("accountId");
+        String openId = param.get("FromUserName");
+        FansActionStat var2 = new FansActionStat(accountId,openId,5);
+        fansActionStatService.saveBatchFansActionStat(var2);
+        return Constants.SUCCESS;
+    }
+
+    /**
+     *  取关事件
+     * @author wangxiao
+     * @date 20:17 2020/9/24
+     * @param param param
+     * @return java.lang.String
+     */
+    private String unsubscribeEvent(Map<String,String> param) {
+        logger.info("************** unsubscribe Received weChat   ****************");
+        String accountId = param.get("accountId");
+        String openId = param.get("FromUserName");
+        FansActionStat var2 = new FansActionStat(accountId,openId,3);
+        fansActionStatService.saveBatchFansActionStat(var2);
+        fansService.unsubscribe(accountId,openId);
         return Constants.SUCCESS;
     }
 
+
+    @Override
+    public void afterPropertiesSet()  {
+        logger.info("微信消息,事件处理类--------------->正在初始化");
+        synchronized (eventMap) {
+            eventMap.put("subscribe",this::subscribeEvent);
+            eventMap.put("SCAN",this::scanEvent);
+            eventMap.put("LOCATION",this::locationEvent);
+            eventMap.put("CLICK",this::clickEvent);
+            eventMap.put("VIEW",this::viewEvent);
+            eventMap.put("unsubscribe",this::unsubscribeEvent);
+        }
+        logger.info("微信消息,事件处理类--------------->初始化完成");
+        WeChatMessageFactory.addService("event",this);
+
+    }
+
+
+
+
 }

+ 7 - 0
operation-backend/src/main/java/com/idiot/operationbackend/service/impl/FansActionStatServiceImpl.java

@@ -10,7 +10,9 @@ import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
 
+import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * @author wang xiao
@@ -58,4 +60,9 @@ public class FansActionStatServiceImpl extends ServiceImpl<FansActionStatMapper,
                 .le(FansActionStat::getCreateTime,end)
                 .orderByAsc(FansActionStat::getCreateTime));
     }
+
+    @Override
+    public boolean saveBatchFansActionStat(FansActionStat... params) {
+        return saveBatch(Arrays.stream(params).collect(Collectors.toList()));
+    }
 }

+ 8 - 1
operation-backend/src/main/java/com/idiot/operationbackend/service/impl/FollowReplyServiceImpl.java

@@ -19,6 +19,13 @@ public class FollowReplyServiceImpl extends ServiceImpl<FollowReplyMapper, Follo
 
     @Override
     public List<FollowReply> queryFollowReply(List<String> ids) {
-        return list(Wrappers.<FollowReply>lambdaQuery().in(FollowReply::getAccountId,ids));
+        return list(Wrappers.<FollowReply>lambdaQuery().eq(FollowReply::getEnable,"1").in(FollowReply::getAccountId,ids));
+    }
+
+    @Override
+    public FollowReply queryFollowReplyByAccountId(String accountId) {
+        return getOne(Wrappers.<FollowReply>lambdaQuery()
+                .eq(FollowReply::getEnable,"1")
+                .eq(FollowReply::getAccountId,accountId),false);
     }
 }

+ 56 - 0
operation-backend/src/main/java/com/idiot/operationbackend/service/impl/ImageMessageServiceImpl.java

@@ -0,0 +1,56 @@
+package com.idiot.operationbackend.service.impl;
+
+import com.idiot.operationbackend.entity.FansActionStat;
+import com.idiot.operationbackend.entity.FansMsg;
+import com.idiot.operationbackend.handler.WeChatMessageFactory;
+import com.idiot.operationbackend.service.facade.FansActionStatService;
+import com.idiot.operationbackend.service.facade.FansMsgService;
+import com.idiot.operationbackend.service.facade.WeChatMessageService;
+import com.idiot.operationbackend.service.facade.WeChatService;
+import com.idiot.operationbackend.support.Constants;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.Map;
+
+/**
+ * @author wang xiao
+ * @date Created in 20:43 2020/9/24
+ */
+public class ImageMessageServiceImpl  implements WeChatMessageService {
+
+    @Autowired
+    private FansMsgService fansMsgService;
+
+    @Autowired
+    private WeChatService weChatService;
+
+    @Autowired
+    private FansActionStatService fansActionStatService;
+
+    @Override
+    public String processMessage(Map<String, String> param) {
+        String accountId = param.get("accountId");
+        String openId = param.get("FromUserName");
+        String content = param.get("Content");
+        String msgId = param.get("MsgId");
+        String fromUserName = param.get(openId);
+        String createTime = param.get("CreateTime");
+        FansMsg fansMsg = new FansMsg();
+        fansMsg.setAccountId(accountId);
+        fansMsg.setCreateTime(Long.parseLong(createTime));
+        fansMsg.setContent(content);
+        fansMsg.setFromUserName(fromUserName);
+        fansMsg.setMsgId(msgId);
+        fansMsg.setMsgType("image");
+        fansMsgService.save(fansMsg);
+        FansActionStat var2 = new FansActionStat(accountId,openId,0);
+        fansActionStatService.saveBatchFansActionStat(var2);
+        weChatService.sendPushMessage(accountId,openId,1);
+        return Constants.SUCCESS;
+    }
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        WeChatMessageFactory.addService("image",this);
+    }
+}

+ 12 - 9
operation-backend/src/main/java/com/idiot/operationbackend/service/impl/TextMessageServiceImpl.java

@@ -3,11 +3,10 @@ package com.idiot.operationbackend.service.impl;
 
 
 import com.idiot.operationbackend.entity.Account;
+import com.idiot.operationbackend.entity.FansActionStat;
 import com.idiot.operationbackend.entity.FansMsg;
 import com.idiot.operationbackend.handler.WeChatMessageFactory;
-import com.idiot.operationbackend.service.facade.AccountService;
-import com.idiot.operationbackend.service.facade.FansMsgService;
-import com.idiot.operationbackend.service.facade.WeChatMessageService;
+import com.idiot.operationbackend.service.facade.*;
 import com.idiot.operationbackend.support.Constants;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -26,26 +25,30 @@ public class TextMessageServiceImpl implements WeChatMessageService {
     private FansMsgService fansMsgService;
 
     @Autowired
-    private AccountService accountService;
+    private WeChatService weChatService;
 
+    @Autowired
+    private FansActionStatService fansActionStatService;
 
     @Override
     public String processMessage(Map<String, String> param) {
-        String appId = param.get("appId");
-        Account account =  accountService.queryByAppId(appId);
+        String accountId = param.get("accountId");
+        String openId = param.get("FromUserName");
         String content = param.get("Content");
         String msgId = param.get("MsgId");
-        String fromUserName = param.get("FromUserName");
+        String fromUserName = param.get(openId);
         String createTime = param.get("CreateTime");
         FansMsg fansMsg = new FansMsg();
-        fansMsg.setAccountId(appId);
+        fansMsg.setAccountId(accountId);
         fansMsg.setCreateTime(Long.parseLong(createTime));
-        fansMsg.setAccountId(account.getId());
         fansMsg.setContent(content);
         fansMsg.setFromUserName(fromUserName);
         fansMsg.setMsgId(msgId);
         fansMsg.setMsgType("text");
         fansMsgService.save(fansMsg);
+        FansActionStat var2 = new FansActionStat(accountId,openId,0);
+        fansActionStatService.saveBatchFansActionStat(var2);
+        weChatService.sendPushMessage(accountId,openId,1);
         return Constants.SUCCESS;
     }
 

+ 109 - 7
operation-backend/src/main/java/com/idiot/operationbackend/service/impl/WeChatServiceImpl.java

@@ -11,6 +11,7 @@ import com.idiot.operationbackend.handler.FansInfoHandler;
 import com.idiot.operationbackend.service.facade.*;
 import com.idiot.operationbackend.support.Constants;
 import com.idiot.operationbackend.support.CustomException;
+import com.idiot.operationbackend.support.ScanQrInfo;
 import com.idiot.operationbackend.support.WxInputStreamResource;
 import com.idiot.operationbackend.support.wechat.AesException;
 import com.idiot.operationbackend.support.wechat.WXBizMsgCrypt;
@@ -28,6 +29,7 @@ import org.springframework.web.client.RestTemplate;
 
 import javax.annotation.Resource;
 import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
@@ -76,6 +78,10 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
 
     private AccountCustomerMsgService accountCustomerMsgService;
 
+    private FansActionStatService fansActionStatService;
+
+    private AccountPushService accountPushService;
+
     @Override
     public String notice(Map<String, String> param) {
         if (Objects.isNull(param)) {
@@ -411,7 +417,7 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
     }
 
     @Override
-    public String getFansSunmmary(String accountId,String startDate,String endDate) {
+    public String getFansSummary(String accountId, String startDate, String endDate) {
         String requestUrl = "https://api.weixin.qq.com/datacube/getusersummary?access_token=%s";
         String accessToken = getAuthorizerAccessToken(accountId);
         requestUrl = String.format(requestUrl,accessToken);
@@ -799,6 +805,84 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
     }
 
 
+    @Override
+    public void processScanQrCode(String accountId, String openId, String qrCodeId, String contents) {
+        /**
+         * 先保存新用户
+         */
+        AccountFans accountFans = fansService.queryByAccountIdAndOpenId(accountId,openId);
+        JSONObject fansObject = JSON.parseObject(getFansInfo(accountId,openId));
+        accountFans.setAccountId(accountId);
+        accountFans.setOpenId(openId);
+        accountFans.setNickName(fansObject.getString("nickname"));
+        accountFans.setHeadImgUrl(fansObject.getString("headimgurl"));
+        accountFans.setSex(fansObject.getInteger("sex"));
+        accountFans.setSubscribe(fansObject.getInteger("subscribe"));
+        accountFans.setCity(fansObject.getString("city"));
+        accountFans.setProvince(fansObject.getString("province"));
+        accountFans.setSubscribeTime(fansObject.getLong("subscribe_time"));
+        accountFans.setSubscribeScene(fansObject.getString("subscribe_scene"));
+        accountFans.setUnionId(fansObject.getString("unionid"));
+        accountFans.setRemark(fansObject.getString("remark"));
+        accountFans.setGroupId(fansObject.getInteger("groupid"));
+        accountFans.setTagIdList(JSONObject.toJSONString(fansObject.getJSONArray("tagid_list")));
+        accountFans.setTags(accountFans.initTags());
+        fansService.saveOrUpdate(accountFans);
+        Account account = accountService.getById(accountId);
+        account.setFansNum(account.getFansNum()+1);
+        accountService.updateById(account);
+        FansActionStat var1 = new FansActionStat(accountId,openId,1);
+        FansActionStat var2 = new FansActionStat(accountId,openId,4);
+        fansActionStatService.saveBatchFansActionStat(var1,var2);
+        String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s";
+        sendCustomerMessage(openId,contents,accountFans.getNickName(),accountId,url);
+    }
+
+
+    @Override
+    public void sendMessage(String accountId, String openId, String nikeName, String content) {
+        content = content.replace("<粉丝昵称>",nikeName);
+        JSONArray jsonArray = JSONArray.parseArray(content);
+        int size = jsonArray.size();
+        if (size == 0) {
+            return;
+        }
+        String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=%s";
+        String accessToken = getAuthorizerAccessToken(accountId);
+        url = String.format(url,accessToken);
+        JSONObject temp  = null;
+        for (int i = 0; i < size; i++) {
+            temp = jsonArray.getJSONObject(i);
+            String param = parseJson(openId,temp);
+            logger.info("微信客服消息,单人第{}条发送,accountId:{},openId:{}----start,时间:{}",i,accountId,openId,LocalDateTime.now());
+            HttpHeaders  headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_JSON);
+            HttpEntity<String> request = new HttpEntity<>(param, headers);
+            String jsonStr = restTemplate.postForObject(url,request,String.class);
+            logger.info("微信客服消息,单人第{}条发送,accountId:{},openId:{}----end,时间:{},微信返回:{}",i,accountId,openId,LocalDateTime.now(),jsonStr);
+        }
+    }
+
+    @Override
+    public void sendPushMessage(String accountId, String openId, int index) {
+        AccountPush accountPush = accountPushService.queryAccountPush(accountId);
+        AccountFans fans = fansService.queryByAccountIdAndOpenId(accountId, openId);
+        if (Objects.nonNull(accountPush)) {
+            int trigger = accountPush.getTrigger();
+            LocalTime localTime = LocalTime.now();
+            if (!StringUtils.isEmpty(accountPush.getQuiet())) {
+                String first = String.valueOf(String.valueOf(trigger).charAt(index));
+                LocalTime start = LocalTime.parse(accountPush.getQuiet().split("-")[0]);
+                LocalTime end = LocalTime.parse(accountPush.getQuiet().split("-")[1]);
+                if (localTime.isAfter(start) && localTime.isBefore(end) && Constants.FIRST.equals(first)) {
+                    logger.info("********************* 设置了智能回复且第{}位时 1 在安静时间内 *****************", index);
+                } else if (Constants.FIRST.equals(first)) {
+                    sendMessage(accountId, openId, fans.getNickName(), accountPush.getContents());
+                }
+            }
+            ;
+        }
+    }
 
     /**
      *  群发消息
@@ -877,7 +961,16 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
         return templateCount;
     }
 
-
+    /**
+     *  批量发送客服消息
+     * @author wangxiao
+     * @date 18:26 2020/9/24
+     * @param accountId accountId
+     * @param fansList fansList
+     * @param contents contents
+     * @param url url
+     * @return long 发送人员数目
+     */
     public long sendCustomerMessage (String accountId,List<AccountFans> fansList,String contents,String url) {
         int result = 0;
         if (CollectionUtils.isEmpty(fansList)) {
@@ -901,11 +994,10 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
      *  单人 发送客服消息消息
      * @author wangxiao
      * @date 15:20 2020/9/24
-     * @param openId
-     * @param nikeName
-     * @param contents
-     * @param url
-     * @return void
+     * @param openId openId
+     * @param nikeName nikeName
+     * @param contents contents
+     * @param url url
      */
     private void sendCustomerMessage(String openId,String contents,String nikeName,String accountId,String url) {
         contents = contents.replace("<粉丝昵称>",nikeName);
@@ -1145,4 +1237,14 @@ public class WeChatServiceImpl implements WeChatService, InitializingBean {
     public void setAccountCustomerMsgService(AccountCustomerMsgService accountCustomerMsgService) {
         this.accountCustomerMsgService = accountCustomerMsgService;
     }
+
+    @Autowired
+    public void setFansActionStatService(FansActionStatService fansActionStatService) {
+        this.fansActionStatService = fansActionStatService;
+    }
+
+    @Autowired
+    public void setAccountPushService(AccountPushService accountPushService) {
+        this.accountPushService = accountPushService;
+    }
 }

+ 1 - 0
operation-backend/src/main/java/com/idiot/operationbackend/support/Constants.java

@@ -14,6 +14,7 @@ public class Constants {
 
     public static final String SUCCESS = "success";
     public static final String FAIL = "fail";
+    public static final String FIRST = "1";
 
     public static final Locale DEFAULT_LOCALE = Locale.CHINA;
 

+ 60 - 0
operation-backend/src/main/java/com/idiot/operationbackend/support/ScanQrInfo.java

@@ -0,0 +1,60 @@
+package com.idiot.operationbackend.support;
+
+/**
+ * @author wang xiao
+ * @date Created in 17:58 2020/9/24
+ */
+public class ScanQrInfo {
+
+    private String openId;
+
+    private String accountId;
+
+    private String qrCodeId;
+
+    private String qrContents;
+
+    public ScanQrInfo() {
+    }
+
+    public ScanQrInfo(String accountId,String openId, String qrCodeId, String qrContents) {
+        this.openId = openId;
+        this.accountId = accountId;
+        this.qrCodeId = qrCodeId;
+        this.qrContents = qrContents;
+    }
+
+    public String getOpenId() {
+        return openId;
+    }
+
+    public void setOpenId(String openId) {
+        this.openId = openId;
+    }
+
+    public String getAccountId() {
+        return accountId;
+    }
+
+    public void setAccountId(String accountId) {
+        this.accountId = accountId;
+    }
+
+    public String getQrCodeId() {
+        return qrCodeId;
+    }
+
+    public void setQrCodeId(String qrCodeId) {
+        this.qrCodeId = qrCodeId;
+    }
+
+    public String getQrContents() {
+        return qrContents;
+    }
+
+    public void setQrContents(String qrContents) {
+        this.qrContents = qrContents;
+    }
+
+
+}