♻️ Refactoring code. 增强微信模块功能,支持素材 回复等

This commit is contained in:
冷冷 committed 2020-05-13 14:46:10 +08:00
1 parent 57223bc514
commit 7b578b5549
17 files changed
+310 -219

No files matched your search

@@ -63,6 +63,11 @@ public interface CacheConstants {
*/
String ROUTE_JVM_RELOAD_TOPIC = "gateway_jvm_route_reload_topic";
/**
* 公众号 reload
*/
String MP_REDIS_RELOAD_TOPIC = "mp_redis_reload_topic";
/**
* 参数缓存
*/
@@ -1,17 +1,29 @@
package com.pig4cloud.pigx.mp.config;
import com.google.common.collect.Maps;
import com.pig4cloud.pigx.admin.api.feign.RemoteTenantService;
import com.pig4cloud.pigx.common.core.constant.CacheConstants;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.mp.entity.WxAccount;
import com.pig4cloud.pigx.mp.handler.*;
import com.pig4cloud.pigx.mp.service.WxAccountService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.constant.WxMpEventConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -23,56 +35,50 @@ import static me.chanjar.weixin.common.api.WxConsts.*;
* <p>
* 微信公众号基础配置,初始化配置
*/
@Slf4j
@Configuration
public class WxMpConfiguration {
public static Map<String, WxMpMessageRouter> getRouters() {
return routers;
}
public static Map<String, WxMpService> getMpServices() {
return mpServices;
}
private WxAccountService accountService;
private LogHandler logHandler;
private NullHandler nullHandler;
private KfSessionHandler kfSessionHandler;
private StoreCheckNotifyHandler storeCheckNotifyHandler;
private LocationHandler locationHandler;
private MenuHandler menuHandler;
private MsgHandler msgHandler;
private UnsubscribeHandler unsubscribeHandler;
private SubscribeHandler subscribeHandler;
private ScanHandler scanHandler;
private RedisTemplate redisTemplate;
@RequiredArgsConstructor
public class WxMpInitConfigRunner {
/**
* 保存 appid-router 的对应关系
*/
private static Map<String, WxMpMessageRouter> routers = Maps.newHashMap();
/**
* 保存 appid-mpservice 的对应关系
*/
private static Map<String, WxMpService> mpServices = Maps.newHashMap();
@Autowired
public WxMpConfiguration(WxAccountService accountService, LogHandler logHandler, NullHandler nullHandler
, KfSessionHandler kfSessionHandler, StoreCheckNotifyHandler storeCheckNotifyHandler
, LocationHandler locationHandler, MenuHandler menuHandler
, MsgHandler msgHandler, UnsubscribeHandler unsubscribeHandler
, SubscribeHandler subscribeHandler, ScanHandler scanHandler
, RedisTemplate redisTemplate) {
this.accountService = accountService;
this.logHandler = logHandler;
this.nullHandler = nullHandler;
this.kfSessionHandler = kfSessionHandler;
this.storeCheckNotifyHandler = storeCheckNotifyHandler;
this.locationHandler = locationHandler;
this.menuHandler = menuHandler;
this.msgHandler = msgHandler;
this.unsubscribeHandler = unsubscribeHandler;
this.subscribeHandler = subscribeHandler;
this.scanHandler = scanHandler;
this.redisTemplate = redisTemplate;
}
/**
* 保存 appid-tenantId 的对应关系
*/
private static Map<String, Integer> tenants = Maps.newHashMap();
private final RemoteTenantService tenantService;
private final WxAccountService accountService;
private final LogHandler logHandler;
private final NullHandler nullHandler;
private final KfSessionHandler kfSessionHandler;
private final StoreCheckNotifyHandler storeCheckNotifyHandler;
private final LocationHandler locationHandler;
private final MenuHandler menuHandler;
private final MsgHandler msgHandler;
private final UnsubscribeHandler unsubscribeHandler;
private final SubscribeHandler subscribeHandler;
private final ScanHandler scanHandler;
private final RedisTemplate redisTemplate;
@PostConstruct
public void initServices() {
mpServices = accountService.list().stream().map(a -> {
// 获取全部租户 遍历所有租户对应的公众号列表
List<WxAccount> accountList = new ArrayList<>();
tenantService.list(SecurityConstants.FROM_IN).getData()
.forEach(tenant -> {
TenantContextHolder.setTenantId(tenant.getId());
accountList.addAll(accountService.list());
});
mpServices = accountList.stream().map(a -> {
WxMpInRedisConfigStorage configStorage = new WxMpInRedisConfigStorage(redisTemplate);
configStorage.setAppId(a.getAppid());
configStorage.setSecret(a.getAppsecret());
@@ -82,6 +88,7 @@ public class WxMpConfiguration {
WxMpService service = new WxMpServiceImpl();
service.setWxMpConfigStorage(configStorage);
routers.put(a.getAppid(), this.newRouter(service));
tenants.put(a.getAppid(), a.getTenantId());
return service;
}).collect(Collectors.toMap(s -> s.getWxMpConfigStorage().getAppId(), a -> a));
}
@@ -146,4 +153,34 @@ public class WxMpConfiguration {
return newRouter;
}
/**
* redis 监听配置,监听 mp_redis_reload_topic,重新加载配置
*
* @param redisConnectionFactory redis 配置
* @return
*/
@Bean
public RedisMessageListenerContainer redisContainer(RedisConnectionFactory redisConnectionFactory) {
RedisMessageListenerContainer container
= new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
container.addMessageListener((message, bytes) -> {
log.warn("接收到重新加载公众号配置事件");
initServices();
}, new ChannelTopic(CacheConstants.MP_REDIS_RELOAD_TOPIC));
return container;
}
public static Map<String, Integer> getTenants() {
return tenants;
}
public static Map<String, WxMpMessageRouter> getRouters() {
return routers;
}
public static Map<String, WxMpService> getMpServices() {
return mpServices;
}
}
@@ -18,12 +18,13 @@ 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.constant.CacheConstants;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.mp.config.WxMpConfiguration;
import com.pig4cloud.pigx.mp.entity.WxAccount;
import com.pig4cloud.pigx.mp.service.WxAccountService;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
@@ -38,8 +39,8 @@ import org.springframework.web.bind.annotation.*;
@AllArgsConstructor
@RequestMapping("/wxaccount")
public class WxAccountController {
private final WxMpConfiguration wxMpConfiguration;
private final WxAccountService wxAccountService;
private final RedisTemplate redisTemplate;
/**
* 分页查询
@@ -76,7 +77,7 @@ public class WxAccountController {
@PreAuthorize("@pms.hasPermission('mp_wxaccount_add')")
public R save(@RequestBody WxAccount wxAccount) {
wxAccountService.save(wxAccount);
wxMpConfiguration.initServices();
redisTemplate.convertAndSend(CacheConstants.MP_REDIS_RELOAD_TOPIC,"重新加载公众号配置");
return R.ok();
}
@@ -91,7 +92,7 @@ public class WxAccountController {
@PreAuthorize("@pms.hasPermission('mp_wxaccount_edit')")
public R updateById(@RequestBody WxAccount wxAccount) {
wxAccountService.updateById(wxAccount);
wxMpConfiguration.initServices();
redisTemplate.convertAndSend(CacheConstants.MP_REDIS_RELOAD_TOPIC,"重新加载公众号配置");
return R.ok();
}
@@ -106,7 +107,7 @@ public class WxAccountController {
@PreAuthorize("@pms.hasPermission('mp_wxaccount_del')")
public R removeById(@PathVariable Integer id) {
wxAccountService.removeById(id);
wxMpConfiguration.initServices();
redisTemplate.convertAndSend(CacheConstants.MP_REDIS_RELOAD_TOPIC,"重新加载公众号配置");
return R.ok();
}
@@ -16,32 +16,15 @@
*/
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.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;
/**
* 微信粉丝消息管理
@@ -55,7 +38,6 @@ import java.util.List;
@RequestMapping("/wxfansmsg")
public class WxFansMsgController {
private final WxAccountFansService wxAccountFansService;
private final WxMsgService wxMsgService;
/**
@@ -88,91 +70,7 @@ public class WxFansMsgController {
*/
@PostMapping
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 articles = JSONUtil.parseObj(wxMsg.getContent()).getJSONArray("articles");
WxMpKefuMessage.WxArticle t;
for (Object object : articles) {
JSONObject obj = JSONUtil.parseObj(JSONUtil.toJsonStr(object));
t = new WxMpKefuMessage.WxArticle();
t.setTitle(obj.getStr("title"));
t.setDescription(obj.getStr("digest"));
t.setPicUrl(obj.getStr("thumbUrl"));
t.setUrl(obj.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());
}
return wxMsgService.saveAndPushMsg(wxMsg);
}
/**
@@ -182,7 +80,6 @@ public class WxFansMsgController {
* @return R
*/
@PutMapping
@PreAuthorize("@ss.hasPermi('wxmp:wxmsg:edit')")
public R updateById(@RequestBody WxMsg wxMsg) {
return R.ok(wxMsgService.updateById(wxMsg));
}
@@ -194,7 +91,6 @@ public class WxFansMsgController {
* @return R
*/
@DeleteMapping("/{id}")
@PreAuthorize("@ss.hasPermi('wxmp:wxmsg:del')")
public R removeById(@PathVariable String id) {
return R.ok(wxMsgService.removeById(id));
}
@@ -6,7 +6,7 @@ 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 com.pig4cloud.pigx.mp.config.WxMpInitConfigRunner;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
@@ -65,7 +65,7 @@ public class WxMaterialController {
mulFile.transferTo(file);
material.setFile(file);
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
WxMpMaterialUploadResult wxMpMaterialUploadResult = wxMpMaterialService.materialFileUpload(mediaType, material);
WxMpMaterialFileBatchGetResult.WxMaterialFileBatchGetNewsItem wxMpMaterialFileBatchGetResult = new WxMpMaterialFileBatchGetResult.WxMaterialFileBatchGetNewsItem();
@@ -98,7 +98,7 @@ public class WxMaterialController {
news.setArticles(articles);
String appId = data.getStr("appId");
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
WxMpMaterialUploadResult wxMpMaterialUploadResult = wxMpMaterialService.materialNewsUpload(news);
return R.ok(wxMpMaterialUploadResult);
@@ -124,7 +124,7 @@ public class WxMaterialController {
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);
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate = new WxMpMaterialArticleUpdate();
wxMpMaterialArticleUpdate.setMediaId(mediaId);
@@ -155,10 +155,10 @@ public class WxMaterialController {
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);
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
WxMediaImgUploadResult wxMediaImgUploadResult = wxMpMaterialService.mediaImgUpload(file);
Map<Object, Object> responseData = new HashMap<>();
Map<Object, Object> responseData = new HashMap<>(2);
responseData.put("link", wxMediaImgUploadResult.getUrl());
FileUtil.del(file);
return JSONUtil.toJsonStr(responseData);
@@ -172,7 +172,7 @@ public class WxMaterialController {
*/
@DeleteMapping
public R materialDel(String appId, String id) {
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
try {
return R.ok(wxMpMaterialService.materialDelete(id));
@@ -192,7 +192,7 @@ public class WxMaterialController {
@GetMapping("/page")
public R getWxMaterialPage(Page page, String type, String appId) {
try {
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
int count = (int) page.getSize();
int offset = (int) page.getCurrent() * count - count;
@@ -216,7 +216,7 @@ public class WxMaterialController {
*/
@GetMapping("/materialVideo")
public R getMaterialVideo(String mediaId, String appId) {
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
try {
return R.ok(wxMpMaterialService.materialVideoInfo(mediaId));
@@ -235,7 +235,7 @@ public class WxMaterialController {
@GetMapping("/materialOther")
public ResponseEntity<byte[]> getMaterialOther(String appId, String mediaId, String fileName) throws Exception {
try {
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
//获取文件
InputStream is = wxMpMaterialService.materialImageOrVoiceDownload(mediaId);
@@ -265,7 +265,7 @@ public class WxMaterialController {
@GetMapping("/tempMaterialOther")
public ResponseEntity<byte[]> getTempMaterialOther(String appId, String mediaId, String fileName) throws Exception {
try {
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
WxMpMaterialService wxMpMaterialService = wxMpService.getMaterialService();
//获取文件
InputStream is = new FileInputStream(wxMpMaterialService.mediaDownload(mediaId));
@@ -1,13 +1,11 @@
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.config.WxMpInitConfigRunner;
import com.pig4cloud.pigx.mp.service.WxAccountService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -54,7 +52,7 @@ public class WxPortalController {
throw new IllegalArgumentException("请求参数非法,请核实!");
}
final WxMpService wxService = WxMpConfiguration.getMpServices().get(appId);
final WxMpService wxService = WxMpInitConfigRunner.getMpServices().get(appId);
if (wxService == null) {
throw new IllegalArgumentException(String.format("未找到对应appid=[%d]的配置,请核实!", appId));
@@ -88,12 +86,12 @@ public class WxPortalController {
@RequestParam("openid") String openid,
@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());
// 查询当前 appId 对应的租户 保存到TTL 中
Integer tenantId = WxMpInitConfigRunner.getTenants().get(appId);
TenantContextHolder.setTenantId(tenantId);
WxMpContextHolder.setAppId(appId);
final WxMpService wxService = WxMpConfiguration.getMpServices().get(appId);
final WxMpService wxService = WxMpInitConfigRunner.getMpServices().get(appId);
log.info("接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
+ " timestamp=[{}], nonce=[{}], requestBody=[{}] ",
@@ -108,7 +106,7 @@ public class WxPortalController {
// 明文模式
if (StrUtil.isBlank(encType)) {
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
WxMpXmlOutMessage outMessage = WxMpConfiguration.getRouters().get(appId).route(inMessage);
WxMpXmlOutMessage outMessage = WxMpInitConfigRunner.getRouters().get(appId).route(inMessage);
if (outMessage != null) {
out = outMessage.toXml();
}
@@ -121,7 +119,7 @@ public class WxPortalController {
log.debug("消息解密后内容为:{} ", inMessage.toString());
WxMpXmlOutMessage outMessage = WxMpConfiguration.getRouters().get(appId).route(inMessage);
WxMpXmlOutMessage outMessage = WxMpInitConfigRunner.getRouters().get(appId).route(inMessage);
if (outMessage != null) {
out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage());
}
@@ -31,18 +31,10 @@ public class WxAutoReply extends Model<WxAutoReply> {
* 公众号ID
*/
private String appId;
/**
* 创建者
*/
private String createId;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新者
*/
private String updateId;
/**
* 更新时间
*/
@@ -27,18 +27,10 @@ public class WxMsg extends Model<WxMsg> {
*/
@TableId
private Integer id;
/**
* 创建者
*/
private String createId;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新者
*/
private String updateId;
/**
* 更新时间
*/
@@ -1,6 +1,16 @@
package com.pig4cloud.pigx.mp.handler;
import com.pig4cloud.pigx.mp.builder.TextBuilder;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
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.session.WxSessionManager;
import me.chanjar.weixin.mp.api.WxMpService;
@@ -8,6 +18,7 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
/**
@@ -15,7 +26,12 @@ import java.util.Map;
*/
@Slf4j
@Component
@AllArgsConstructor
public class LocationHandler extends AbstractHandler {
private final WxAutoReplyService wxAutoReplyService;
private final WxAccountFansMapper wxAccountFansMapper;
private final WxAccountMapper wxAccountMapper;
private final WxMsgMapper msgMapper;
@Override
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
@@ -25,10 +41,19 @@ public class LocationHandler extends AbstractHandler {
log.info("上报地理位置,纬度 : {},经度 : {},精度 : {}",
wxMessage.getLatitude(), wxMessage.getLongitude(), wxMessage.getPrecision());
//TODO 可以将用户地理位置信息保存到本地数据库,以便以后使用
//发送关注消息
List<WxAutoReply> listWxAutoReply = wxAutoReplyService.list(Wrappers.<WxAutoReply>query().lambda()
.eq(WxAutoReply::getType, ReplyTypeEnum.MSG.getType())
.eq(WxAutoReply::getAppId, WxMpContextHolder.getAppId())
.eq(WxAutoReply::getReqType, wxMessage.getMsgType()));
// 查询公众号 基本信息
WxAccount wxAccount = wxAccountMapper.selectOne(Wrappers.<WxAccount>lambdaQuery()
.eq(WxAccount::getAccount, wxMessage.getToUser()));
String content = "感谢反馈,您的的地理位置已收到!";
return new TextBuilder().build(content, wxMessage, null);
// 查询粉丝基本信息
WxAccountFans fans = wxAccountFansMapper.selectOne(Wrappers.<WxAccountFans>lambdaQuery()
.eq(WxAccountFans::getOpenid, wxMessage.getFromUser()));
return MsgHandler.getWxMpXmlOutMessage(wxMessage, listWxAutoReply, fans, msgMapper, wxAccount);
}
}
@@ -18,7 +18,6 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Map;
/**
@@ -28,6 +27,7 @@ import java.util.Map;
*/
@Slf4j
@Component
@AllArgsConstructor
public class LogHandler extends AbstractHandler {
private final WxAccountFansMapper fansMapper;
@@ -97,8 +97,6 @@ public class LogHandler extends AbstractHandler {
wxMsg.setRepScale(wxMessage.getScale());
wxMsg.setRepContent(wxMessage.getLabel());
}
LocalDateTime now = LocalDateTime.now();
wxMsg.setCreateTime(now);
msgMapper.insert(wxMsg);
log.debug("保存微信用户信息成功 {}", wxMsg);
return null;
@@ -114,12 +114,12 @@ public class MenuHandler extends AbstractHandler {
List<WxMpXmlOutNewsMessage.Item> list = new ArrayList<>();
List<JSONObject> articles = JSONUtil.parseObj(content).getJSONArray("articles").toList(JSONObject.class);
WxMpXmlOutNewsMessage.Item t;
for (JSONObject jSONObject : articles) {
for (JSONObject jsonObject : articles) {
t = new WxMpXmlOutNewsMessage.Item();
t.setTitle(jSONObject.getStr("title"));
t.setDescription(jSONObject.getStr("digest"));
t.setPicUrl(jSONObject.getStr("thumbUrl"));
t.setUrl(jSONObject.getStr("url"));
t.setTitle(jsonObject.getStr("title"));
t.setDescription(jsonObject.getStr("digest"));
t.setPicUrl(jsonObject.getStr("thumbUrl"));
t.setUrl(jsonObject.getStr("url"));
list.add(t);
}
wxMpXmlOutMessage = new NewsBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()).articles(list).build();
@@ -168,14 +168,14 @@ public class MsgHandler extends AbstractHandler {
List<WxMpXmlOutNewsMessage.Item> list = new ArrayList<>();
JSONObject content = JSONUtil.parseObj(wxAutoReply.getContent());
List<JSONObject> listJSONObject = content.getJSONArray("articles").toList(JSONObject.class);
List<JSONObject> jsonObjectList = content.getJSONArray("articles").toList(JSONObject.class);
WxMpXmlOutNewsMessage.Item t;
for (JSONObject jSONObject : listJSONObject) {
for (JSONObject jsonObject : jsonObjectList) {
t = new WxMpXmlOutNewsMessage.Item();
t.setTitle(jSONObject.getStr("title"));
t.setDescription(jSONObject.getStr("digest"));
t.setPicUrl(jSONObject.getStr("thumbUrl"));
t.setUrl(jSONObject.getStr("url"));
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());
@@ -1,6 +1,7 @@
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.WxMsg;
/**
@@ -11,4 +12,11 @@ import com.pig4cloud.pigx.mp.entity.WxMsg;
*/
public interface WxMsgService extends IService<WxMsg> {
/**
* 保存信息并向用户推送
*
* @param wxMsg
* @return
*/
R saveAndPushMsg(WxMsg wxMsg);
}
@@ -21,7 +21,8 @@ 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;
import com.pig4cloud.pigx.mp.config.WxMpConfiguration;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.mp.config.WxMpInitConfigRunner;
import com.pig4cloud.pigx.mp.entity.WxAccount;
import com.pig4cloud.pigx.mp.entity.WxAccountFans;
import com.pig4cloud.pigx.mp.mapper.WxAccountFansMapper;
@@ -72,8 +73,14 @@ public class WxAccountFansServiceImpl extends ServiceImpl<WxAccountFansMapper, W
.selectOne(Wrappers.<WxAccount>query().lambda()
.eq(WxAccount::getAppid, appId));
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
// 获取操作微信接口类
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
WxMpUserService wxMpUserService = wxMpService.getUserService();
// 获取对应公众号租户ID
Integer tenantId = WxMpInitConfigRunner.getTenants().get(appId);
TenantContextHolder.setTenantId(tenantId);
fetchUser(null, wxAccount, wxMpUserService);
return Boolean.TRUE;
}
@@ -20,7 +20,7 @@ import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.mp.config.WxMpConfiguration;
import com.pig4cloud.pigx.mp.config.WxMpInitConfigRunner;
import com.pig4cloud.pigx.mp.entity.WxAccount;
import com.pig4cloud.pigx.mp.mapper.WxAccountMapper;
import com.pig4cloud.pigx.mp.service.WxAccountService;
@@ -59,7 +59,7 @@ public class WxAccountServiceImpl extends ServiceImpl<WxAccountMapper, WxAccount
@Override
public R generateQr(String appId) {
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
try {
WxMpQrCodeTicket ticket = wxMpService.getQrcodeService().qrCodeCreateLastTicket(1);
String url = wxMpService.getQrcodeService().qrCodePictureUrl(ticket.getTicket());
@@ -90,7 +90,7 @@ public class WxAccountServiceImpl extends ServiceImpl<WxAccountMapper, WxAccount
Date start = new Date(Long.parseLong(split[0]));
Date end = new Date(Long.parseLong(split[1]));
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
WxMpDataCubeService cubeService = wxMpService.getDataCubeService();
List<List<Object>> result = new ArrayList<>();
@@ -21,7 +21,7 @@ import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.mp.config.WxMpConfiguration;
import com.pig4cloud.pigx.mp.config.WxMpInitConfigRunner;
import com.pig4cloud.pigx.mp.entity.WxAccount;
import com.pig4cloud.pigx.mp.entity.WxMpMenu;
import com.pig4cloud.pigx.mp.mapper.WxAccountMapper;
@@ -94,7 +94,7 @@ public class WxMenuServiceImpl extends ServiceImpl<WxMenuMapper, WxMpMenu> imple
if (PUB_ED.equals(wxMpMenu.getPubFlag())) {
return R.failed("微信菜单配置已发布,不要重复发布");
}
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
WxMpMenuService menuService = wxMpService.getMenuService();
// 给数据库保存的加一层
@@ -136,7 +136,7 @@ public class WxMenuServiceImpl extends ServiceImpl<WxMenuMapper, WxMpMenu> imple
*/
@Override
public R delete(String appId) {
WxMpService wxMpService = WxMpConfiguration.getMpServices().get(appId);
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(appId);
WxMpMenuService menuService = wxMpService.getMenuService();
try {
menuService.menuDelete();
@@ -1,11 +1,31 @@
package com.pig4cloud.pigx.mp.service.impl;
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.service.impl.ServiceImpl;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.mp.config.WxMpInitConfigRunner;
import com.pig4cloud.pigx.mp.constant.MsgTypeEnum;
import com.pig4cloud.pigx.mp.entity.WxAccount;
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 com.pig4cloud.pigx.mp.service.WxMsgService;
import lombok.AllArgsConstructor;
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.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* 微信消息
*
@@ -13,6 +33,118 @@ import org.springframework.stereotype.Service;
* @date 2019-05-28 16:12:10
*/
@Service
@AllArgsConstructor
public class WxMsgServiceImpl extends ServiceImpl<WxMsgMapper, WxMsg> implements WxMsgService {
private final WxAccountFansMapper accountFansMapper;
private final WxAccountMapper accountMapper;
private final WxMsgMapper msgMapper;
/**
* 保存信息并向用户推送
*
* @param wxMsg 推送消息内容
* @return
*/
@Override
public R saveAndPushMsg(WxMsg wxMsg) {
// 查询用户详细
WxAccountFans wxUser = accountFansMapper.selectById(wxMsg.getWxUserId());
WxAccount wxAccount = accountMapper.selectOne(Wrappers.<WxAccount>lambdaQuery()
.eq(WxAccount::getAppid, wxMsg.getAppId()));
//维护消息-用户
wxMsg.setNickName(wxUser.getNickname());
wxMsg.setHeadimgUrl(wxUser.getHeadimgUrl());
wxMsg.setType(MsgTypeEnum.MP2USER.getType());
//维护消息-公众号
wxMsg.setAppLogo(wxAccount.getQrUrl());
wxMsg.setAppName(wxAccount.getName());
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 articles = JSONUtil.parseObj(wxMsg.getContent()).getJSONArray("articles");
WxMpKefuMessage.WxArticle t;
for (Object object : articles) {
JSONObject obj = JSONUtil.parseObj(JSONUtil.toJsonStr(object));
t = new WxMpKefuMessage.WxArticle();
t.setTitle(obj.getStr("title"));
t.setDescription(obj.getStr("digest"));
t.setPicUrl(obj.getStr("thumbUrl"));
t.setUrl(obj.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) {
return R.failed("非法消息类型");
}
WxMpService wxMpService = WxMpInitConfigRunner.getMpServices().get(wxMsg.getAppId());
WxMpKefuService wxMpKefuService = wxMpService.getKefuService();
wxMpKefuMessage.setToUser(wxUser.getOpenid());
try {
wxMpKefuService.sendKefuMessage(wxMpKefuMessage);
msgMapper.insert(wxMsg);
return R.ok(wxMsg);
} catch (WxErrorException e) {
return R.failed(e.getError().getErrorMsg());
}
}
}