♻️ Refactoring code. 微信管理

This commit is contained in:
冷冷 committed 2020-04-27 18:36:55 +08:00
1 parent b864c748b6
commit 3af4a03e10
35 files changed
+1393 -686

No files matched your search

+1 -1
View File
@@ -23,7 +23,7 @@
<druid.version>1.1.21</druid.version>
<mysql.connector.version>8.0.19</mysql.connector.version>
<swagger.core.version>1.5.22</swagger.core.version>
<mp.weixin.version>3.6.0</mp.weixin.version>
<mp.weixin.version>3.7.0</mp.weixin.version>
<ijpay.version>1.2.0</ijpay.version>
<fastjson.version>1.2.67</fastjson.version>
<aliyun.version>3.0.52.ALL</aliyun.version>
@@ -0,0 +1,35 @@
package com.pig4cloud.pigx.mp.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author lengleng
* @date 2020/4/25
* <p>
* 消息类型
*/
@Getter
@AllArgsConstructor
public enum MsgTypeEnum {
/**
* 用户发给公众号
*/
USER2MP("1", "用户发给公众号"),
/**
* 公众号发给用户
*/
MP2USER("2", "公众号发给用户");
/***
* 类型
*/
private String type;
/**
* 描述
*/
private String desc;
}
@@ -0,0 +1,36 @@
package com.pig4cloud.pigx.mp.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author lengleng
* @date 2020/4/25
* <p>
* 匹配类型
*/
@Getter
@AllArgsConstructor
public enum ReplyMateEnum {
/**
* 完全匹配
*/
ALL("1", "完全匹配"),
/**
* 半匹配
*/
LIKE("2", "半匹配");
/***
* 类型
*/
private String type;
/**
* 描述
*/
private String desc;
}
@@ -0,0 +1,56 @@
package com.pig4cloud.pigx.mp.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author lengleng
* @date 2020/4/25
* <p>
* 回复类型
*/
@Getter
@AllArgsConstructor
public enum ReplyTypeEnum {
/**
* 关注自动回复
*/
ATTENTION("1", "关注时回复"),
/**
* 用户消息回复
*/
MSG("2", "消息回复"),
/**
* 关键字回复
*/
KEYWORD("3", "关键词回复");
/***
* 类型
*/
private String type;
/**
* 描述
*/
private String desc;
/**
* 根据 type 查找枚举
*
* @param type
* @return
*/
public static ReplyTypeEnum getEnumByType(String type) {
for (ReplyTypeEnum value : ReplyTypeEnum.values()) {
if (value.getType().equals(type)) {
return value;
}
}
return null;
}
}
@@ -0,0 +1,35 @@
package com.pig4cloud.pigx.mp.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author lengleng
* @date 2020/4/26
* <p>
* 公众号订阅状态
*/
@Getter
@AllArgsConstructor
public enum SubStatusEnum {
/**
* 已关注
*/
SUBED("1", "已关注"),
/**
* 未关注
*/
UNSUB("0", "关注");
/***
* 类型
*/
private String type;
/**
* 描述
*/
private String desc;
}
@@ -0,0 +1,123 @@
package com.pig4cloud.pigx.mp.controller;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.mp.constant.ReplyTypeEnum;
import com.pig4cloud.pigx.mp.entity.WxAutoReply;
import com.pig4cloud.pigx.mp.service.WxAutoReplyService;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 消息自动回复
*
* @author JL
* @date 2019-04-18 15:40:39
*/
@RestController
@AllArgsConstructor
@RequestMapping("/wxautoreply")
public class WxAutoReplyController {
private final WxAutoReplyService wxAutoReplyService;
/**
* 分页查询
*
* @param page 分页对象
* @param wxAutoReply 消息自动回复
* @return
*/
@GetMapping("/page")
public R getWxAutoReplyPage(Page page, WxAutoReply wxAutoReply) {
return R.ok(wxAutoReplyService.page(page, Wrappers.query(wxAutoReply)));
}
/**
* 通过id查询消息自动回复
*
* @param id id
* @return R
*/
@GetMapping("/{id}")
public R getById(@PathVariable("id") String id) {
return R.ok(wxAutoReplyService.getById(id));
}
/**
* 新增消息自动回复
*
* @param wxAutoReply 消息自动回复
* @return R
*/
@PostMapping
public R save(@RequestBody WxAutoReply wxAutoReply) {
this.jude(wxAutoReply);
return R.ok(wxAutoReplyService.save(wxAutoReply));
}
/**
* 修改消息自动回复
*
* @param wxAutoReply 消息自动回复
* @return R
*/
@PutMapping
public R updateById(@RequestBody WxAutoReply wxAutoReply) {
this.jude(wxAutoReply);
return R.ok(wxAutoReplyService.updateById(wxAutoReply));
}
/**
* 通过id删除消息自动回复
*
* @param id id
* @return R
*/
@DeleteMapping("/{id}")
public R removeById(@PathVariable String id) {
return R.ok(wxAutoReplyService.removeById(id));
}
/**
* //校验参数
*
* @param wxAutoReply
*/
public void jude(WxAutoReply wxAutoReply) {
if (ReplyTypeEnum.MSG.getType().equals(wxAutoReply.getType())) {
Wrapper<WxAutoReply> queryWrapper = Wrappers.<WxAutoReply>lambdaQuery()
.eq(WxAutoReply::getReqType, wxAutoReply.getReqType());
List<WxAutoReply> list = wxAutoReplyService.list(queryWrapper);
if (wxAutoReply.getId() != null) {
if (list != null && list.size() == 1) {
if (!list.get(0).getId().equals(wxAutoReply.getId())) {
throw new RuntimeException("请求消息类型重复");
}
}
if (list != null && list.size() > 1) {
throw new RuntimeException("请求消息类型重复");
}
}
}
if (ReplyTypeEnum.KEYWORD.getType().equals(wxAutoReply.getType())) {
Wrapper<WxAutoReply> queryWrapper = Wrappers.<WxAutoReply>lambdaQuery()
.eq(WxAutoReply::getReqKey, wxAutoReply.getReqKey())
.eq(WxAutoReply::getRepType, wxAutoReply.getRepMate());
List<WxAutoReply> list = wxAutoReplyService.list(queryWrapper);
if (list != null && list.size() == 1) {
if (!list.get(0).getId().equals(wxAutoReply.getId())) {
throw new RuntimeException("关键词重复");
}
}
if (list != null && list.size() > 1) {
throw new RuntimeException("关键词重复");
}
}
}
}
@@ -16,17 +16,32 @@
*/
package com.pig4cloud.pigx.mp.controller;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.mp.entity.WxFansMsg;
import com.pig4cloud.pigx.mp.service.WxFansMsgService;
import com.pig4cloud.pigx.mp.config.WxMpConfiguration;
import com.pig4cloud.pigx.mp.constant.MsgTypeEnum;
import com.pig4cloud.pigx.mp.entity.WxAccountFans;
import com.pig4cloud.pigx.mp.entity.WxMsg;
import com.pig4cloud.pigx.mp.service.WxAccountFansService;
import com.pig4cloud.pigx.mp.service.WxMsgService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpKefuService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* 微信粉丝消息管理
@@ -34,77 +49,154 @@ import org.springframework.web.bind.annotation.*;
* @author lengleng
* @date 2019-03-27 20:45:27
*/
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/wxfansmsg")
public class WxFansMsgController {
private final WxFansMsgService wxFansMsgService;
private final WxAccountFansService wxAccountFansService;
private final WxMsgService wxMsgService;
/**
* 分页查询
*
* @param page 分页对象
* @param wxFansMsg 消息
* @return
* @param page 分页对象
* @param msg 查询条件
*/
@GetMapping("/page")
public R getWxFansMsgPage(Page page, WxFansMsg wxFansMsg) {
wxFansMsg.setTenantId(TenantContextHolder.getTenantId());
return R.ok(wxFansMsgService.page(page, Wrappers.query(wxFansMsg)));
public R getWxMsgPage(Page page, WxMsg msg) {
return R.ok(wxMsgService.page(page, Wrappers.query(msg)));
}
/**
* 通过id查询消息
* 通过id查询微信消息
*
* @param id id
* @return R
*/
@GetMapping("/{id}")
public R getById(@PathVariable("id") Integer id) {
return R.ok(wxFansMsgService.getById(id));
return R.ok(wxMsgService.getById(id));
}
/**
* 新增消息
* 新增微信消息
*
* @param wxFansMsg 消息
* @param wxMsg 微信消息
* @return R
*/
@SysLog("新增消息")
@PostMapping
@PreAuthorize("@pms.hasPermission('mp_wxfansmsg_add')")
public R save(@RequestBody WxFansMsg wxFansMsg) {
wxFansMsg.setTenantId(TenantContextHolder.getTenantId());
return R.ok(wxFansMsgService.save(wxFansMsg));
public R save(@RequestBody WxMsg wxMsg) {
try {
WxAccountFans wxUser = wxAccountFansService.getById(wxMsg.getWxUserId());
//入库
wxMsg.setNickName(wxUser.getNickname());
wxMsg.setHeadimgUrl(wxUser.getHeadimgUrl());
wxMsg.setCreateTime(LocalDateTime.now());
wxMsg.setType(MsgTypeEnum.MP2USER.getType());
WxMpKefuMessage wxMpKefuMessage = null;
if (WxConsts.KefuMsgType.TEXT.equals(wxMsg.getRepType())) {
wxMsg.setRepContent(wxMsg.getRepContent());
wxMpKefuMessage = WxMpKefuMessage.TEXT().build();
wxMpKefuMessage.setContent(wxMsg.getRepContent());
}
if (WxConsts.KefuMsgType.IMAGE.equals(wxMsg.getRepType())) {//图片
wxMsg.setRepName(wxMsg.getRepName());
wxMsg.setRepUrl(wxMsg.getRepUrl());
wxMsg.setRepMediaId(wxMsg.getRepMediaId());
wxMpKefuMessage = WxMpKefuMessage.IMAGE().build();
wxMpKefuMessage.setMediaId(wxMsg.getRepMediaId());
}
if (WxConsts.KefuMsgType.VOICE.equals(wxMsg.getRepType())) {
wxMsg.setRepName(wxMsg.getRepName());
wxMsg.setRepUrl(wxMsg.getRepUrl());
wxMsg.setRepMediaId(wxMsg.getRepMediaId());
wxMpKefuMessage = WxMpKefuMessage.VOICE().build();
wxMpKefuMessage.setMediaId(wxMsg.getRepMediaId());
}
if (WxConsts.KefuMsgType.VIDEO.equals(wxMsg.getRepType())) {
wxMsg.setRepName(wxMsg.getRepName());
wxMsg.setRepDesc(wxMsg.getRepDesc());
wxMsg.setRepUrl(wxMsg.getRepUrl());
wxMsg.setRepMediaId(wxMsg.getRepMediaId());
wxMpKefuMessage = WxMpKefuMessage.VIDEO().build();
wxMpKefuMessage.setMediaId(wxMsg.getRepMediaId());
wxMpKefuMessage.setTitle(wxMsg.getRepName());
wxMpKefuMessage.setDescription(wxMsg.getRepDesc());
}
if (WxConsts.KefuMsgType.MUSIC.equals(wxMsg.getRepType())) {
wxMsg.setRepName(wxMsg.getRepName());
wxMsg.setRepDesc(wxMsg.getRepDesc());
wxMsg.setRepUrl(wxMsg.getRepUrl());
wxMsg.setRepHqUrl(wxMsg.getRepHqUrl());
wxMpKefuMessage = WxMpKefuMessage.MUSIC().build();
wxMpKefuMessage.setTitle(wxMsg.getRepName());
wxMpKefuMessage.setDescription(wxMsg.getRepDesc());
wxMpKefuMessage.setMusicUrl(wxMsg.getRepUrl());
wxMpKefuMessage.setHqMusicUrl(wxMsg.getRepHqUrl());
wxMpKefuMessage.setThumbMediaId(wxMsg.getRepThumbMediaId());
}
if (WxConsts.KefuMsgType.NEWS.equals(wxMsg.getRepType())) {
List<WxMpKefuMessage.WxArticle> list = new ArrayList<>();
JSONArray jSONArray = JSONUtil.parseObj(wxMsg.getContent()).getJSONArray("articles");
WxMpKefuMessage.WxArticle t;
for (Object object : jSONArray) {
JSONObject jSONObject = JSONUtil.parseObj(JSONUtil.toJsonStr(object));
t = new WxMpKefuMessage.WxArticle();
t.setTitle(jSONObject.getStr("title"));
t.setDescription(jSONObject.getStr("digest"));
t.setPicUrl(jSONObject.getStr("thumbUrl"));
t.setUrl(jSONObject.getStr("url"));
list.add(t);
}
wxMsg.setRepName(wxMsg.getRepName());
wxMsg.setRepDesc(wxMsg.getRepDesc());
wxMsg.setRepUrl(wxMsg.getRepUrl());
wxMsg.setRepMediaId(wxMsg.getRepMediaId());
wxMsg.setContent(wxMsg.getContent());
wxMpKefuMessage = WxMpKefuMessage.NEWS().build();
wxMpKefuMessage.setArticles(list);
}
if (wxMpKefuMessage != null) {
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(wxMsg.getAppId());
WxMpKefuService wxMpKefuService = wxMpService.getKefuService();
wxMpKefuMessage.setToUser(wxUser.getOpenid());
wxMpKefuService.sendKefuMessage(wxMpKefuMessage);
wxMsgService.save(wxMsg);
return R.ok(wxMsg);
} else {
return R.failed("非法消息类型");
}
} catch (WxErrorException e) {
e.printStackTrace();
log.error("新增微信消息失败" + e.getMessage());
return R.failed(e.getMessage());
}
}
/**
* 修改消息
* 修改微信消息
*
* @param wxFansMsg 消息
* @param wxMsg 微信消息
* @return R
*/
@SysLog("修改消息")
@PutMapping
@PreAuthorize("@pms.hasPermission('mp_wxfansmsg_edit')")
public R updateById(@RequestBody WxFansMsg wxFansMsg) {
wxFansMsg.setTenantId(TenantContextHolder.getTenantId());
return R.ok(wxFansMsgService.updateById(wxFansMsg));
@PreAuthorize("@ss.hasPermi('wxmp:wxmsg:edit')")
public R updateById(@RequestBody WxMsg wxMsg) {
return R.ok(wxMsgService.updateById(wxMsg));
}
/**
* 通过id删除消息
* 通过id删除微信消息
*
* @param id id
* @return R
*/
@SysLog("删除消息")
@DeleteMapping("/{id}")
@PreAuthorize("@pms.hasPermission('mp_wxfansmsg_del')")
public R removeById(@PathVariable Integer id) {
return R.ok(wxFansMsgService.removeById(id));
@PreAuthorize("@ss.hasPermi('wxmp:wxmsg:del')")
public R removeById(@PathVariable String id) {
return R.ok(wxMsgService.removeById(id));
}
}
@@ -1,106 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.mp.controller;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.mp.entity.WxFansMsgRes;
import com.pig4cloud.pigx.mp.service.WxFansMsgResService;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
/**
* 微信粉丝消息回复管理
*
* @author lengleng
* @date 2019-03-27 20:45:48
*/
@RestController
@AllArgsConstructor
@RequestMapping("/wxfansmsgres")
public class WxFansMsgResController {
private final WxFansMsgResService wxFansMsgResService;
/**
* 分页查询
*
* @param page 分页对象
* @param wxFansMsgRes 回复
* @return
*/
@GetMapping("/page")
public R getWxFansMsgResPage(Page page, WxFansMsgRes wxFansMsgRes) {
return R.ok(wxFansMsgResService.page(page, Wrappers.query(wxFansMsgRes)));
}
/**
* 通过id查询回复
*
* @param id id
* @return R
*/
@GetMapping("/{id}")
public R getById(@PathVariable("id") Integer id) {
return R.ok(wxFansMsgResService.getById(id));
}
/**
* 新增回复
*
* @param wxFansMsgRes 回复
* @return R
*/
@SysLog("新增回复")
@PostMapping
@PreAuthorize("@pms.hasPermission('mp_wxfansmsgres_add')")
public R save(@RequestBody WxFansMsgRes wxFansMsgRes) {
return wxFansMsgResService.saveAndSend(wxFansMsgRes);
}
/**
* 修改回复
*
* @param wxFansMsgRes 回复
* @return R
*/
@SysLog("修改回复")
@PutMapping
@PreAuthorize("@pms.hasPermission('mp_wxfansmsgres_edit')")
public R updateById(@RequestBody WxFansMsgRes wxFansMsgRes) {
return R.ok(wxFansMsgResService.updateById(wxFansMsgRes));
}
/**
* 通过id删除回复
*
* @param id id
* @return R
*/
@SysLog("删除回复")
@DeleteMapping("/{id}")
@PreAuthorize("@pms.hasPermission('mp_wxfansmsgres_del')")
public R removeById(@PathVariable Integer id) {
return R.ok(wxFansMsgResService.removeById(id));
}
}
@@ -0,0 +1,288 @@
package com.pig4cloud.pigx.mp.controller;
import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.mp.config.WxMpConfiguration;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpMaterialService;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.material.*;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 微信素材
*
* @author JL
* @date 2019-03-23 21:26:35
*/
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/wxmaterial")
public class WxMaterialController {
/**
* 上传非图文微信素材
*
* @param mulFile
* @param mediaType
* @return
*/
@PostMapping("/materialFileUpload")
public R materialFileUpload(@RequestParam("file") MultipartFile mulFile,
@RequestParam String appId,
@RequestParam("title") String title,
@RequestParam("introduction") String introduction,
@RequestParam("mediaType") String mediaType) {
try {
WxMpMaterial material = new WxMpMaterial();
material.setName(mulFile.getOriginalFilename());
if (WxConsts.MediaFileType.VIDEO.equals(mediaType)) {
material.setVideoTitle(title);
material.setVideoIntroduction(introduction);
}
File file = FileUtil.newFile(FileUtil.getTmpDirPath() + mulFile.getOriginalFilename());
mulFile.transferTo(file);
material.setFile(file);
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
WxMpMaterialUploadResult wxMpMaterialUploadResult = wxMpMaterialService.materialFileUpload(mediaType, material);
WxMpMaterialFileBatchGetResult.WxMaterialFileBatchGetNewsItem wxMpMaterialFileBatchGetResult = new WxMpMaterialFileBatchGetResult.WxMaterialFileBatchGetNewsItem();
wxMpMaterialFileBatchGetResult.setName(file.getName());
wxMpMaterialFileBatchGetResult.setMediaId(wxMpMaterialUploadResult.getMediaId());
wxMpMaterialFileBatchGetResult.setUrl(wxMpMaterialUploadResult.getUrl());
FileUtil.del(file);
return R.ok(wxMpMaterialFileBatchGetResult);
} catch (WxErrorException e) {
log.warn("上传非图文微信素材失败: {}", e.getLocalizedMessage());
return R.failed(e.getLocalizedMessage());
} catch (Exception e) {
log.error("上传失败", e);
return R.failed(e.getLocalizedMessage());
}
}
/**
* 新增图文消息
*
* @param data
* @return
*/
@PostMapping("/materialNews")
public R materialNewsUpload(@RequestBody JSONObject data) {
try {
JSONArray jSONArray = data.getJSONArray("articles");
List<WxMpMaterialNews.WxMpMaterialNewsArticle> articles = jSONArray.toList(WxMpMaterialNews.WxMpMaterialNewsArticle.class);
WxMpMaterialNews news = new WxMpMaterialNews();
news.setArticles(articles);
String appId = data.getStr("appId");
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
WxMpMaterialUploadResult wxMpMaterialUploadResult = wxMpMaterialService.materialNewsUpload(news);
return R.ok(wxMpMaterialUploadResult);
} catch (WxErrorException e) {
log.warn("新增图文失败: {}", e.getMessage());
return R.failed(e.getMessage());
} catch (Exception e) {
log.error("新增图文失败", e);
return R.failed(e.getLocalizedMessage());
}
}
/**
* 修改图文消息
*
* @param data
* @return
*/
@PutMapping("/materialNews")
public R materialNewsUpdate(@RequestBody JSONObject data) {
try {
String mediaId = data.getStr("mediaId");
JSONArray jSONArray = data.getJSONArray("articles");
List<WxMpMaterialNews.WxMpMaterialNewsArticle> articles = jSONArray.toList(WxMpMaterialNews.WxMpMaterialNewsArticle.class);
String appId = data.getStr("appId");
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate = new WxMpMaterialArticleUpdate();
wxMpMaterialArticleUpdate.setMediaId(mediaId);
int index = 0;
for (WxMpMaterialNews.WxMpMaterialNewsArticle article : articles) {
wxMpMaterialArticleUpdate.setIndex(index);
wxMpMaterialArticleUpdate.setArticles(article);
wxMpMaterialService.materialNewsUpdate(wxMpMaterialArticleUpdate);
index++;
}
return R.ok();
} catch (WxErrorException e) {
log.warn("修改图文失败:{}", e.getLocalizedMessage());
return R.failed(e.getLocalizedMessage());
} catch (Exception e) {
log.error("修改图文失败", e);
return R.failed(e.getLocalizedMessage());
}
}
/**
* 上传图文消息内的图片获取URL
*
* @param mulFile
* @return
*/
@PostMapping("/newsImgUpload")
public String newsImgUpload(@RequestParam("file") MultipartFile mulFile, @RequestParam String appId) throws Exception {
File file = FileUtil.createTempFile(FileUtil.getTmpDir());
mulFile.transferTo(file);
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
WxMediaImgUploadResult wxMediaImgUploadResult = wxMpMaterialService.mediaImgUpload(file);
Map<Object, Object> responseData = new HashMap<>();
responseData.put("link", wxMediaImgUploadResult.getUrl());
FileUtil.del(file);
return JSONUtil.toJsonStr(responseData);
}
/**
* 通过id删除微信素材
*
* @param
* @return R
*/
@DeleteMapping
public R materialDel(String appId, String id) {
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
try {
return R.ok(wxMpMaterialService.materialDelete(id));
} catch (WxErrorException e) {
log.error("删除微信素材失败", e);
return R.failed(e.getMessage());
}
}
/**
* 分页查询
*
* @param page 分页对象
* @param type
* @return
*/
@GetMapping("/page")
public R getWxMaterialPage(Page page, String type, String appId) {
try {
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
int count = (int) page.getSize();
int offset = (int) page.getCurrent() * count - count;
if (WxConsts.MaterialType.NEWS.equals(type)) {
return R.ok(wxMpMaterialService.materialNewsBatchGet(offset, count));
} else {
return R.ok(wxMpMaterialService.materialFileBatchGet(type, offset, count));
}
} catch (WxErrorException e) {
log.error("查询素材失败", e);
return R.failed(e.getLocalizedMessage());
}
}
/**
* 获取微信视频素材
*
* @param
* @return R
*/
@GetMapping("/materialVideo")
public R getMaterialVideo(String mediaId, String appId) {
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
try {
return R.ok(wxMpMaterialService.materialVideoInfo(mediaId));
} catch (WxErrorException e) {
log.error("获取微信视频素材失败", e);
return R.failed(e.getMessage());
}
}
/**
* 获取微信素材直接文件
*
* @param
* @return R
*/
@GetMapping("/materialOther")
public ResponseEntity<byte[]> getMaterialOther(String appId, String mediaId, String fileName) throws Exception {
try {
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
//获取文件
InputStream is = wxMpMaterialService.materialImageOrVoiceDownload(mediaId);
byte[] body = new byte[is.available()];
is.read(body);
HttpHeaders headers = new HttpHeaders();
//设置文件类型
headers.add("Content-Disposition", "attchement;filename=" + URLEncoder.encode(fileName, "UTF-8"));
headers.add("Content-Type", "application/octet-stream");
HttpStatus statusCode = HttpStatus.OK;
//返回数据
ResponseEntity<byte[]> entity = new ResponseEntity<>(body, headers, statusCode);
return entity;
} catch (WxErrorException e) {
e.printStackTrace();
log.error("获取微信素材直接文件失败", e);
return null;
}
}
/**
* 获取微信临时素材直接文件
*
* @param
* @return R
*/
@GetMapping("/tempMaterialOther")
public ResponseEntity<byte[]> getTempMaterialOther(String appId, String mediaId, String fileName) throws Exception {
try {
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
//获取文件
InputStream is = new FileInputStream(wxMpMaterialService.mediaDownload(mediaId));
byte[] body = new byte[is.available()];
is.read(body);
HttpHeaders headers = new HttpHeaders();
//设置文件类型
headers.add("Content-Disposition", "attchement;filename=" + URLEncoder.encode(fileName, "UTF-8"));
headers.add("Content-Type", "application/octet-stream");
HttpStatus statusCode = HttpStatus.OK;
//返回数据
ResponseEntity<byte[]> entity = new ResponseEntity<>(body, headers, statusCode);
return entity;
} catch (WxErrorException e) {
e.printStackTrace();
log.error("获取微信素材直接文件失败", e);
return null;
}
}
}
@@ -17,11 +17,8 @@
package com.pig4cloud.pigx.mp.controller;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.mp.entity.WxMpMenu;
import com.pig4cloud.pigx.mp.service.WxMenuService;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -41,18 +38,6 @@ public class WxMenuController {
private final WxMenuService wxMenuService;
/**
* 分页查询
*
* @param page 分页对象
* @param wxMpMenu
* @return
*/
@GetMapping("/page")
public R getWxMpMenuPage(Page page, WxMpMenu wxMpMenu) {
return R.ok(wxMenuService.page(page, Wrappers.query(wxMpMenu)));
}
/**
* 通过appid查询微信菜单
@@ -95,6 +80,4 @@ public class WxMenuController {
public R delete(@PathVariable("appId") String appId) {
return wxMenuService.delete(appId);
}
}
@@ -1,10 +1,15 @@
package com.pig4cloud.pigx.mp.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.common.security.annotation.Inner;
import com.pig4cloud.pigx.mp.config.WxMpConfiguration;
import com.pig4cloud.pigx.mp.config.WxMpContextHolder;
import com.pig4cloud.pigx.mp.entity.WxAccount;
import com.pig4cloud.pigx.mp.service.WxAccountService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
@@ -21,8 +26,10 @@ import org.springframework.web.bind.annotation.*;
@Slf4j
@Inner(value = false)
@RestController
@AllArgsConstructor
@RequestMapping("/{appId}/portal")
public class WxPortalController {
private final WxAccountService accountService;
/**
* 微信接入校验处理
@@ -82,6 +89,9 @@ public class WxPortalController {
@RequestParam(name = "encrypt_type", required = false) String encType,
@RequestParam(name = "msg_signature", required = false) String msgSignature) {
WxAccount wxAccount = accountService.getOne(Wrappers.<WxAccount>lambdaQuery()
.eq(WxAccount::getAppid, appId));
TenantContextHolder.setTenantId(wxAccount.getTenantId());
WxMpContextHolder.setAppId(appId);
final WxMpService wxService = WxMpConfiguration.getMpServices().get(appId);
@@ -1,37 +0,0 @@
package com.pig4cloud.pigx.mp.controller;
import com.pig4cloud.pigx.mp.config.WxMpConfiguration;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author Edward
*/
@Controller
@RequestMapping("/wx/redirect/{appid}")
public class WxRedirectController {
@RequestMapping("/greet")
public String greetUser(@PathVariable String appid, @RequestParam String code, ModelMap map) {
WxMpService mpService = WxMpConfiguration.getMpServices().get(appid);
try {
WxMpOAuth2AccessToken accessToken = mpService.oauth2getAccessToken(code);
WxMpUser user = mpService.oauth2getUserInfo(accessToken, null);
map.put("user", user);
} catch (WxErrorException e) {
e.printStackTrace();
}
return "greet_user";
}
}
@@ -0,0 +1,117 @@
package com.pig4cloud.pigx.mp.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
/**
* 消息自动回复
*
* @author JL
* @date 2019-04-18 15:40:39
*/
@Data
@TableName("wx_auto_reply")
@EqualsAndHashCode(callSuper = true)
public class WxAutoReply extends Model<WxAutoReply> {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId
private Integer id;
/**
* 公众号ID
*/
private String appId;
/**
* 创建者
*/
private String createId;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新者
*/
private String updateId;
/**
* 更新时间
*/
private LocalDateTime updateTime;
/**
* 备注
*/
private String remark;
/**
* 逻辑删除标记(0:显示;1:隐藏)
*/
private String delFlag;
/**
* 类型(1、关注时回复;2、消息回复;3、关键词回复)
*/
@NotNull(message = "类型不能为空")
private String type;
/**
* 关键词
*/
private String reqKey;
/**
* 请求消息类型(text:文本;image:图片;voice:语音;video:视频;shortvideo:小视频;location:地理位置)
*/
private String reqType;
/**
* 回复消息类型(text:文本;image:图片;voice:语音;video:视频;music:音乐;news:图文)
*/
@NotNull(message = "回复消息类型不能为空")
private String repType;
/**
* 回复类型文本匹配类型(1、全匹配,2、半匹配)
*/
private String repMate;
/**
* 回复类型文本保存文字
*/
private String repContent;
/**
* 回复的素材名、视频和音乐的标题
*/
private String repName;
/**
* 回复类型imge、voice、news、video的mediaID或音乐缩略图的媒体id
*/
private String repMediaId;
/**
* 视频和音乐的描述
*/
private String repDesc;
/**
* 链接
*/
private String repUrl;
/**
* 高质量链接
*/
private String repHqUrl;
/**
* 缩略图的媒体id
*/
private String repThumbMediaId;
/**
* 缩略图url
*/
private String repThumbUrl;
/**
* 图文消息的内容
*/
private String content;
}
@@ -1,123 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.mp.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
/**
* 微信消息
*
* @author lengleng
* @date 2019-03-27 20:45:27
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class WxFansMsg extends Model<WxFansMsg> {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId
private Integer id;
/**
* 用户标识
*/
private String openid;
/**
* 昵称
*/
private String nickname;
/**
* 头像地址
*/
private String headimgUrl;
/**
* 微信账号ID
*/
private Integer wxAccountId;
/**
* 微信公众号appid
*/
private String wxAccountAppid;
/**
* 微信公众号名
*/
private String wxAccountName;
/**
* 消息ID
*/
private Long msgId;
/**
* 消息类型
*/
private String msgType;
/**
* 内容
*/
private String content;
/**
* 最近一条回复内容
*/
private String resContent;
/**
* 是否已回复
*/
private String isRes;
/**
* 微信素材ID
*/
private String mediaId;
/**
* 微信图片URL
*/
private String picUrl;
/**
* 本地图片路径
*/
private String picPath;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
/**
* 是否删除 -1:已删除 0:正常
*/
@TableLogic
private String delFlag;
/**
* 租户
*/
private Integer tenantId;
}
@@ -0,0 +1,149 @@
package com.pig4cloud.pigx.mp.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
/**
* 微信消息
*
* @author JL
* @date 2019-05-28 16:12:10
*/
@Data
@TableName("wx_msg")
@EqualsAndHashCode(callSuper = true)
@ApiModel(description = "微信消息")
public class WxMsg extends Model<WxMsg> {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId
private Integer id;
/**
* 创建者
*/
private String createId;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新者
*/
private String updateId;
/**
* 更新时间
*/
private LocalDateTime updateTime;
/**
* 备注
*/
private String remark;
/**
* 逻辑删除标记(0:显示;1:隐藏)
*/
private String delFlag;
/***
* 公众号ID
*/
private String appId;
/**
* 公众号名称
*/
private String appName;
/**
* 公众号logo
*/
private String appLogo;
/**
* 微信用户ID
*/
private Integer wxUserId;
/**
* 昵称
*/
private String nickName;
/**
* 头像
*/
private String headimgUrl;
/**
* 微信openId
*/
private String openId;
/**
* 消息分类(1、用户发给公众号;2、公众号发给用户;)
*/
private String type;
/**
* 消息类型(text:文本;image:图片;voice:语音;video:视频;shortvideo:小视频;location:地理位置;music:音乐;news:图文;event:推送事件)
*/
private String repType;
/**
* 事件类型(subscribe:关注;unsubscribe:取关;CLICK、VIEW:菜单事件)
*/
private String repEvent;
/**
* 回复类型文本保存文字
*/
private String repContent;
/**
* 回复类型imge、voice、news、video的mediaID或音乐缩略图的媒体id
*/
private String repMediaId;
/**
* 回复的素材名、视频和音乐的标题
*/
private String repName;
/**
* 视频和音乐的描述
*/
private String repDesc;
/**
* 链接
*/
private String repUrl;
/**
* 高质量链接
*/
private String repHqUrl;
/**
* 图文消息的内容
*/
private String content;
/**
* 缩略图的媒体id
*/
private String repThumbMediaId;
/**
* 缩略图url
*/
private String repThumbUrl;
/**
* 地理位置维度
*/
private Double repLocationX;
/**
* 地理位置经度
*/
private Double repLocationY;
/**
* 地图缩放大小
*/
private Double repScale;
/**
* 已读标记(0:是;1:否)
*/
private String readFlag;
}
@@ -1,10 +1,13 @@
package com.pig4cloud.pigx.mp.handler;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pig4cloud.pigx.mp.constant.MsgTypeEnum;
import com.pig4cloud.pigx.mp.entity.WxAccount;
import com.pig4cloud.pigx.mp.entity.WxFansMsg;
import com.pig4cloud.pigx.mp.service.WxAccountService;
import com.pig4cloud.pigx.mp.service.WxFansMsgService;
import com.pig4cloud.pigx.mp.entity.WxAccountFans;
import com.pig4cloud.pigx.mp.entity.WxMsg;
import com.pig4cloud.pigx.mp.mapper.WxAccountFansMapper;
import com.pig4cloud.pigx.mp.mapper.WxAccountMapper;
import com.pig4cloud.pigx.mp.mapper.WxMsgMapper;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@@ -13,9 +16,9 @@ import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Map;
/**
@@ -27,8 +30,9 @@ import java.util.Map;
@Component
@AllArgsConstructor
public class LogHandler extends AbstractHandler {
private final WxFansMsgService wxFansMsgService;
private final WxAccountService wxAccountService;
private final WxAccountFansMapper fansMapper;
private final WxAccountMapper accountMapper;
private final WxMsgMapper msgMapper;
@Override
@SneakyThrows
@@ -37,32 +41,57 @@ public class LogHandler extends AbstractHandler {
WxSessionManager sessionManager) {
log.debug("接收到请求消息,内容:{}", wxMessage.getContent());
if (!WxConsts.XmlMsgType.TEXT.equals(wxMessage.getMsgType())) {
log.debug("消息类型其他类型不保存", wxMessage.getContent());
return null;
}
WxAccount wxAccount = wxAccountService.getOne(Wrappers.<WxAccount>lambdaQuery()
WxAccount wxAccount = accountMapper.selectOne(Wrappers.<WxAccount>lambdaQuery()
.eq(WxAccount::getAccount, wxMessage.getToUser()));
WxAccountFans fans = fansMapper.selectOne(Wrappers.<WxAccountFans>lambdaQuery()
.eq(WxAccountFans::getOpenid, wxMessage.getFromUser()));
WxMpUser wxmpUser = wxMpService.getUserService()
.userInfo(wxMessage.getFromUser());
WxFansMsg wxFansMsg = new WxFansMsg();
wxFansMsg.setOpenid(wxmpUser.getOpenId());
wxFansMsg.setNickname(wxmpUser.getNickname());
wxFansMsg.setHeadimgUrl(wxmpUser.getHeadImgUrl());
wxFansMsg.setWxAccountId(wxAccount.getId());
wxFansMsg.setWxAccountName(wxAccount.getName());
wxFansMsg.setWxAccountAppid(wxAccount.getAppid());
wxFansMsg.setMsgType(wxMessage.getMsgType());
wxFansMsg.setMsgId(wxMessage.getMsgId());
wxFansMsg.setContent(wxMessage.getContent());
wxFansMsg.setTenantId(wxAccount.getTenantId());
wxFansMsgService.save(wxFansMsg);
log.debug("保存微信用户信息成功 {}", wxFansMsg);
WxMsg wxMsg = new WxMsg();
wxMsg.setWxUserId(fans.getId());
wxMsg.setNickName(fans.getNickname());
wxMsg.setHeadimgUrl(fans.getHeadimgUrl());
wxMsg.setType(MsgTypeEnum.USER2MP.getType());
wxMsg.setRepEvent(wxMessage.getEvent());
wxMsg.setRepType(wxMessage.getMsgType());
wxMsg.setRepMediaId(wxMessage.getMediaId());
wxMsg.setOpenId(fans.getOpenid());
wxMsg.setAppId(wxAccount.getAppid());
wxMsg.setAppLogo(wxAccount.getQrUrl());
wxMsg.setAppName(wxAccount.getName());
if (WxConsts.XmlMsgType.TEXT.equals(wxMessage.getMsgType())) {
wxMsg.setRepContent(wxMessage.getContent());
}
if (WxConsts.XmlMsgType.VOICE.equals(wxMessage.getMsgType())) {
wxMsg.setRepName(wxMessage.getMediaId() + "." + wxMessage.getFormat());
wxMsg.setRepContent(wxMessage.getRecognition());
}
if (WxConsts.XmlMsgType.IMAGE.equals(wxMessage.getMsgType())) {
wxMsg.setRepUrl(wxMessage.getPicUrl());
}
if (WxConsts.XmlMsgType.LINK.equals(wxMessage.getMsgType())) {
wxMsg.setRepName(wxMessage.getTitle());
wxMsg.setRepDesc(wxMessage.getDescription());
wxMsg.setRepUrl(wxMessage.getUrl());
}
if (WxConsts.MediaFileType.FILE.equals(wxMessage.getMsgType())) {
wxMsg.setRepName(wxMessage.getTitle());
wxMsg.setRepDesc(wxMessage.getDescription());
}
if (WxConsts.XmlMsgType.VIDEO.equals(wxMessage.getMsgType())) {
wxMsg.setRepThumbMediaId(wxMessage.getThumbMediaId());
}
if (WxConsts.XmlMsgType.LOCATION.equals(wxMessage.getMsgType())) {
wxMsg.setRepLocationX(wxMessage.getLocationX());
wxMsg.setRepLocationY(wxMessage.getLocationY());
wxMsg.setRepScale(wxMessage.getScale());
wxMsg.setRepContent(wxMessage.getLabel());
}
LocalDateTime now = LocalDateTime.now();
wxMsg.setCreateTime(now);
msgMapper.insert(wxMsg);
log.debug("保存微信用户信息成功 {}", wxMsg);
return null;
}
}
@@ -1,30 +1,192 @@
package com.pig4cloud.pigx.mp.handler;
import com.pig4cloud.pigx.mp.builder.TextBuilder;
import lombok.SneakyThrows;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pig4cloud.pigx.mp.config.WxMpContextHolder;
import com.pig4cloud.pigx.mp.constant.MsgTypeEnum;
import com.pig4cloud.pigx.mp.constant.ReplyMateEnum;
import com.pig4cloud.pigx.mp.constant.ReplyTypeEnum;
import com.pig4cloud.pigx.mp.entity.WxAccount;
import com.pig4cloud.pigx.mp.entity.WxAccountFans;
import com.pig4cloud.pigx.mp.entity.WxAutoReply;
import com.pig4cloud.pigx.mp.entity.WxMsg;
import com.pig4cloud.pigx.mp.mapper.WxAccountFansMapper;
import com.pig4cloud.pigx.mp.mapper.WxAccountMapper;
import com.pig4cloud.pigx.mp.mapper.WxMsgMapper;
import com.pig4cloud.pigx.mp.service.WxAutoReplyService;
import lombok.AllArgsConstructor;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutNewsMessage;
import me.chanjar.weixin.mp.builder.outxml.*;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
/**
* @author Binary Wang(https://github.com/binarywang)
* @author JL
*/
@Component
@AllArgsConstructor
public class MsgHandler extends AbstractHandler {
private final WxAutoReplyService wxAutoReplyService;
private final WxAccountFansMapper wxAccountFansMapper;
private final WxAccountMapper wxAccountMapper;
private final WxMsgMapper wxMsgMapper;
@Override
@SneakyThrows
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
Map<String, Object> context, WxMpService weixinService,
Map<String, Object> context, WxMpService wxMpService,
WxSessionManager sessionManager) {
String content = "收到信息内容:" + wxMessage.getContent();
return new TextBuilder().build(content, wxMessage, weixinService);
//组装回复消息
if (!wxMessage.getMsgType().equals(XmlMsgType.EVENT)) {
WxMpXmlOutMessage rs;
WxAccountFans fans = wxAccountFansMapper.selectOne(Wrappers.<WxAccountFans>lambdaQuery()
.eq(WxAccountFans::getOpenid, wxMessage.getFromUser()));
// 查询公众号 基本信息
WxAccount wxAccount = wxAccountMapper.selectOne(Wrappers.<WxAccount>lambdaQuery()
.eq(WxAccount::getAccount, wxMessage.getToUser()));
//1、先处理是否有文本关键字回复
if (WxConsts.KefuMsgType.TEXT.equals(wxMessage.getMsgType())) {
//先全匹配
List<WxAutoReply> listWxAutoReply = wxAutoReplyService.list(Wrappers
.<WxAutoReply>query().lambda()
.eq(WxAutoReply::getType, ReplyTypeEnum.KEYWORD.getType())
.eq(WxAutoReply::getRepMate, ReplyMateEnum.ALL.getType())
.eq(WxAutoReply::getAppId, WxMpContextHolder.getAppId())
.eq(WxAutoReply::getReqKey, wxMessage.getContent()));
if (listWxAutoReply != null && listWxAutoReply.size() > 0) {
rs = getWxMpXmlOutMessage(wxMessage, listWxAutoReply, fans, wxMsgMapper, wxAccount);
if (rs != null) {
return rs;
}
}
//再半匹配
listWxAutoReply = wxAutoReplyService.list(Wrappers
.<WxAutoReply>query().lambda()
.eq(WxAutoReply::getType, ReplyTypeEnum.KEYWORD.getType())
.eq(WxAutoReply::getAppId, WxMpContextHolder.getAppId())
.eq(WxAutoReply::getRepMate, ReplyMateEnum.LIKE.getType())
.like(WxAutoReply::getReqKey, wxMessage.getContent()));
if (listWxAutoReply != null && listWxAutoReply.size() > 0) {
rs = getWxMpXmlOutMessage(wxMessage, listWxAutoReply, fans, wxMsgMapper, wxAccount);
if (rs != null) {
return rs;
}
}
}
//2、再处理消息回复
List<WxAutoReply> listWxAutoReply = wxAutoReplyService.list(Wrappers
.<WxAutoReply>query().lambda()
.eq(WxAutoReply::getAppId, WxMpContextHolder.getAppId())
.eq(WxAutoReply::getType, ReplyTypeEnum.MSG.getType())
.eq(WxAutoReply::getReqType, wxMessage.getMsgType()));
rs = getWxMpXmlOutMessage(wxMessage, listWxAutoReply, fans, wxMsgMapper, wxAccount);
return rs;
}
return null;
}
/**
* 组装回复消息,并记录消息
*
* @param wxMessage
* @param listWxAutoReply
* @param wxMsgMapper
* @param wxAccount
* @return
*/
public static WxMpXmlOutMessage getWxMpXmlOutMessage(WxMpXmlMessage wxMessage
, List<WxAutoReply> listWxAutoReply, WxAccountFans fans, WxMsgMapper wxMsgMapper, WxAccount wxAccount) {
WxMpXmlOutMessage wxMpXmlOutMessage = null;
//记录接收消息
if (listWxAutoReply != null && listWxAutoReply.size() > 0) {
WxAutoReply wxAutoReply = listWxAutoReply.get(0);
//记录回复消息
WxMsg wxMsg = new WxMsg();
wxMsg.setWxUserId(fans.getId());
wxMsg.setNickName(fans.getNickname());
wxMsg.setHeadimgUrl(fans.getHeadimgUrl());
wxMsg.setCreateTime(LocalDateTime.now());
wxMsg.setType(MsgTypeEnum.MP2USER.getType());
wxMsg.setRepType(wxAutoReply.getRepType());
wxMsg.setOpenId(fans.getOpenid());
wxMsg.setAppName(wxAccount.getName());
wxMsg.setAppLogo(wxAccount.getQrUrl());
wxMsg.setAppId(wxAccount.getAppid());
//文本
if (WxConsts.KefuMsgType.TEXT.equals(wxAutoReply.getRepType())) {
wxMsg.setRepContent(wxAutoReply.getRepContent());
wxMpXmlOutMessage = new TextBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()).content(wxAutoReply.getRepContent()).build();
}
//图片
if (WxConsts.KefuMsgType.IMAGE.equals(wxAutoReply.getRepType())) {
wxMsg.setRepName(wxAutoReply.getRepName());
wxMsg.setRepUrl(wxAutoReply.getRepUrl());
wxMsg.setRepMediaId(wxAutoReply.getRepMediaId());
wxMpXmlOutMessage = new ImageBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()).mediaId(wxAutoReply.getRepMediaId()).build();
}
if (WxConsts.KefuMsgType.VOICE.equals(wxAutoReply.getRepType())) {
wxMsg.setRepName(wxAutoReply.getRepName());
wxMsg.setRepUrl(wxAutoReply.getRepUrl());
wxMsg.setRepMediaId(wxAutoReply.getRepMediaId());
wxMpXmlOutMessage = new VoiceBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()).mediaId(wxAutoReply.getRepMediaId()).build();
}
if (WxConsts.KefuMsgType.VIDEO.equals(wxAutoReply.getRepType())) {
wxMsg.setRepName(wxAutoReply.getRepName());
wxMsg.setRepDesc(wxAutoReply.getRepDesc());
wxMsg.setRepUrl(wxAutoReply.getRepUrl());
wxMsg.setRepMediaId(wxAutoReply.getRepMediaId());
wxMpXmlOutMessage = new VideoBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()).mediaId(wxAutoReply.getRepMediaId())
.title(wxAutoReply.getRepName()).description(wxAutoReply.getRepDesc()).build();
}
if (WxConsts.KefuMsgType.MUSIC.equals(wxAutoReply.getRepType())) {
wxMsg.setRepName(wxAutoReply.getRepName());
wxMsg.setRepDesc(wxAutoReply.getRepDesc());
wxMsg.setRepUrl(wxAutoReply.getRepUrl());
wxMsg.setRepHqUrl(wxAutoReply.getRepHqUrl());
wxMsg.setRepThumbMediaId(wxAutoReply.getRepThumbMediaId());
wxMsg.setRepThumbUrl(wxAutoReply.getRepThumbUrl());
wxMpXmlOutMessage = new MusicBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
.thumbMediaId(wxAutoReply.getRepThumbMediaId())
.title(wxAutoReply.getRepName()).description(wxAutoReply.getRepDesc())
.musicUrl(wxAutoReply.getRepUrl()).hqMusicUrl(wxAutoReply.getRepHqUrl()).build();
}
if (WxConsts.KefuMsgType.NEWS.equals(wxAutoReply.getRepType())) {
List<WxMpXmlOutNewsMessage.Item> list = new ArrayList<>();
JSONObject content = JSONUtil.parseObj(wxAutoReply.getContent());
List<JSONObject> listJSONObject = content.getJSONArray("articles").toList(JSONObject.class);
WxMpXmlOutNewsMessage.Item t;
for (JSONObject jSONObject : listJSONObject) {
t = new WxMpXmlOutNewsMessage.Item();
t.setTitle(jSONObject.getStr("title"));
t.setDescription(jSONObject.getStr("digest"));
t.setPicUrl(jSONObject.getStr("thumbUrl"));
t.setUrl(jSONObject.getStr("url"));
list.add(t);
}
wxMsg.setRepName(wxAutoReply.getRepName());
wxMsg.setRepDesc(wxAutoReply.getRepDesc());
wxMsg.setRepUrl(wxAutoReply.getRepUrl());
wxMsg.setRepMediaId(wxAutoReply.getRepMediaId());
wxMsg.setContent(wxAutoReply.getContent());
wxMpXmlOutMessage = new NewsBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()).articles(list).build();
}
wxMsgMapper.insert(wxMsg);
}
return wxMpXmlOutMessage;
}
}
@@ -1,6 +1,18 @@
package com.pig4cloud.pigx.mp.handler;
import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pig4cloud.pigx.mp.builder.TextBuilder;
import com.pig4cloud.pigx.mp.config.WxMpContextHolder;
import com.pig4cloud.pigx.mp.constant.ReplyTypeEnum;
import com.pig4cloud.pigx.mp.entity.WxAccount;
import com.pig4cloud.pigx.mp.entity.WxAccountFans;
import com.pig4cloud.pigx.mp.entity.WxAutoReply;
import com.pig4cloud.pigx.mp.mapper.WxAccountFansMapper;
import com.pig4cloud.pigx.mp.mapper.WxAccountMapper;
import com.pig4cloud.pigx.mp.mapper.WxMsgMapper;
import com.pig4cloud.pigx.mp.service.WxAutoReplyService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
@@ -10,6 +22,10 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Map;
/**
@@ -17,7 +33,12 @@ import java.util.Map;
*/
@Slf4j
@Component
@AllArgsConstructor
public class SubscribeHandler extends AbstractHandler {
private final WxAutoReplyService wxAutoReplyService;
private final WxAccountFansMapper wxAccountFansMapper;
private final WxAccountMapper wxAccountMapper;
private final WxMsgMapper msgMapper;
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
@@ -26,45 +47,60 @@ public class SubscribeHandler extends AbstractHandler {
log.info("新关注用户 OPENID: " + wxMessage.getFromUser());
// 获取微信用户基本信息
try {
WxMpUser userWxInfo = weixinService.getUserService()
WxMpUser wxMpUser = weixinService.getUserService()
.userInfo(wxMessage.getFromUser(), null);
if (userWxInfo != null) {
// TODO 可以添加关注用户到本地数据库
WxAccountFans wxAccountFans = wxAccountFansMapper.selectOne(Wrappers
.<WxAccountFans>lambdaUpdate().eq(WxAccountFans::getOpenid, wxMessage.getFromUser()));
if (wxAccountFans != null) {
wxAccountFansMapper.deleteById(wxAccountFans);
}
wxAccountFans.setOpenid(wxMpUser.getOpenId());
wxAccountFans.setSubscribeStatus(String.valueOf(BooleanUtil.toInt(wxMpUser.getSubscribe())));
wxAccountFans.setSubscribeTime(LocalDateTime
.ofInstant(Instant.ofEpochMilli(wxMpUser.getSubscribeTime() * 1000L)
, ZoneId.systemDefault()));
wxAccountFans.setNickname(wxMpUser.getNickname());
wxAccountFans.setGender(String.valueOf(wxMpUser.getSex()));
wxAccountFans.setLanguage(wxMpUser.getLanguage());
wxAccountFans.setCountry(wxMpUser.getCountry());
wxAccountFans.setProvince(wxMpUser.getProvince());
wxAccountFans.setCity(wxMpUser.getCity());
wxAccountFans.setHeadimgUrl(wxMpUser.getHeadImgUrl());
wxAccountFans.setRemark(wxMpUser.getRemark());
WxAccount wxAccount = wxAccountMapper.selectOne(Wrappers.<WxAccount>lambdaQuery()
.eq(WxAccount::getAppid, WxMpContextHolder.getAppId()));
wxAccountFans.setWxAccountId(wxAccount.getId());
wxAccountFans.setWxAccountAppid(wxAccount.getAppid());
wxAccountFans.setWxAccountName(wxAccount.getName());
wxAccountFansMapper.insert(wxAccountFans);
return this.handleSpecial(wxMessage, wxAccountFans);
} catch (WxErrorException e) {
log.error("该公众号没有获取用户信息失败!" , e);
log.error("该公众号没有获取用户信息失败!", e);
}
WxMpXmlOutMessage responseResult = null;
try {
responseResult = this.handleSpecial(wxMessage);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
if (responseResult != null) {
return responseResult;
}
try {
return new TextBuilder().build("感谢关注" , wxMessage, weixinService);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
return new TextBuilder().build("感谢关注", wxMessage, weixinService);
}
/**
* 处理特殊请求,比如如果是扫码进来的,可以做相应处理
*/
private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage)
throws Exception {
//TODO
return null;
private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage, WxAccountFans fans) {
//发送关注消息
List<WxAutoReply> listWxAutoReply = wxAutoReplyService.list(Wrappers.<WxAutoReply>query().lambda()
.eq(WxAutoReply::getType, ReplyTypeEnum.ATTENTION.getType())
.eq(WxAutoReply::getAppId,WxMpContextHolder.getAppId()));
// 查询公众号 基本信息
WxAccount wxAccount = wxAccountMapper.selectOne(Wrappers.<WxAccount>lambdaQuery()
.eq(WxAccount::getAccount, wxMessage.getToUser()));
WxMpXmlOutMessage wxMpXmlOutMessage = MsgHandler.getWxMpXmlOutMessage(wxMessage, listWxAutoReply, fans, msgMapper, wxAccount);
return wxMpXmlOutMessage;
}
}
@@ -1,5 +1,10 @@
package com.pig4cloud.pigx.mp.handler;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pig4cloud.pigx.mp.constant.SubStatusEnum;
import com.pig4cloud.pigx.mp.entity.WxAccountFans;
import com.pig4cloud.pigx.mp.mapper.WxAccountFansMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
@@ -14,7 +19,9 @@ import java.util.Map;
*/
@Slf4j
@Component
@AllArgsConstructor
public class UnsubscribeHandler extends AbstractHandler {
private final WxAccountFansMapper wxAccountFansMapper;
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
@@ -22,7 +29,10 @@ public class UnsubscribeHandler extends AbstractHandler {
WxSessionManager sessionManager) {
String openId = wxMessage.getFromUser();
log.info("取消关注用户 OPENID: " + openId);
// TODO 可以更新本地数据库为取消关注状态
WxAccountFans fans = new WxAccountFans();
fans.setSubscribeStatus(SubStatusEnum.UNSUB.getType());
wxAccountFansMapper.update(fans, Wrappers
.<WxAccountFans>lambdaUpdate().eq(WxAccountFans::getOpenid,openId));
return null;
}
@@ -0,0 +1,16 @@
package com.pig4cloud.pigx.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.pig4cloud.pigx.mp.entity.WxAutoReply;
import org.apache.ibatis.annotations.Mapper;
/**
* 消息自动回复
*
* @author JL
* @date 2019-04-18 15:40:39
*/
@Mapper
public interface WxAutoReplyMapper extends BaseMapper<WxAutoReply> {
}
@@ -1,32 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.pig4cloud.pigx.mp.entity.WxFansMsg;
import org.apache.ibatis.annotations.Mapper;
/**
* lengleng
*
* @author lengleng
* @date 2019-03-27 20:45:27
*/
@Mapper
public interface WxFansMsgMapper extends BaseMapper<WxFansMsg> {
}
@@ -0,0 +1,15 @@
package com.pig4cloud.pigx.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.pig4cloud.pigx.mp.entity.WxMsg;
import org.apache.ibatis.annotations.Mapper;
/**
* 微信消息
*
* @author JL
* @date 2019-05-28 16:12:10
*/
@Mapper
public interface WxMsgMapper extends BaseMapper<WxMsg> {
}
@@ -0,0 +1,14 @@
package com.pig4cloud.pigx.mp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.pig4cloud.pigx.mp.entity.WxAutoReply;
/**
* 消息自动回复
*
* @author JL
* @date 2019-04-18 15:40:39
*/
public interface WxAutoReplyService extends IService<WxAutoReply> {
}
@@ -1,38 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.mp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.mp.entity.WxFansMsgRes;
/**
* 微信消息回复业务
*
* @author lengleng
* @date 2019-03-27 20:45:48
*/
public interface WxFansMsgResService extends IService<WxFansMsgRes> {
/**
* 保存并发送回复
*
* @param wxFansMsgRes
* @return
*/
R saveAndSend(WxFansMsgRes wxFansMsgRes);
}
@@ -1,30 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.mp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.pig4cloud.pigx.mp.entity.WxFansMsg;
/**
* 微信消息业务
*
* @author lengleng
* @date 2019-03-27 20:45:27
*/
public interface WxFansMsgService extends IService<WxFansMsg> {
}
@@ -0,0 +1,14 @@
package com.pig4cloud.pigx.mp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.pig4cloud.pigx.mp.entity.WxMsg;
/**
* 微信消息
*
* @author JL
* @date 2019-05-28 16:12:10
*/
public interface WxMsgService extends IService<WxMsg> {
}
@@ -17,6 +17,7 @@
package com.pig4cloud.pigx.mp.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -105,7 +106,7 @@ public class WxAccountFansServiceImpl extends ServiceImpl<WxAccountFansMapper, W
}
wxAccountFans.setOpenid(wxMpUser.getOpenId());
wxAccountFans.setSubscribeStatus(wxMpUser.getSubscribe() ? "1" : "0");
wxAccountFans.setSubscribeStatus(String.valueOf(BooleanUtil.toInt(wxMpUser.getSubscribe())));
wxAccountFans.setSubscribeTime(LocalDateTime
.ofInstant(Instant.ofEpochMilli(wxMpUser.getSubscribeTime() * 1000L)
, ZoneId.systemDefault()));
@@ -0,0 +1,18 @@
package com.pig4cloud.pigx.mp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.mp.entity.WxAutoReply;
import com.pig4cloud.pigx.mp.mapper.WxAutoReplyMapper;
import com.pig4cloud.pigx.mp.service.WxAutoReplyService;
import org.springframework.stereotype.Service;
/**
* 消息自动回复
*
* @author JL
* @date 2019-04-18 15:40:39
*/
@Service
public class WxAutoReplyServiceImpl extends ServiceImpl<WxAutoReplyMapper, WxAutoReply> implements WxAutoReplyService {
}
@@ -1,89 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.mp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.security.service.PigxUser;
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
import com.pig4cloud.pigx.mp.config.WxMpConfiguration;
import com.pig4cloud.pigx.mp.entity.WxFansMsg;
import com.pig4cloud.pigx.mp.entity.WxFansMsgRes;
import com.pig4cloud.pigx.mp.mapper.WxFansMsgMapper;
import com.pig4cloud.pigx.mp.mapper.WxFansMsgResMapper;
import com.pig4cloud.pigx.mp.service.WxFansMsgResService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 微信消息回复业务
*
* @author lengleng
* @date 2019-03-27 20:45:48
*/
@Slf4j
@Service
@AllArgsConstructor
public class WxFansMsgResServiceImpl extends ServiceImpl<WxFansMsgResMapper, WxFansMsgRes> implements WxFansMsgResService {
private final WxFansMsgMapper wxFansMsgMapper;
/**
* 保存并发送回复
* <p>
* 1. 根据消息ID 查询消息的所属 公众号信息
* 2. 构建文本客服消息并发送
* 3. 完善回复消息并保存
* 4. 更新微信消息为已回复
*
* @param wxFansMsgRes
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public R saveAndSend(WxFansMsgRes wxFansMsgRes) {
WxFansMsg wxFansMsg = wxFansMsgMapper.selectById(wxFansMsgRes.getFansMsgId());
String wxAccountAppid = wxFansMsg.getWxAccountAppid();
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(wxAccountAppid);
try {
wxMpService.getKefuService().sendKefuMessage(WxMpKefuMessage
.TEXT()
.toUser(wxFansMsg.getOpenid())
.content(wxFansMsgRes.getResContent())
.build());
} catch (WxErrorException e) {
log.error("发送客服消息失败 ", e);
return R.failed(e.getError().getErrorMsg());
}
PigxUser user = SecurityUtils.getUser();
wxFansMsgRes.setUserId(user.getId());
wxFansMsgRes.setUserName(user.getUsername());
baseMapper.insert(wxFansMsgRes);
wxFansMsg.setIsRes("1");
wxFansMsgMapper.updateById(wxFansMsg);
return R.ok();
}
}
@@ -1,34 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.mp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.mp.entity.WxFansMsg;
import com.pig4cloud.pigx.mp.mapper.WxFansMsgMapper;
import com.pig4cloud.pigx.mp.service.WxFansMsgService;
import org.springframework.stereotype.Service;
/**
* 微信消息业务
*
* @author lengleng
* @date 2019-03-27 20:45:27
*/
@Service
public class WxFansMsgServiceImpl extends ServiceImpl<WxFansMsgMapper, WxFansMsg> implements WxFansMsgService {
}
@@ -0,0 +1,18 @@
package com.pig4cloud.pigx.mp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.mp.entity.WxMsg;
import com.pig4cloud.pigx.mp.mapper.WxMsgMapper;
import com.pig4cloud.pigx.mp.service.WxMsgService;
import org.springframework.stereotype.Service;
/**
* 微信消息
*
* @author JL
* @date 2019-05-28 16:12:10
*/
@Service
public class WxMsgServiceImpl extends ServiceImpl<WxMsgMapper, WxMsg> implements WxMsgService {
}
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (C) 2018-2019
~ All rights reserved, Designed By www.joolun.com
-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pig4cloud.pigx.mp.mapper.WxAutoReplyMapper">
</mapper>
@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~
~ Copyright (c) 2018-2025, lengleng All rights reserved.
~
~ Redistribution and use in source and binary forms, with or without
~ modification, are permitted provided that the following conditions are met:
~
~ Redistributions of source code must retain the above copyright notice,
~ this list of conditions and the following disclaimer.
~ Redistributions in binary form must reproduce the above copyright
~ notice, this list of conditions and the following disclaimer in the
~ documentation and/or other materials provided with the distribution.
~ Neither the name of the pig4cloud.com developer nor the names of its
~ contributors may be used to endorse or promote products derived from
~ this software without specific prior written permission.
~ Author: lengleng (wangiegie@gmail.com)
~
-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pig4cloud.pigx.mp.mapper.WxFansMsgMapper">
<resultMap id="wxFansMsgMap" type="com.pig4cloud.pigx.mp.entity.WxFansMsg">
<id property="id" column="id"/>
<result property="openid" column="openid"/>
<result property="nickname" column="nickname"/>
<result property="headimgUrl" column="headimg_url"/>
<result property="wxAccountId" column="wx_account_id"/>
<result property="wxAccountName" column="wx_account_name"/>
<result property="wxAccountAppid" column="wx_account_appid"/>
<result property="msgType" column="msg_type"/>
<result property="content" column="content"/>
<result property="resContent" column="res_content"/>
<result property="isRes" column="is_res"/>
<result property="mediaId" column="media_id"/>
<result property="picUrl" column="pic_url"/>
<result property="picPath" column="pic_path"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="delFlag" column="del_flag"/>
<result property="tenantId" column="tenant_id"/>
</resultMap>
</mapper>
@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~
~ Copyright (c) 2018-2025, lengleng All rights reserved.
~
~ Redistribution and use in source and binary forms, with or without
~ modification, are permitted provided that the following conditions are met:
~
~ Redistributions of source code must retain the above copyright notice,
~ this list of conditions and the following disclaimer.
~ Redistributions in binary form must reproduce the above copyright
~ notice, this list of conditions and the following disclaimer in the
~ documentation and/or other materials provided with the distribution.
~ Neither the name of the pig4cloud.com developer nor the names of its
~ contributors may be used to endorse or promote products derived from
~ this software without specific prior written permission.
~ Author: lengleng (wangiegie@gmail.com)
~
-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pig4cloud.pigx.mp.mapper.WxFansMsgResMapper">
<resultMap id="wxFansMsgResMap" type="com.pig4cloud.pigx.mp.entity.WxFansMsgRes">
<id property="id" column="id"/>
<result property="fansMsgId" column="fans_msg_id"/>
<result property="resContent" column="res_content"/>
<result property="userId" column="user_id"/>
<result property="userName" column="user_name"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
</mapper>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (C) 2018-2019
~ All rights reserved, Designed By www.joolun.com
-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.pig4cloud.pigx.mp.mapper.WxMsgMapper">
</mapper>