first commit
This commit is contained in:
63
play-weichat/pom.xml
Normal file
63
play-weichat/pom.xml
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.starry</groupId>
|
||||
<artifactId>play-with</artifactId>
|
||||
<version>1.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>play-weichat</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<!--weixin-java-common-->
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-common</artifactId>
|
||||
</dependency>
|
||||
<!--weixin-java-admin-->
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-mp</artifactId>
|
||||
</dependency>
|
||||
<!--weixin-java-miniapp-->
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-miniapp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--weixin-java-pay-->
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-pay</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>guava</artifactId>
|
||||
<groupId>com.google.guava</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.starry</groupId>
|
||||
<artifactId>play-common</artifactId>
|
||||
<version>1.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>cos_api</artifactId>
|
||||
<groupId>com.qcloud</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.starry.weichat.builder;
|
||||
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
public abstract class AbstractBuilder {
|
||||
|
||||
public abstract WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage, WxMpService service);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
package com.starry.weichat.builder;
|
||||
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
public class ImageBuilder extends AbstractBuilder {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
|
||||
WxMpService service) {
|
||||
|
||||
return WxMpXmlOutMessage.IMAGE().mediaId(content)
|
||||
.fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
package com.starry.weichat.builder;
|
||||
|
||||
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.WxMpXmlOutTextMessage;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
public class TextBuilder extends AbstractBuilder {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
|
||||
WxMpService service) {
|
||||
WxMpXmlOutTextMessage m = WxMpXmlOutMessage.TEXT().content(content)
|
||||
.fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
|
||||
.build();
|
||||
return m;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
package com.starry.weichat.config;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
public interface CommonConstants {
|
||||
/**
|
||||
* 是
|
||||
*/
|
||||
String YES = "1";
|
||||
/**
|
||||
* 否
|
||||
*/
|
||||
String NO = "0";
|
||||
|
||||
/**
|
||||
* 树形父类ID
|
||||
*/
|
||||
String PARENT_ID = "0";
|
||||
/**
|
||||
* 编码
|
||||
*/
|
||||
String UTF8 = "UTF-8";
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.starry.weichat.config;
|
||||
|
||||
import com.starry.weichat.interceptor.ThirdSessionInterceptor;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* web配置
|
||||
*
|
||||
* @author admin
|
||||
*/
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
* 拦截器
|
||||
*
|
||||
* @param registry InterceptorRegistry
|
||||
*/
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
/*
|
||||
进入ThirdSession拦截器
|
||||
*/
|
||||
registry.addInterceptor(new ThirdSessionInterceptor())
|
||||
// 拦截/api/**接口
|
||||
.addPathPatterns("/weixin/api/**")
|
||||
// 放行接口
|
||||
.excludePathPatterns("/weixin/api/ma/wxuser/login",
|
||||
"/weixin/api/ma/orderinfo/notify-order", "/weixin/api/ma/orderinfo/notify-logisticsr",
|
||||
"/weixin/api/ma/orderinfo/notify-refunds");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
package com.starry.weichat.config;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
|
||||
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
|
||||
import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
|
||||
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(WxMaProperties.class)
|
||||
public class WxMaConfiguration {
|
||||
private static final Map<String, WxMaMessageRouter> routers = Maps.newHashMap();
|
||||
private static Map<String, WxMaService> maServices;
|
||||
private final WxMaProperties properties;
|
||||
private final WxMaMessageHandler subscribeMsgHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
service.getMsgService().sendSubscribeMsg(WxMaSubscribeMessage.builder()
|
||||
.templateId("此处更换为自己的模板id")
|
||||
.data(Lists.newArrayList(
|
||||
new WxMaSubscribeMessage.MsgData("keyword1", "339208499")))
|
||||
.toUser(wxMessage.getFromUser())
|
||||
.build());
|
||||
return null;
|
||||
};
|
||||
private final WxMaMessageHandler logHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
log.info("收到消息:" + wxMessage.toString());
|
||||
service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson())
|
||||
.toUser(wxMessage.getFromUser()).build());
|
||||
return null;
|
||||
};
|
||||
private final WxMaMessageHandler textHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息")
|
||||
.toUser(wxMessage.getFromUser()).build());
|
||||
return null;
|
||||
};
|
||||
private final WxMaMessageHandler picHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
try {
|
||||
WxMediaUploadResult uploadResult = service.getMediaService()
|
||||
.uploadMedia("image", "png",
|
||||
ClassLoader.getSystemResourceAsStream("tmp.png"));
|
||||
service.getMsgService().sendKefuMsg(
|
||||
WxMaKefuMessage
|
||||
.newImageBuilder()
|
||||
.mediaId(uploadResult.getMediaId())
|
||||
.toUser(wxMessage.getFromUser())
|
||||
.build());
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
private final WxMaMessageHandler qrcodeHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
try {
|
||||
final File file = service.getQrcodeService().createQrcode("123", 430);
|
||||
WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia("image", file);
|
||||
service.getMsgService().sendKefuMsg(
|
||||
WxMaKefuMessage
|
||||
.newImageBuilder()
|
||||
.mediaId(uploadResult.getMediaId())
|
||||
.toUser(wxMessage.getFromUser())
|
||||
.build());
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
@Autowired
|
||||
public WxMaConfiguration(WxMaProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public static WxMaService getMaService(String appId) {
|
||||
WxMaService wxService = maServices.get(appId);
|
||||
if (wxService == null) {
|
||||
throw new IllegalArgumentException(String.format("未找到对应appId=[%s]的配置,请核实!", appId));
|
||||
}
|
||||
|
||||
return wxService;
|
||||
}
|
||||
|
||||
public static WxMaMessageRouter getRouter(String appId) {
|
||||
return routers.get(appId);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
List<WxMaProperties.Config> configs = this.properties.getConfigs();
|
||||
if (configs == null) {
|
||||
throw new RuntimeException("大哥,拜托先看下项目首页的说明(readme文件),添加下相关配置,注意别配错了!");
|
||||
}
|
||||
|
||||
maServices = configs.stream()
|
||||
.map(a -> {
|
||||
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
|
||||
// 使用上面的配置时,需要同时引入jedis-lock的依赖,否则会报类无法找到的异常
|
||||
config.setAppid(a.getAppId());
|
||||
config.setSecret(a.getSecret());
|
||||
config.setToken(a.getToken());
|
||||
config.setAesKey(a.getAesKey());
|
||||
config.setMsgDataFormat(a.getMsgDataFormat());
|
||||
|
||||
WxMaService service = new WxMaServiceImpl();
|
||||
service.setWxMaConfig(config);
|
||||
routers.put(a.getAppId(), this.newRouter(service));
|
||||
return service;
|
||||
}).collect(Collectors.toMap(s -> s.getWxMaConfig().getAppid(), a -> a));
|
||||
}
|
||||
|
||||
private WxMaMessageRouter newRouter(WxMaService service) {
|
||||
final WxMaMessageRouter router = new WxMaMessageRouter(service);
|
||||
router
|
||||
.rule().handler(logHandler).next()
|
||||
.rule().async(false).content("订阅消息").handler(subscribeMsgHandler).end()
|
||||
.rule().async(false).content("文本").handler(textHandler).end()
|
||||
.rule().async(false).content("图片").handler(picHandler).end()
|
||||
.rule().async(false).content("二维码").handler(qrcodeHandler).end();
|
||||
return router;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
package com.starry.weichat.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "wx.ma")
|
||||
public class WxMaProperties {
|
||||
|
||||
private List<Config> configs;
|
||||
|
||||
@Data
|
||||
public static class Config {
|
||||
/**
|
||||
* 设置微信小程序的appid
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 设置微信小程序的Secret
|
||||
*/
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* 设置微信小程序消息服务器配置的token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 设置微信小程序消息服务器配置的EncodingAESKey
|
||||
*/
|
||||
private String aesKey;
|
||||
|
||||
/**
|
||||
* 消息格式,XML或者JSON
|
||||
*/
|
||||
private String msgDataFormat;
|
||||
/**
|
||||
* 微信支付商户号
|
||||
*/
|
||||
private String mchId;
|
||||
/**
|
||||
* 微信支付商户密钥
|
||||
*/
|
||||
private String mchKey;
|
||||
/**
|
||||
* p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
|
||||
*/
|
||||
private String keyPath;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
|
||||
package com.starry.weichat.config;
|
||||
|
||||
|
||||
import com.starry.weichat.handler.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
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.config.impl.WxMpDefaultConfigImpl;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static me.chanjar.weixin.common.api.WxConsts.EventType.SUBSCRIBE;
|
||||
import static me.chanjar.weixin.common.api.WxConsts.EventType.UNSUBSCRIBE;
|
||||
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType.EVENT;
|
||||
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.*;
|
||||
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.POI_CHECK_NOTIFY;
|
||||
|
||||
/**
|
||||
* wechat mp configuration
|
||||
*
|
||||
* @author admin
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(WxMpProperties.class)
|
||||
public class WxMpConfiguration {
|
||||
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 WxMpProperties properties;
|
||||
|
||||
@Bean
|
||||
public WxMpService wxMpService() {
|
||||
// 代码里 getConfigs()处报错的同学,请注意仔细阅读项目说明,你的IDE需要引入lombok插件!!!!
|
||||
final List<WxMpProperties.MpConfig> configs = this.properties.getConfigs();
|
||||
if (configs == null) {
|
||||
throw new RuntimeException("大哥,拜托先看下项目首页的说明(readme文件),添加下相关配置,注意别配错了!");
|
||||
}
|
||||
|
||||
WxMpService service = new WxMpServiceImpl();
|
||||
service.setMultiConfigStorages(configs
|
||||
.stream().map(a -> {
|
||||
WxMpDefaultConfigImpl configStorage = new WxMpDefaultConfigImpl();
|
||||
configStorage.setAppId(a.getAppId());
|
||||
configStorage.setSecret(a.getSecret());
|
||||
configStorage.setToken(a.getToken());
|
||||
configStorage.setAesKey(a.getAesKey());
|
||||
return configStorage;
|
||||
}).collect(Collectors.toMap(WxMpDefaultConfigImpl::getAppId, a -> a, (o, n) -> o)));
|
||||
return service;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WxMpMessageRouter messageRouter(WxMpService wxMpService) {
|
||||
final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);
|
||||
|
||||
// 记录所有事件的日志 (异步执行)
|
||||
newRouter.rule().handler(this.logHandler).next();
|
||||
|
||||
// 接收客服会话管理事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(KF_CREATE_SESSION)
|
||||
.handler(this.kfSessionHandler).end();
|
||||
newRouter.rule().async(false).msgType(EVENT).event(KF_CLOSE_SESSION)
|
||||
.handler(this.kfSessionHandler).end();
|
||||
newRouter.rule().async(false).msgType(EVENT).event(KF_SWITCH_SESSION)
|
||||
.handler(this.kfSessionHandler).end();
|
||||
|
||||
// 门店审核事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(POI_CHECK_NOTIFY).handler(this.storeCheckNotifyHandler).end();
|
||||
|
||||
// 自定义菜单事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.CLICK).handler(this.menuHandler).end();
|
||||
|
||||
// 点击菜单连接事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.VIEW).handler(this.nullHandler).end();
|
||||
|
||||
// 关注事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(SUBSCRIBE).handler(this.subscribeHandler).end();
|
||||
|
||||
// 取消关注事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(UNSUBSCRIBE).handler(this.unsubscribeHandler).end();
|
||||
|
||||
// 上报地理位置事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.LOCATION).handler(this.locationHandler).end();
|
||||
|
||||
// 接收地理位置消息
|
||||
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION).handler(this.locationHandler).end();
|
||||
|
||||
// 扫码事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(WxConsts.EventType.SCAN).handler(this.scanHandler).end();
|
||||
|
||||
// 默认
|
||||
newRouter.rule().async(false).handler(this.msgHandler).end();
|
||||
|
||||
return newRouter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.starry.weichat.config;
|
||||
|
||||
import com.starry.weichat.utils.JsonUtils;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* wechat mp properties
|
||||
*
|
||||
* @author admin
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "wx.mp")
|
||||
public class WxMpProperties {
|
||||
private List<MpConfig> configs;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonUtils.toJson(this);
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class MpConfig {
|
||||
/**
|
||||
* 设置微信公众号的appid
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 设置微信公众号的app secret
|
||||
*/
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* 设置微信公众号的token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 设置微信公众号的EncodingAESKey
|
||||
*/
|
||||
private String aesKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (C) 2018-2019
|
||||
* All rights reserved, Designed By admin
|
||||
* 注意:
|
||||
*
|
||||
*/
|
||||
package com.starry.weichat.config;
|
||||
|
||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||
import com.github.binarywang.wxpay.service.WxPayService;
|
||||
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 微信支付Configuration
|
||||
*
|
||||
* @author admin
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class WxPayConfiguration {
|
||||
|
||||
private static WxMaProperties wxMaProperties;
|
||||
|
||||
@Autowired
|
||||
public WxPayConfiguration(WxMaProperties wxMaProperties) {
|
||||
WxPayConfiguration.wxMaProperties = wxMaProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取WxMpService
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static WxPayService getPayService() {
|
||||
WxPayService wxPayService = null;
|
||||
WxPayConfig payConfig = new WxPayConfig();
|
||||
payConfig.setAppId(wxMaProperties.getConfigs().get(0).getAppId());
|
||||
payConfig.setMchId(wxMaProperties.getConfigs().get(0).getMchId());
|
||||
payConfig.setMchKey(wxMaProperties.getConfigs().get(0).getMchKey());
|
||||
payConfig.setKeyPath(wxMaProperties.getConfigs().get(0).getKeyPath());
|
||||
// 可以指定是否使用沙箱环境
|
||||
payConfig.setUseSandboxEnv(false);
|
||||
wxPayService = new WxPayServiceImpl();
|
||||
wxPayService.setConfig(payConfig);
|
||||
return wxPayService;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
|
||||
package com.starry.weichat.constant;
|
||||
|
||||
/**
|
||||
* 全局常量
|
||||
*
|
||||
* @author admin
|
||||
* 2019年1月21日
|
||||
*/
|
||||
public interface ConfigConstant {
|
||||
|
||||
// 订阅状态(0:已订阅;1:未订阅;2:网页授权用户)
|
||||
/**
|
||||
* 0:未订阅,取消订阅
|
||||
*/
|
||||
String SUBSCRIBE_TYPE_NO = "0";
|
||||
/**
|
||||
* 1:已订阅
|
||||
*/
|
||||
String SUBSCRIBE_TYPE_YES = "1";
|
||||
/**
|
||||
* 2:网页授权用户
|
||||
*/
|
||||
String SUBSCRIBE_TYPE_WEBLIEN = "2";
|
||||
|
||||
/**
|
||||
* 应用类型 1:小程序
|
||||
*/
|
||||
String WX_APP_TYPE_1 = "1";
|
||||
/**
|
||||
* 应用类型 2:公众号
|
||||
*/
|
||||
String WX_APP_TYPE_2 = "2";
|
||||
|
||||
/**
|
||||
* 消息自动回复类型(1、关注时回复;2、消息回复;3、关键词回复)
|
||||
*/
|
||||
String WX_AUTO_REPLY_TYPE_1 = "1";
|
||||
String WX_AUTO_REPLY_TYPE_2 = "2";
|
||||
String WX_AUTO_REPLY_TYPE_3 = "3";
|
||||
|
||||
/**
|
||||
* 回复类型文本匹配类型(1、全匹配,2、半匹配)
|
||||
*/
|
||||
String WX_REP_MATE_1 = "1";
|
||||
String WX_REP_MATE_2 = "2";
|
||||
|
||||
/**
|
||||
* 消息分类(1、用户发给公众号;2、公众号发给用户;)
|
||||
*/
|
||||
String WX_MSG_TYPE_1 = "1";
|
||||
String WX_MSG_TYPE_2 = "2";
|
||||
|
||||
/**
|
||||
* 群发消息发送类型(1、分组发;2、选择用户发)
|
||||
*/
|
||||
String WX_MASS_SEND_TYPE_1 = "1";
|
||||
String WX_MASS_SEND_TYPE_2 = "2";
|
||||
|
||||
/**
|
||||
* 群发消息发送后的状态(SUB_SUCCESS:提交成功,SUB_FAIL:提交失败,SEND_SUCCESS:发送成功,SENDING:发送中,SEND_FAIL:发送失败,DELETE:已删除)
|
||||
*/
|
||||
String WX_MASS_STATUS_SUB_SUCCESS = "SUB_SUCCESS";
|
||||
String WX_MASS_STATUS_SUB_FAIL = "SUB_FAIL";
|
||||
String WX_MASS_STATUS_SEND_SUCCESS = "SEND_SUCCESS";
|
||||
String WX_MASS_STATUS_SENDING = "SENDING";
|
||||
String WX_MASS_STATUS_SEND_FAIL = "SEND_FAIL";
|
||||
String WX_MASS_STATUS_DELETE = "DELETE";
|
||||
|
||||
/**
|
||||
* 菜单类型(1:普通菜单,2:个性化菜单)
|
||||
*/
|
||||
String WX_MENU_TYPE_1 = "1";
|
||||
String WX_MENU_TYPE_2 = "2";
|
||||
|
||||
/**
|
||||
* header中的app-id
|
||||
*/
|
||||
String HEADER_APP_ID = "app-id";
|
||||
|
||||
/**
|
||||
* header中的third-session
|
||||
*/
|
||||
String HEADER_THIRDSESSION = "third-session";
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
package com.starry.weichat.constant;
|
||||
|
||||
/**
|
||||
* 全局返回码
|
||||
* 小程序用6开头,例60001
|
||||
*
|
||||
* @author admin
|
||||
* 2019年7月25日
|
||||
*/
|
||||
public enum MyReturnCode {
|
||||
|
||||
// 其它错误
|
||||
ERR_60000(60000, "系统错误,请稍候再试") {},
|
||||
ERR_60001(60001, "登录超时,请重新登录") {},
|
||||
ERR_60002(60002, "session不能为空") {},
|
||||
|
||||
ERR_70001(70001, "该状态订单不允许操作") {},
|
||||
ERR_70002(70002, "请选择付款方式") {},
|
||||
ERR_70003(70003, "没有符合下单条件的规格商品,商品已下架或库存不足") {},
|
||||
ERR_70004(70004, "只有未支付的详单能发起支付") {},
|
||||
ERR_70005(70005, "无效订单") {},
|
||||
|
||||
ERR_80004(80004, "该商品已删除") {},
|
||||
|
||||
;
|
||||
|
||||
private int code;
|
||||
private String msg;
|
||||
|
||||
MyReturnCode(int code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MyReturnCode{" + "code='" + code + '\'' + "msg='" + msg + '\'' + '}';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
package com.starry.weichat.constant;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
public interface WebSocketConstant {
|
||||
|
||||
String USER_DESTINATION_PREFIX = "/weixin/";
|
||||
String WX_MSG = "wx_msg";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
package com.starry.weichat.constant;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
public interface WxMaConstants {
|
||||
|
||||
/**
|
||||
* redis中3rd_session过期时间(单位:小时)
|
||||
*/
|
||||
long TIME_OUT_SESSION = 6;
|
||||
/**
|
||||
* redis中3rd_session拼接前缀
|
||||
*/
|
||||
String THIRD_SESSION_BEGIN = "wx:ma:3rd_session";
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,127 @@
|
||||
|
||||
package com.starry.weichat.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.starry.common.result.R;
|
||||
import com.starry.weichat.constant.ConfigConstant;
|
||||
import com.starry.weichat.entity.WxAutoReply;
|
||||
import com.starry.weichat.service.WxAutoReplyService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息自动回复
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-04-18 15:40:39
|
||||
*/
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequestMapping("/wxautoreply")
|
||||
public class WxAutoReplyController {
|
||||
|
||||
@Resource
|
||||
WxAutoReplyService wxAutoReplyService;
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
* @param page 分页对象
|
||||
* @param wxAutoReply 消息自动回复
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxautoreply:index')")
|
||||
public R getWxAutoReplyPage(Page page, WxAutoReply wxAutoReply) {
|
||||
return R.ok(wxAutoReplyService.page(page,Wrappers.query(wxAutoReply)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 通过id查询消息自动回复
|
||||
* @param id id
|
||||
* @return R
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxautoreply:get')")
|
||||
public R getById(@PathVariable("id") String id){
|
||||
return R.ok(wxAutoReplyService.getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增消息自动回复
|
||||
* @param wxAutoReply 消息自动回复
|
||||
* @return R
|
||||
*/
|
||||
@PostMapping
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxautoreply:add')")
|
||||
public R save(@RequestBody WxAutoReply wxAutoReply){
|
||||
this.jude(wxAutoReply);
|
||||
return R.ok(wxAutoReplyService.save(wxAutoReply));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改消息自动回复
|
||||
* @param wxAutoReply 消息自动回复
|
||||
* @return R
|
||||
*/
|
||||
@PutMapping
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxautoreply:edit')")
|
||||
public R updateById(@RequestBody WxAutoReply wxAutoReply){
|
||||
this.jude(wxAutoReply);
|
||||
return R.ok(wxAutoReplyService.updateById(wxAutoReply));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id删除消息自动回复
|
||||
* @param id id
|
||||
* @return R
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxautoreply:del')")
|
||||
public R removeById(@PathVariable String id){
|
||||
return R.ok(wxAutoReplyService.removeById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* //校验参数
|
||||
* @param wxAutoReply
|
||||
*/
|
||||
public void jude(WxAutoReply wxAutoReply){
|
||||
if(ConfigConstant.WX_AUTO_REPLY_TYPE_2.equals(wxAutoReply.getType())){
|
||||
Wrapper<WxAutoReply> queryWrapper = Wrappers.<WxAutoReply>lambdaQuery()
|
||||
.eq(WxAutoReply::getReqType,wxAutoReply.getReqType());
|
||||
List<WxAutoReply> list = wxAutoReplyService.list(queryWrapper);
|
||||
if(StringUtils.isNotBlank(wxAutoReply.getId())){
|
||||
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(ConfigConstant.WX_AUTO_REPLY_TYPE_3.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("关键词重复");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
|
||||
package com.starry.weichat.controller;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.starry.common.result.R;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.mp.api.WxMpDraftService;
|
||||
import me.chanjar.weixin.mp.api.WxMpFreePublishService;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.bean.draft.WxMpAddDraft;
|
||||
import me.chanjar.weixin.mp.bean.draft.WxMpDraftArticles;
|
||||
import me.chanjar.weixin.mp.bean.draft.WxMpUpdateDraft;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 微信草稿箱
|
||||
*
|
||||
* @author admin
|
||||
* @since 2022-03-10 21:26:35
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequestMapping("/wxdraft")
|
||||
@Api(value = "wxdraft", tags = "微信草稿箱")
|
||||
public class WxDraftController {
|
||||
|
||||
@Resource
|
||||
WxMpService wxService;
|
||||
|
||||
/**
|
||||
* 新增图文消息
|
||||
*
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "新增草稿箱")
|
||||
@PostMapping
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxdraft:add')")
|
||||
public R add(@RequestBody JSONObject data) throws Exception {
|
||||
JSONArray jSONArray = data.getJSONArray("articles");
|
||||
List<WxMpDraftArticles> articles = jSONArray.toList(WxMpDraftArticles.class);
|
||||
WxMpAddDraft wxMpAddDraft = new WxMpAddDraft();
|
||||
wxMpAddDraft.setArticles(articles);
|
||||
WxMpDraftService wxMpDraftService = wxService.getDraftService();
|
||||
String rs = wxMpDraftService.addDraft(wxMpAddDraft);
|
||||
return R.ok(rs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改微信草稿箱
|
||||
*
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "修改微信草稿箱")
|
||||
@PutMapping
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxdraft:edit')")
|
||||
public R edit(@RequestBody JSONObject data) throws Exception {
|
||||
String mediaId = data.getStr("mediaId");
|
||||
JSONArray jSONArray = data.getJSONArray("articles");
|
||||
List<WxMpDraftArticles> articles = jSONArray.toList(WxMpDraftArticles.class);
|
||||
WxMpDraftService wxMpDraftService = wxService.getDraftService();
|
||||
WxMpUpdateDraft wxMpUpdateDraft = new WxMpUpdateDraft();
|
||||
wxMpUpdateDraft.setMediaId(mediaId);
|
||||
int index = 0;
|
||||
for (WxMpDraftArticles article : articles) {
|
||||
wxMpUpdateDraft.setIndex(index);
|
||||
wxMpUpdateDraft.setArticles(article);
|
||||
wxMpDraftService.updateDraft(wxMpUpdateDraft);
|
||||
index++;
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id删除微信草稿箱
|
||||
*
|
||||
* @param
|
||||
* @return R
|
||||
*/
|
||||
@ApiOperation(value = "通过id删除微信草稿箱")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxdraft:del')")
|
||||
public R del(String id) throws Exception {
|
||||
WxMpDraftService wxMpDraftService = wxService.getDraftService();
|
||||
return R.ok(wxMpDraftService.delDraft(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "分页查询")
|
||||
@GetMapping("/page")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxdraft:index')")
|
||||
public R getPage(Page page) throws Exception {
|
||||
WxMpDraftService wxMpDraftService = wxService.getDraftService();
|
||||
int count = (int) page.getSize();
|
||||
int offset = (int) page.getCurrent() * count - count;
|
||||
return R.ok(wxMpDraftService.listDraft(offset, count));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布草稿箱
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "发布草稿箱")
|
||||
@PostMapping("/publish/{id}")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxdraft:publish')")
|
||||
public R publish(@PathVariable String id) throws Exception {
|
||||
WxMpFreePublishService wxMpFreePublishService = wxService.getFreePublishService();
|
||||
wxMpFreePublishService.submit(id);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
package com.starry.weichat.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.starry.common.result.R;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.mp.api.WxMpFreePublishService;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 微信发布
|
||||
*
|
||||
* @author admin
|
||||
* @since 2022-03-10 21:26:35
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequestMapping("/freepublish")
|
||||
@Api(value = "freepublish", tags = "微信发布")
|
||||
public class WxFreePublishController {
|
||||
|
||||
@Resource
|
||||
WxMpService wxService;
|
||||
|
||||
/**
|
||||
* 删除发布
|
||||
*
|
||||
* @param
|
||||
* @return R
|
||||
*/
|
||||
@ApiOperation(value = "删除发布")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxfreepublish:del')")
|
||||
public R del(String id) throws Exception {
|
||||
WxMpFreePublishService wxMpFreePublishService = wxService.getFreePublishService();
|
||||
return R.ok(wxMpFreePublishService.deletePushAllArticle(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取成功发布列表
|
||||
*
|
||||
* @param page 获取成功发布列表
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation(value = "获取成功发布列表")
|
||||
@GetMapping("/page")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxfreepublish:index')")
|
||||
public R getPage(Page page) throws Exception {
|
||||
WxMpFreePublishService wxMpFreePublishService = wxService.getFreePublishService();
|
||||
int count = (int) page.getSize();
|
||||
int offset = (int) page.getCurrent() * count - count;
|
||||
return R.ok(wxMpFreePublishService.getPublicationRecords(offset, count));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
|
||||
package com.starry.weichat.controller;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.starry.common.result.R;
|
||||
import com.starry.weichat.entity.ImageManager;
|
||||
import com.starry.weichat.utils.FileUtils;
|
||||
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.WxMediaImgUploadResult;
|
||||
import me.chanjar.weixin.mp.bean.material.WxMpMaterial;
|
||||
import me.chanjar.weixin.mp.bean.material.WxMpMaterialFileBatchGetResult;
|
||||
import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 微信素材
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-23 21:26:35
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequestMapping("/wxmaterial")
|
||||
public class WxMaterialController {
|
||||
|
||||
@Resource
|
||||
WxMpService wxService;
|
||||
|
||||
/**
|
||||
* 上传非图文微信素材
|
||||
* @param mulFile
|
||||
* @param mediaType
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/materialFileUpload")
|
||||
// @PreAuthorize("@customSs.hasPermi('wxmp:wxmaterial:add')")
|
||||
public R materialFileUpload(@RequestParam("file") MultipartFile mulFile,
|
||||
@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 = FileUtils.multipartFileToFile(mulFile);
|
||||
material.setFile(file);
|
||||
WxMpMaterialService wxMpMaterialService = wxService.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());
|
||||
return R.ok(wxMpMaterialFileBatchGetResult);
|
||||
} catch (WxErrorException e) {
|
||||
log.error("上传非图文微信素材失败" + e);
|
||||
return R.error(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("上传失败", e);
|
||||
return R.error(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传图文消息内的图片获取URL
|
||||
* @param mulFile
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/newsImgUpload")
|
||||
// @PreAuthorize("@customSs.hasPermi('wxmp:wxmaterial:add')")
|
||||
public String newsImgUpload(@RequestParam("file") MultipartFile mulFile) throws Exception {
|
||||
File file = FileUtils.multipartFileToFile(mulFile);
|
||||
WxMpMaterialService wxMpMaterialService = wxService.getMaterialService();
|
||||
WxMediaImgUploadResult wxMediaImgUploadResult = wxMpMaterialService.mediaImgUpload(file);
|
||||
Map<Object, Object> responseData = new HashMap<>();
|
||||
responseData.put("link", wxMediaImgUploadResult.getUrl());
|
||||
return JSONUtil.toJsonStr(responseData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id删除微信素材
|
||||
* @param
|
||||
* @return R
|
||||
*/
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxmaterial:del')")
|
||||
public R materialDel(String id){
|
||||
WxMpMaterialService wxMpMaterialService = wxService.getMaterialService();
|
||||
try {
|
||||
return R.ok(wxMpMaterialService.materialDelete(id));
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("删除微信素材失败", e);
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
* @param page 分页对象
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxmaterial:index')")
|
||||
public R getWxMaterialPage(Page page, String type) {
|
||||
try {
|
||||
WxMpMaterialService wxMpMaterialService = wxService.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.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询2
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/page-manager")
|
||||
// @PreAuthorize("@customSs.hasPermi('wxmp:wxmaterial:index')")
|
||||
public String getWxMaterialPageManager(Integer count, Integer offset, String type) throws WxErrorException {
|
||||
List<ImageManager> listImageManager = new ArrayList<>();
|
||||
WxMpMaterialService wxMpMaterialService = wxService.getMaterialService();
|
||||
List<WxMpMaterialFileBatchGetResult.WxMaterialFileBatchGetNewsItem> list = wxMpMaterialService.materialFileBatchGet(type,offset,count).getItems();
|
||||
list.forEach(wxMaterialFileBatchGetNewsItem -> {
|
||||
ImageManager imageManager = new ImageManager();
|
||||
imageManager.setName(wxMaterialFileBatchGetNewsItem.getMediaId());
|
||||
imageManager.setUrl(wxMaterialFileBatchGetNewsItem.getUrl());
|
||||
imageManager.setThumb(wxMaterialFileBatchGetNewsItem.getUrl());
|
||||
listImageManager.add(imageManager);
|
||||
});
|
||||
return JSONUtil.toJsonStr(listImageManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信视频素材
|
||||
* @param
|
||||
* @return R
|
||||
*/
|
||||
@GetMapping("/materialVideo")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxmaterial:get')")
|
||||
public R getMaterialVideo(String mediaId){
|
||||
WxMpMaterialService wxMpMaterialService = wxService.getMaterialService();
|
||||
try {
|
||||
return R.ok(wxMpMaterialService.materialVideoInfo(mediaId));
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("获取微信视频素材失败", e);
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信素材直接文件
|
||||
* @param
|
||||
* @return R
|
||||
*/
|
||||
@GetMapping("/materialOther")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxmaterial:get')")
|
||||
public ResponseEntity<byte[]> getMaterialOther(String mediaId, String fileName) throws Exception {
|
||||
try {
|
||||
WxMpMaterialService wxMpMaterialService = wxService.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;
|
||||
//返回数据
|
||||
return new ResponseEntity<>(body, headers, statusCode);
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("获取微信素材直接文件失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信临时素材直接文件
|
||||
* @param
|
||||
* @return R
|
||||
*/
|
||||
@GetMapping("/tempMaterialOther")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxmsg:index')")
|
||||
public ResponseEntity<byte[]> getTempMaterialOther(String mediaId, String fileName) throws Exception {
|
||||
WxMpMaterialService wxMpMaterialService = wxService.getMaterialService();
|
||||
try (InputStream is = Files.newInputStream(wxMpMaterialService.mediaDownload(mediaId).toPath())){
|
||||
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;
|
||||
//返回数据
|
||||
return new ResponseEntity<>(body, headers, statusCode);
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("获取微信素材直接文件失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
package com.starry.weichat.controller;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.starry.common.result.R;
|
||||
import com.starry.weichat.service.WxMenuService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 自定义菜单
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-27 16:52:10
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequestMapping("/wxmenu")
|
||||
public class WxMenuController {
|
||||
|
||||
@Resource
|
||||
WxMenuService wxMenuService;
|
||||
|
||||
/**
|
||||
* 通过appId查询自定义菜单
|
||||
*
|
||||
* @return R
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxmenu:get')")
|
||||
public R getWxMenuButton() {
|
||||
return R.ok(wxMenuService.getWxMenuButton());
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存并发布菜单
|
||||
*
|
||||
* @param
|
||||
* @return R
|
||||
*/
|
||||
@PostMapping("/release")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxmenu:add')")
|
||||
public R saveAndRelease(@RequestBody String data) {
|
||||
JSONObject jSONObject = JSONUtil.parseObj(data);
|
||||
String strWxMenu = jSONObject.getStr("strWxMenu");
|
||||
String appId = jSONObject.getStr("appId");
|
||||
try {
|
||||
wxMenuService.saveAndRelease(strWxMenu);
|
||||
return R.ok();
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("发布自定义菜单失败appID:" + appId + ":" + e.getMessage());
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
|
||||
package com.starry.weichat.controller;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.starry.common.result.R;
|
||||
import com.starry.weichat.config.CommonConstants;
|
||||
import com.starry.weichat.constant.ConfigConstant;
|
||||
import com.starry.weichat.entity.WxMsg;
|
||||
import com.starry.weichat.entity.WxMsgVO;
|
||||
import com.starry.weichat.entity.WxUser;
|
||||
import com.starry.weichat.service.WxMsgService;
|
||||
import com.starry.weichat.service.WxUserService;
|
||||
import io.swagger.annotations.Api;
|
||||
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.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 微信消息
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-05-28 16:12:10
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequestMapping("/wxmsg")
|
||||
@Api(value = "wxmsg", tags = "wxmsg管理")
|
||||
public class WxMsgController {
|
||||
|
||||
@Resource
|
||||
WxMsgService wxMsgService;
|
||||
|
||||
@Resource
|
||||
WxUserService wxUserService;
|
||||
|
||||
@Resource
|
||||
WxMpService wxService;
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param wxMsgVO 微信消息
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxmsg:index')")
|
||||
public R getWxMsgPage(Page<WxMsg> page, WxMsgVO wxMsgVO) {
|
||||
if (StringUtils.isNotBlank(wxMsgVO.getNotInRepType())) {
|
||||
return R.ok(wxMsgService.listWxMsgMapGroup(page, wxMsgVO));
|
||||
}
|
||||
//标记为已读
|
||||
if (StringUtils.isNotBlank(wxMsgVO.getWxUserId())) {
|
||||
WxMsg wxMsg = new WxMsg();
|
||||
wxMsg.setReadFlag(CommonConstants.YES);
|
||||
Wrapper<WxMsg> queryWrapper = Wrappers.<WxMsg>lambdaQuery().eq(WxMsg::getWxUserId, wxMsgVO.getWxUserId()).eq(WxMsg::getReadFlag, CommonConstants.NO);
|
||||
wxMsgService.update(wxMsg, queryWrapper);
|
||||
}
|
||||
return R.ok(wxMsgService.page(page, Wrappers.query(wxMsgVO)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id查询微信消息
|
||||
*
|
||||
* @param id id
|
||||
* @return R
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxmsg:get')")
|
||||
public R getById(@PathVariable("id") String id) {
|
||||
return R.ok(wxMsgService.getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增微信消息
|
||||
*
|
||||
* @param wxMsg 微信消息
|
||||
* @return R
|
||||
*/
|
||||
@PostMapping
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxmsg:add')")
|
||||
public R save(@RequestBody WxMsg wxMsg) {
|
||||
try {
|
||||
WxUser wxUser = wxUserService.getById(wxMsg.getWxUserId());
|
||||
//入库
|
||||
wxMsg.setNickName(wxUser.getNickName());
|
||||
wxMsg.setHeadimgUrl(wxUser.getHeadimgUrl());
|
||||
wxMsg.setCreateTime(LocalDateTime.now());
|
||||
wxMsg.setType(ConfigConstant.WX_MSG_TYPE_2);
|
||||
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 = 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) {
|
||||
WxMpKefuService wxMpKefuService = wxService.getKefuService();
|
||||
wxMpKefuMessage.setToUser(wxUser.getOpenId());
|
||||
wxMpKefuService.sendKefuMessage(wxMpKefuMessage);
|
||||
wxMsgService.save(wxMsg);
|
||||
return R.ok(wxMsg);
|
||||
} else {
|
||||
return R.error("非法消息类型");
|
||||
}
|
||||
} catch (WxErrorException e) {
|
||||
log.error("新增微信消息失败" + e.getMessage());
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改微信消息
|
||||
*
|
||||
* @param wxMsg 微信消息
|
||||
* @return R
|
||||
*/
|
||||
@PutMapping
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxmsg:edit')")
|
||||
public R updateById(@RequestBody WxMsg wxMsg) {
|
||||
return R.ok(wxMsgService.updateById(wxMsg));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id删除微信消息
|
||||
*
|
||||
* @param id id
|
||||
* @return R
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxmsg:del')")
|
||||
public R removeById(@PathVariable String id) {
|
||||
return R.ok(wxMsgService.removeById(id));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
|
||||
package com.starry.weichat.controller;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/weixin/portal/{appid}")
|
||||
public class WxPortalController {
|
||||
|
||||
@Resource
|
||||
private final WxMpService wxService;
|
||||
|
||||
@Resource
|
||||
private final WxMpMessageRouter messageRouter;
|
||||
|
||||
@GetMapping(produces = "text/plain;charset=utf-8")
|
||||
public String authGet(@PathVariable String appid,
|
||||
@RequestParam(name = "signature", required = false) String signature,
|
||||
@RequestParam(name = "timestamp", required = false) String timestamp,
|
||||
@RequestParam(name = "nonce", required = false) String nonce,
|
||||
@RequestParam(name = "echostr", required = false) String echostr) {
|
||||
|
||||
log.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature,
|
||||
timestamp, nonce, echostr);
|
||||
if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
|
||||
throw new IllegalArgumentException("请求参数非法,请核实!");
|
||||
}
|
||||
|
||||
if (!this.wxService.switchover(appid)) {
|
||||
throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
|
||||
}
|
||||
|
||||
if (wxService.checkSignature(timestamp, nonce, signature)) {
|
||||
return echostr;
|
||||
}
|
||||
|
||||
return "非法请求";
|
||||
}
|
||||
|
||||
@PostMapping(produces = "application/xml; charset=UTF-8")
|
||||
public String post(@PathVariable String appid,
|
||||
@RequestBody String requestBody,
|
||||
@RequestParam("signature") String signature,
|
||||
@RequestParam("timestamp") String timestamp,
|
||||
@RequestParam("nonce") String nonce,
|
||||
@RequestParam("openid") String openid,
|
||||
@RequestParam(name = "encrypt_type", required = false) String encType,
|
||||
@RequestParam(name = "msg_signature", required = false) String msgSignature) {
|
||||
log.info("\n接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
|
||||
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
|
||||
openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
|
||||
|
||||
if (!this.wxService.switchover(appid)) {
|
||||
throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
|
||||
}
|
||||
|
||||
if (!wxService.checkSignature(timestamp, nonce, signature)) {
|
||||
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
|
||||
}
|
||||
|
||||
String out = null;
|
||||
if (encType == null) {
|
||||
// 明文传输的消息
|
||||
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
|
||||
WxMpXmlOutMessage outMessage = this.route(inMessage);
|
||||
if (outMessage == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
out = outMessage.toXml();
|
||||
} else if ("aes".equalsIgnoreCase(encType)) {
|
||||
// aes加密的消息
|
||||
WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(),
|
||||
timestamp, nonce, msgSignature);
|
||||
log.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
|
||||
WxMpXmlOutMessage outMessage = this.route(inMessage);
|
||||
if (outMessage == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage());
|
||||
}
|
||||
|
||||
log.debug("\n组装回复信息:{}", out);
|
||||
return out;
|
||||
}
|
||||
|
||||
private WxMpXmlOutMessage route(WxMpXmlMessage message) {
|
||||
try {
|
||||
return this.messageRouter.route(message);
|
||||
} catch (Exception e) {
|
||||
log.error("路由消息时出现异常!", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
|
||||
package com.starry.weichat.controller;
|
||||
|
||||
import com.starry.common.result.R;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.mp.api.WxMpDataCubeService;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
/**
|
||||
* 微信账号配置
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-23 21:26:35
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequestMapping("/wxsummary")
|
||||
public class WxSummaryController {
|
||||
|
||||
@Resource
|
||||
WxMpService wxService;
|
||||
|
||||
/**
|
||||
* 获取用户增减数据
|
||||
*
|
||||
* @param appId
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/usersummary")
|
||||
// @PreAuthorize("@customSs.hasPermi('wxmp:wxsummary:index')")
|
||||
public R getUsersummary(String appId, String startDate, String endDate) {
|
||||
try {
|
||||
WxMpDataCubeService wxMpDataCubeService = wxService.getDataCubeService();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
return R.ok(wxMpDataCubeService.getUserSummary(sdf.parse(startDate), sdf.parse(endDate)));
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("获取用户增减数据失败", e);
|
||||
return R.error(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
|
||||
log.error("获取用户增减数据失败", e);
|
||||
return R.error("获取用户增减数据失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取累计用户数据
|
||||
*
|
||||
* @param appId
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/usercumulate")
|
||||
// @PreAuthorize("@customSs.hasPermi('wxmp:wxsummary:index')")
|
||||
public R getUserCumulate(String appId, String startDate, String endDate) {
|
||||
try {
|
||||
WxMpDataCubeService wxMpDataCubeService = wxService.getDataCubeService();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
return R.ok(wxMpDataCubeService.getUserCumulate(sdf.parse(startDate), sdf.parse(endDate)));
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("获取累计用户数据失败", e);
|
||||
return R.error(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
|
||||
log.error("获取用户增减数据失败", e);
|
||||
return R.error("获取用户增减数据失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取接口分析数据
|
||||
*
|
||||
* @param appId
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/interfacesummary")
|
||||
// @PreAuthorize("@customSs.hasPermi('wxmp:wxsummary:index')")
|
||||
public R getInterfaceSummary(String appId, String startDate, String endDate) {
|
||||
try {
|
||||
WxMpDataCubeService wxMpDataCubeService = wxService.getDataCubeService();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
return R.ok(wxMpDataCubeService.getInterfaceSummary(sdf.parse(startDate), sdf.parse(endDate)));
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("获取接口分析数据失败", e);
|
||||
return R.error(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
|
||||
log.error("获取接口分析数据失败", e);
|
||||
return R.error("获取接口分析数据失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
|
||||
package com.starry.weichat.controller;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.starry.common.result.R;
|
||||
import com.starry.weichat.entity.WxUser;
|
||||
import com.starry.weichat.service.WxUserService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 微信用户
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-25 15:39:39
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequestMapping("/wxuser")
|
||||
public class WxUserController {
|
||||
|
||||
@Resource
|
||||
WxUserService wxUserService;
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param wxUser 微信用户
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxuser:index')")
|
||||
public R getWxUserPage(Page page, WxUser wxUser, String tagId) {
|
||||
Wrapper<WxUser> queryWrapper;
|
||||
if (StringUtils.isNotBlank(tagId)) {
|
||||
queryWrapper = Wrappers.lambdaQuery(wxUser)
|
||||
.and(wrapper -> wrapper
|
||||
.eq(WxUser::getTagidList, "[" + tagId + "]")
|
||||
.or()
|
||||
.like(WxUser::getTagidList, "," + tagId + ",")
|
||||
.or()
|
||||
.likeRight(WxUser::getTagidList, "[" + tagId + ",")
|
||||
.or()
|
||||
.likeLeft(WxUser::getTagidList, "," + tagId + "]"));
|
||||
} else if (StrUtil.isNotBlank(wxUser.getNickName())) {
|
||||
String nickName = wxUser.getNickName();
|
||||
wxUser.setNickName(null);
|
||||
queryWrapper = Wrappers.lambdaQuery(wxUser)
|
||||
.like(WxUser::getNickName, nickName);
|
||||
} else {
|
||||
queryWrapper = Wrappers.lambdaQuery(wxUser);
|
||||
}
|
||||
return R.ok(wxUserService.page(page, queryWrapper));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 通过id查询微信用户
|
||||
*
|
||||
* @param id id
|
||||
* @return R
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxuser:get')")
|
||||
public R getById(@PathVariable("id") String id) {
|
||||
return R.ok(wxUserService.getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增微信用户
|
||||
*
|
||||
* @param wxUser 微信用户
|
||||
* @return R
|
||||
*/
|
||||
@PostMapping
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxuser:add')")
|
||||
public R save(@RequestBody WxUser wxUser) {
|
||||
return R.ok(wxUserService.save(wxUser));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改微信用户
|
||||
*
|
||||
* @param wxUser 微信用户
|
||||
* @return R
|
||||
*/
|
||||
@PutMapping
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxuser:edit')")
|
||||
public R updateById(@RequestBody WxUser wxUser) {
|
||||
return R.ok(wxUserService.updateById(wxUser));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id删除微信用户
|
||||
*
|
||||
* @param id id
|
||||
* @return R
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxuser:del')")
|
||||
public R removeById(@PathVariable String id) {
|
||||
return R.ok(wxUserService.removeById(id));
|
||||
}
|
||||
|
||||
@PostMapping("/synchron")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxuser:synchro')")
|
||||
public R synchron() {
|
||||
try {
|
||||
wxUserService.synchroWxUser();
|
||||
return R.ok();
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("同步微信用户失败", e);
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改微信用户备注
|
||||
*
|
||||
* @param wxUser
|
||||
* @return
|
||||
*/
|
||||
@PutMapping("/remark")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxuser:edit:remark')")
|
||||
public R remark(@RequestBody WxUser wxUser) {
|
||||
try {
|
||||
return R.ok(wxUserService.updateRemark(wxUser));
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("修改微信用户备注失败", e);
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打标签
|
||||
*
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
@PutMapping("/tagid-list")
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxuser:tagging')")
|
||||
public R tagidList(@RequestBody JSONObject data) {
|
||||
try {
|
||||
String appId = data.getStr("appId");
|
||||
String taggingType = data.getStr("taggingType");
|
||||
JSONArray tagIdsArray = data.getJSONArray("tagIds");
|
||||
JSONArray openIdsArray = data.getJSONArray("openIds");
|
||||
String[] openIds = openIdsArray.toArray(new String[0]);
|
||||
for (Object tagId : tagIdsArray) {
|
||||
wxUserService.tagging(taggingType, Long.valueOf(String.valueOf(tagId)), openIds);
|
||||
}
|
||||
return R.ok();
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("修改微信用户备注失败", e);
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
|
||||
package com.starry.weichat.controller;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.starry.common.result.R;
|
||||
import com.starry.weichat.entity.WxUser;
|
||||
import com.starry.weichat.entity.WxUserTagsDict;
|
||||
import com.starry.weichat.service.WxUserService;
|
||||
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.api.WxMpUserTagService;
|
||||
import me.chanjar.weixin.mp.bean.tag.WxUserTag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 微信用户标签
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-25 15:39:39
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequestMapping("/wxusertags")
|
||||
public class WxUserTagsController {
|
||||
|
||||
@Resource
|
||||
WxMpService wxService;
|
||||
|
||||
@Resource
|
||||
WxUserService wxUserService;
|
||||
|
||||
/**
|
||||
* 获取微信用户标签
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxusertags:list')")
|
||||
@GetMapping("/list")
|
||||
public R getWxUserList(String appId) {
|
||||
WxMpUserTagService wxMpUserTagService = wxService.getUserTagService();
|
||||
try {
|
||||
List<WxUserTag> listWxUserTag = wxMpUserTagService.tagGet();
|
||||
return R.ok(listWxUserTag);
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("获取微信用户标签失败", e);
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信用户标签字典
|
||||
* @param appId
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxusertags:list')")
|
||||
@GetMapping("/dict")
|
||||
public R getWxUserTagsDict(String appId) {
|
||||
WxMpUserTagService wxMpUserTagService = wxService.getUserTagService();
|
||||
try {
|
||||
List<WxUserTag> listWxUserTag = wxMpUserTagService.tagGet();
|
||||
List<WxUserTagsDict> listWxUserTagsDict = new ArrayList<>();
|
||||
WxUserTagsDict wxUserTagsDict;
|
||||
for(WxUserTag wxUserTag : listWxUserTag){
|
||||
wxUserTagsDict = new WxUserTagsDict();
|
||||
wxUserTagsDict.setName(wxUserTag.getName());
|
||||
wxUserTagsDict.setValue(wxUserTag.getId());
|
||||
listWxUserTagsDict.add(wxUserTagsDict);
|
||||
}
|
||||
return R.ok(listWxUserTagsDict);
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("获取微信用户标签字典失败", e);
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增微信用户标签
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxusertags:add')")
|
||||
@PostMapping
|
||||
public R save(@RequestBody JSONObject data){
|
||||
String appId = data.getStr("appId");
|
||||
String name = data.getStr("name");
|
||||
WxMpUserTagService wxMpUserTagService = wxService.getUserTagService();
|
||||
try {
|
||||
return R.ok(wxMpUserTagService.tagCreate(name));
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("新增微信用户标签失败", e);
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改微信用户标签
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxusertags:edit')")
|
||||
@PutMapping
|
||||
public R updateById(@RequestBody JSONObject data){
|
||||
String appId = data.getStr("appId");
|
||||
Long id = data.getLong("id");
|
||||
String name = data.getStr("name");
|
||||
WxMpUserTagService wxMpUserTagService = wxService.getUserTagService();
|
||||
try {
|
||||
return R.ok(wxMpUserTagService.tagUpdate(id,name));
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("修改微信用户标签失败", e);
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除微信用户标签
|
||||
* @param id
|
||||
* @param appId
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("@customSs.hasPermi('wxmp:wxusertags:del')")
|
||||
@DeleteMapping
|
||||
public R removeById(Long id,String appId){
|
||||
int count = (int) wxUserService.count(Wrappers.<WxUser>lambdaQuery()
|
||||
.and(wrapper -> wrapper
|
||||
.eq(WxUser::getTagidList,"["+id+"]")
|
||||
.or()
|
||||
.like(WxUser::getTagidList,","+id+",")
|
||||
.or()
|
||||
.likeRight(WxUser::getTagidList,"["+id+",")
|
||||
.or()
|
||||
.likeLeft(WxUser::getTagidList,","+id+"]")));
|
||||
if(count>0){
|
||||
return R.error("该标签下有用户存在,无法删除");
|
||||
}
|
||||
WxMpUserTagService wxMpUserTagService = wxService.getUserTagService();
|
||||
try {
|
||||
return R.ok(wxMpUserTagService.tagDelete(id));
|
||||
} catch (WxErrorException e) {
|
||||
|
||||
log.error("删除微信用户标签失败", e);
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
package com.starry.weichat.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* imageManager
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-23 21:26:35
|
||||
*/
|
||||
@Data
|
||||
public class ImageManager implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String url;
|
||||
private String thumb;
|
||||
private String tag;
|
||||
private String name;
|
||||
private Integer id;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
package com.starry.weichat.entity;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.Data;
|
||||
import me.chanjar.weixin.common.bean.menu.WxMenuRule;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自定义菜单模型
|
||||
*
|
||||
* @author admin
|
||||
*/
|
||||
@Data
|
||||
public class Menu implements Serializable {
|
||||
private static final long serialVersionUID = -7083914585539687746L;
|
||||
|
||||
private List<MenuButton> button = new ArrayList<>();
|
||||
|
||||
private WxMenuRule matchrule;
|
||||
|
||||
/**
|
||||
* 反序列化
|
||||
*/
|
||||
public static Menu fromJson(String json) {
|
||||
return JSONUtil.parseObj(json).toBean(Menu.class);
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
return JSONUtil.toJsonStr(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.toJson();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
|
||||
package com.starry.weichat.entity;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自定义菜单模型
|
||||
*
|
||||
* @author admin
|
||||
*/
|
||||
@Data
|
||||
public class MenuButton implements Serializable {
|
||||
|
||||
private String type;
|
||||
|
||||
private String name;
|
||||
|
||||
private String key;
|
||||
|
||||
private String url;
|
||||
|
||||
private String media_id;
|
||||
|
||||
private String appid;
|
||||
|
||||
private String pagepath;
|
||||
|
||||
private List<MenuButton> sub_button = new ArrayList<>();
|
||||
/**
|
||||
* content内容
|
||||
*/
|
||||
private JSONObject content;
|
||||
|
||||
private String repContent;
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
private String repType;
|
||||
/**
|
||||
* 消息名
|
||||
*/
|
||||
private String repName;
|
||||
/**
|
||||
* 视频和音乐的描述
|
||||
*/
|
||||
private String repDesc;
|
||||
/**
|
||||
* 视频和音乐的描述
|
||||
*/
|
||||
private String repUrl;
|
||||
/**
|
||||
* 高质量链接
|
||||
*/
|
||||
private String repHqUrl;
|
||||
/**
|
||||
* 缩略图的媒体id
|
||||
*/
|
||||
private String repThumbMediaId;
|
||||
/**
|
||||
* 缩略图url
|
||||
*/
|
||||
private String repThumbUrl;
|
||||
private String article_id;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
package com.starry.weichat.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Data
|
||||
public class ThirdSession implements Serializable {
|
||||
/**
|
||||
* 微信用户ID
|
||||
*/
|
||||
private String wxUserId;
|
||||
/**
|
||||
* 配置项ID
|
||||
*/
|
||||
private String appId;
|
||||
/**
|
||||
* 微信sessionKey
|
||||
*/
|
||||
private String sessionKey;
|
||||
/**
|
||||
* 用户标识
|
||||
*/
|
||||
private String openId;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
|
||||
package com.starry.weichat.entity;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.starry.common.config.typehandler.JsonTypeHandler;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 消息自动回复
|
||||
*
|
||||
* @author admin
|
||||
* @since 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(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* 图文消息的内容
|
||||
*/
|
||||
@TableField(typeHandler = JsonTypeHandler.class, jdbcType = JdbcType.VARCHAR)
|
||||
private JSONObject content;
|
||||
|
||||
}
|
||||
118
play-weichat/src/main/java/com/starry/weichat/entity/WxMenu.java
Normal file
118
play-weichat/src/main/java/com/starry/weichat/entity/WxMenu.java
Normal file
@@ -0,0 +1,118 @@
|
||||
|
||||
package com.starry.weichat.entity;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.starry.common.config.typehandler.JsonTypeHandler;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 自定义菜单
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-27 16:52:10
|
||||
*/
|
||||
@Data
|
||||
@TableName("wx_menu")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class WxMenu extends Model<WxMenu> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 菜单ID(click、scancode_push、scancode_waitmsg、pic_sysphoto、pic_photo_or_album、pic_weixin、location_select:保存key)
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
/**
|
||||
* 父菜单ID
|
||||
*/
|
||||
private String parentId;
|
||||
/**
|
||||
* 排序值
|
||||
*/
|
||||
private Integer sort;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
/**
|
||||
* 逻辑删除标记(0:显示;1:隐藏)
|
||||
*/
|
||||
private String delFlag;
|
||||
/**
|
||||
* 菜单类型click、view、miniprogram、scancode_push、scancode_waitmsg、pic_sysphoto、pic_photo_or_album、pic_weixin、location_select、media_id、view_limited等
|
||||
*/
|
||||
@NotNull(message = "菜单类型不能为空")
|
||||
private String type;
|
||||
/**
|
||||
* 菜单名
|
||||
*/
|
||||
@NotNull(message = "菜单名不能为空")
|
||||
private String name;
|
||||
/**
|
||||
* View:保存链接到url
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* Img、voice、News:保存mediaID
|
||||
*/
|
||||
private String repMediaId;
|
||||
/**
|
||||
* 回复消息类型(text:文本;image:图片;voice:语音;video:视频;music:音乐;news:图文)
|
||||
*/
|
||||
private String repType;
|
||||
/**
|
||||
* 素材名、视频和音乐的标题
|
||||
*/
|
||||
private String repName;
|
||||
/**
|
||||
* Text:保存文字
|
||||
*/
|
||||
private String repContent;
|
||||
/**
|
||||
* 小程序的appid
|
||||
*/
|
||||
private String maAppId;
|
||||
/**
|
||||
* 小程序的页面路径
|
||||
*/
|
||||
private String maPagePath;
|
||||
/**
|
||||
* 视频和音乐的描述
|
||||
*/
|
||||
private String repDesc;
|
||||
/**
|
||||
* 视频和音乐的描述
|
||||
*/
|
||||
private String repUrl;
|
||||
/**
|
||||
* 高质量链接
|
||||
*/
|
||||
private String repHqUrl;
|
||||
/**
|
||||
* 缩略图的媒体id
|
||||
*/
|
||||
private String repThumbMediaId;
|
||||
/**
|
||||
* 缩略图url
|
||||
*/
|
||||
private String repThumbUrl;
|
||||
/**
|
||||
* 图文消息的内容
|
||||
*/
|
||||
@TableField(typeHandler = JsonTypeHandler.class, jdbcType = JdbcType.VARCHAR)
|
||||
private JSONObject content;
|
||||
}
|
||||
146
play-weichat/src/main/java/com/starry/weichat/entity/WxMsg.java
Normal file
146
play-weichat/src/main/java/com/starry/weichat/entity/WxMsg.java
Normal file
@@ -0,0 +1,146 @@
|
||||
|
||||
package com.starry.weichat.entity;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.starry.common.config.typehandler.JsonTypeHandler;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 微信消息
|
||||
*
|
||||
* @author admin
|
||||
* @since 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(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String createId;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updateId;
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 逻辑删除标记(0:显示;1:隐藏)
|
||||
*/
|
||||
private String delFlag;
|
||||
/**
|
||||
* 公众号名称
|
||||
*/
|
||||
private String appName;
|
||||
/**
|
||||
* 公众号logo
|
||||
*/
|
||||
private String appLogo;
|
||||
/**
|
||||
* 微信用户ID
|
||||
*/
|
||||
private String wxUserId;
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
private String nickName;
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
private String headimgUrl;
|
||||
/**
|
||||
* 消息分类(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;
|
||||
/**
|
||||
* 图文消息的内容
|
||||
*/
|
||||
@TableField(typeHandler = JsonTypeHandler.class, jdbcType = JdbcType.VARCHAR)
|
||||
private JSONObject content;
|
||||
/**
|
||||
* 缩略图的媒体id
|
||||
*/
|
||||
private String repThumbMediaId;
|
||||
/**
|
||||
* 缩略图url
|
||||
*/
|
||||
private String repThumbUrl;
|
||||
/**
|
||||
* 地理位置维度
|
||||
*/
|
||||
private Double repLocationX;
|
||||
/**
|
||||
* 地理位置经度
|
||||
*/
|
||||
private Double repLocationY;
|
||||
/**
|
||||
* 地图缩放大小
|
||||
*/
|
||||
private Double repScale;
|
||||
/**
|
||||
* 已读标记(0:是;1:否)
|
||||
*/
|
||||
private String readFlag;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
package com.starry.weichat.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 微信消息
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-05-28 16:12:10
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class WxMsgVO extends WxMsg {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 数量
|
||||
*/
|
||||
private Integer countMsg;
|
||||
|
||||
/**
|
||||
* repType not in筛选
|
||||
*/
|
||||
private String notInRepType;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.starry.weichat.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 微信开发数据
|
||||
* @author admin
|
||||
*/
|
||||
@Data
|
||||
public class WxOpenDataDTO {
|
||||
private String appId;
|
||||
private String userId;
|
||||
private String encryptedData;
|
||||
private String errMsg;
|
||||
private String iv;
|
||||
private String rawData;
|
||||
private String signature;
|
||||
private String sessionKey;
|
||||
}
|
||||
154
play-weichat/src/main/java/com/starry/weichat/entity/WxUser.java
Normal file
154
play-weichat/src/main/java/com/starry/weichat/entity/WxUser.java
Normal file
@@ -0,0 +1,154 @@
|
||||
|
||||
package com.starry.weichat.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.starry.common.config.typehandler.ArrayLongTypeHandler;
|
||||
import com.starry.common.sensitive.Sensitive;
|
||||
import com.starry.common.sensitive.SensitiveTypeEnum;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 微信用户
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-25 15:39:39
|
||||
*/
|
||||
@Data
|
||||
@TableName("wx_user")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class WxUser extends Model<WxUser> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private String id;
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String createId;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private String updateId;
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
/**
|
||||
* 备注信息
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 逻辑删除标记(0:显示;1:隐藏)
|
||||
*/
|
||||
private String delFlag;
|
||||
/**
|
||||
* 应用类型(1:小程序,2:公众号)
|
||||
*/
|
||||
private String appType;
|
||||
/**
|
||||
* 是否订阅(0:是;1:否;2:网页授权用户)
|
||||
*/
|
||||
private String subscribe;
|
||||
/**
|
||||
* 返回用户关注的渠道来源,ADD_SCENE_SEARCH 公众号搜索,ADD_SCENE_ACCOUNT_MIGRATION 公众号迁移,ADD_SCENE_PROFILE_CARD 名片分享,ADD_SCENE_QR_CODE 扫描二维码,ADD_SCENEPROFILE LINK 图文页内名称点击,ADD_SCENE_PROFILE_ITEM 图文页右上角菜单,ADD_SCENE_PAID 支付后关注,ADD_SCENE_OTHERS 其他
|
||||
*/
|
||||
private String subscribeScene;
|
||||
/**
|
||||
* 关注时间
|
||||
*/
|
||||
private LocalDateTime subscribeTime;
|
||||
/**
|
||||
* 关注次数
|
||||
*/
|
||||
private Integer subscribeNum;
|
||||
/**
|
||||
* 取消关注时间
|
||||
*/
|
||||
private LocalDateTime cancelSubscribeTime;
|
||||
/**
|
||||
* 用户标识
|
||||
*/
|
||||
private String openId;
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
private String nickName;
|
||||
/**
|
||||
* 性别(1:男,2:女,0:未知)
|
||||
*/
|
||||
private String sex;
|
||||
/**
|
||||
* 所在城市
|
||||
*/
|
||||
private String city;
|
||||
/**
|
||||
* 所在国家
|
||||
*/
|
||||
private String country;
|
||||
/**
|
||||
* 所在省份
|
||||
*/
|
||||
private String province;
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
@Sensitive(type = SensitiveTypeEnum.MOBILE_PHONE)
|
||||
private String phone;
|
||||
/**
|
||||
* 用户语言
|
||||
*/
|
||||
private String language;
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
private String headimgUrl;
|
||||
/**
|
||||
* union_id
|
||||
*/
|
||||
private String unionId;
|
||||
/**
|
||||
* 用户组
|
||||
*/
|
||||
private String groupId;
|
||||
/**
|
||||
* 标签列表
|
||||
*/
|
||||
@TableField(typeHandler = ArrayLongTypeHandler.class, jdbcType = JdbcType.VARCHAR)
|
||||
private Long[] tagidList;
|
||||
/**
|
||||
* 二维码扫码场景
|
||||
*/
|
||||
private String qrSceneStr;
|
||||
/**
|
||||
* 地理位置纬度
|
||||
*/
|
||||
private Double latitude;
|
||||
/**
|
||||
* 地理位置经度
|
||||
*/
|
||||
private Double longitude;
|
||||
/**
|
||||
* 地理位置精度
|
||||
*/
|
||||
@TableField(value = "`precision`")
|
||||
private Double precision;
|
||||
/**
|
||||
* 会话密钥
|
||||
*/
|
||||
private String sessionKey;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
package com.starry.weichat.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Data
|
||||
public class WxUserTagsDict {
|
||||
private String name;
|
||||
private Long value;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
package com.starry.weichat.handler;
|
||||
|
||||
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
public abstract class AbstractHandler implements WxMpMessageHandler {
|
||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
package com.starry.weichat.handler;
|
||||
|
||||
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 org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Component
|
||||
public class KfSessionHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
// TODO 对会话做处理
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
package com.starry.weichat.handler;
|
||||
|
||||
import com.starry.weichat.builder.TextBuilder;
|
||||
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 org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Component
|
||||
public class LocationHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) {
|
||||
// TODO 接收处理用户发送的地理位置消息
|
||||
try {
|
||||
String content = "感谢反馈,您的的地理位置已收到!";
|
||||
return new TextBuilder().build(content, wxMessage, null);
|
||||
} catch (Exception e) {
|
||||
this.logger.error("位置消息接收处理失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 上报地理位置事件
|
||||
this.logger.info("上报地理位置,纬度 : {},经度 : {},精度 : {}",
|
||||
wxMessage.getLatitude(), wxMessage.getLongitude(), wxMessage.getPrecision());
|
||||
|
||||
// TODO 可以将用户地理位置信息保存到本地数据库,以便以后使用
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
package com.starry.weichat.handler;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.starry.common.utils.HttpUtils;
|
||||
import com.starry.weichat.utils.JsonUtils;
|
||||
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 org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Component
|
||||
public class LogHandler extends AbstractHandler {
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
this.logger.info("\n接收到请求消息,内容:{}", JsonUtils.toJson(wxMessage));
|
||||
// 以下为测试代码,自行删除不影响系统功能
|
||||
if (wxMessage.getMsgType().equals(WxConsts.XmlMsgType.EVENT)) {
|
||||
if (wxMessage.getEvent().equals(WxConsts.EventType.SUBSCRIBE) ||
|
||||
wxMessage.getEvent().equals(WxConsts.EventType.SCAN)) {
|
||||
if (wxMessage.getEventKey().contains("jl-wiki")) {
|
||||
String openId = wxMessage.getFromUser();
|
||||
String sceneStr = StrUtil.split(wxMessage.getEventKey(), ":").get(1);
|
||||
String rs = HttpUtils.sendPost("http://127.0.0.1:8083/joolun-open/user", StrUtil.format("openId={}&sceneStr={}", openId, sceneStr));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
|
||||
package com.starry.weichat.handler;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.starry.weichat.config.CommonConstants;
|
||||
import com.starry.weichat.constant.ConfigConstant;
|
||||
import com.starry.weichat.entity.WxMenu;
|
||||
import com.starry.weichat.entity.WxMsg;
|
||||
import com.starry.weichat.entity.WxUser;
|
||||
import com.starry.weichat.mapper.WxMenuMapper;
|
||||
import com.starry.weichat.mapper.WxMsgMapper;
|
||||
import com.starry.weichat.mapper.WxUserMapper;
|
||||
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.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.bean.result.WxMpUser;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class MenuHandler extends AbstractHandler {
|
||||
|
||||
private final WxMenuMapper wxMenuMapper;
|
||||
private final WxUserMapper wxUserMapper;
|
||||
private final WxMsgMapper wxMsgMapper;
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService weixinService,
|
||||
WxSessionManager sessionManager) throws WxErrorException {
|
||||
// 消息记录
|
||||
WxMenu wxMenu;
|
||||
if (WxConsts.EventType.CLICK.equals(wxMessage.getEvent())
|
||||
|| WxConsts.EventType.SCANCODE_WAITMSG.equals(wxMessage.getEvent())) {
|
||||
wxMenu = wxMenuMapper.selectById(wxMessage.getEventKey());
|
||||
if (wxMenu == null) {// 菜单过期
|
||||
return new TextBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()).content("非常抱歉,该菜单已删除!").build();
|
||||
}
|
||||
} else {
|
||||
wxMenu = new WxMenu();
|
||||
}
|
||||
WxUser wxUser = wxUserMapper.selectOne(Wrappers.<WxUser>lambdaQuery()
|
||||
.eq(WxUser::getOpenId, wxMessage.getFromUser()));
|
||||
if (wxUser == null) {// 库中无此用户
|
||||
WxMpUser userWxInfo = weixinService.getUserService()
|
||||
.userInfo(wxMessage.getFromUser(), null);
|
||||
wxUser = new WxUser();
|
||||
wxUser.setSubscribeNum(1);
|
||||
SubscribeHandler.setWxUserValue(wxUser, userWxInfo);
|
||||
wxUserMapper.insert(wxUser);
|
||||
}
|
||||
// 组装菜单回复消息
|
||||
return getWxMpXmlOutMessage(wxMessage, wxMenu, wxUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装菜单回复消息
|
||||
*
|
||||
* @param wxMessage
|
||||
* @param wxMenu
|
||||
* @return
|
||||
*/
|
||||
public WxMpXmlOutMessage getWxMpXmlOutMessage(WxMpXmlMessage wxMessage, WxMenu wxMenu, WxUser wxUser) {
|
||||
WxMpXmlOutMessage wxMpXmlOutMessage = null;
|
||||
// 记录接收消息
|
||||
WxMsg wxMsg = new WxMsg();
|
||||
// wxMsg.setTenantId(wxApp.getTenantId());
|
||||
wxMsg.setWxUserId(wxUser.getId());
|
||||
wxMsg.setNickName(wxUser.getNickName());
|
||||
wxMsg.setHeadimgUrl(wxUser.getHeadimgUrl());
|
||||
wxMsg.setType(ConfigConstant.WX_MSG_TYPE_1);
|
||||
wxMsg.setRepEvent(wxMessage.getEvent());
|
||||
wxMsg.setRepType(wxMessage.getMsgType());
|
||||
wxMsg.setRepName(wxMenu.getName());
|
||||
if (WxConsts.EventType.VIEW.equals(wxMessage.getEvent())) {
|
||||
wxMsg.setRepUrl(wxMessage.getEventKey());
|
||||
}
|
||||
if (WxConsts.EventType.SCANCODE_WAITMSG.equals(wxMessage.getEvent())) {
|
||||
wxMsg.setRepContent(wxMessage.getScanCodeInfo().getScanResult());
|
||||
}
|
||||
wxMsg.setReadFlag(CommonConstants.NO);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
wxMsg.setCreateTime(now);
|
||||
wxMsgMapper.insert(wxMsg);
|
||||
if (WxConsts.MenuButtonType.CLICK.equals(wxMenu.getType())
|
||||
|| WxConsts.MenuButtonType.SCANCODE_WAITMSG.equals(wxMenu.getType())) {
|
||||
// 记录回复消息
|
||||
wxMsg = new WxMsg();
|
||||
wxMsg.setWxUserId(wxUser.getId());
|
||||
wxMsg.setNickName(wxUser.getNickName());
|
||||
wxMsg.setHeadimgUrl(wxUser.getHeadimgUrl());
|
||||
wxMsg.setCreateTime(now.plusSeconds(1));
|
||||
wxMsg.setType(ConfigConstant.WX_MSG_TYPE_2);
|
||||
wxMsg.setRepType(wxMenu.getRepType());
|
||||
if (WxConsts.KefuMsgType.TEXT.equals(wxMenu.getRepType())) {
|
||||
wxMsg.setRepContent(wxMenu.getRepContent());
|
||||
wxMpXmlOutMessage = new TextBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()).content(wxMenu.getRepContent()).build();
|
||||
}
|
||||
if (WxConsts.KefuMsgType.IMAGE.equals(wxMenu.getRepType())) {
|
||||
wxMsg.setRepName(wxMenu.getRepName());
|
||||
wxMsg.setRepUrl(wxMenu.getRepUrl());
|
||||
wxMsg.setRepMediaId(wxMenu.getRepMediaId());
|
||||
wxMpXmlOutMessage = new ImageBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()).mediaId(wxMenu.getRepMediaId()).build();
|
||||
}
|
||||
if (WxConsts.KefuMsgType.VOICE.equals(wxMenu.getRepType())) {
|
||||
wxMsg.setRepName(wxMenu.getRepName());
|
||||
wxMsg.setRepUrl(wxMenu.getRepUrl());
|
||||
wxMsg.setRepMediaId(wxMenu.getRepMediaId());
|
||||
wxMpXmlOutMessage = new VoiceBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()).mediaId(wxMenu.getRepMediaId()).build();
|
||||
}
|
||||
if (WxConsts.KefuMsgType.VIDEO.equals(wxMenu.getRepType())) {
|
||||
wxMsg.setRepName(wxMenu.getRepName());
|
||||
wxMsg.setRepDesc(wxMenu.getRepDesc());
|
||||
wxMsg.setRepUrl(wxMenu.getRepUrl());
|
||||
wxMsg.setRepMediaId(wxMenu.getRepMediaId());
|
||||
wxMpXmlOutMessage = new VideoBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()).mediaId(wxMenu.getRepMediaId())
|
||||
.title(wxMenu.getRepName()).description(wxMenu.getRepDesc()).build();
|
||||
}
|
||||
if (WxConsts.KefuMsgType.MUSIC.equals(wxMenu.getRepType())) {
|
||||
wxMsg.setRepName(wxMenu.getRepName());
|
||||
wxMsg.setRepDesc(wxMenu.getRepDesc());
|
||||
wxMsg.setRepUrl(wxMenu.getRepUrl());
|
||||
wxMsg.setRepHqUrl(wxMenu.getRepHqUrl());
|
||||
wxMsg.setRepThumbMediaId(wxMenu.getRepThumbMediaId());
|
||||
wxMsg.setRepThumbUrl(wxMenu.getRepThumbUrl());
|
||||
wxMpXmlOutMessage = new MusicBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
|
||||
.thumbMediaId(wxMenu.getRepThumbMediaId())
|
||||
.title(wxMenu.getRepName()).description(wxMenu.getRepDesc())
|
||||
.musicUrl(wxMenu.getRepUrl()).hqMusicUrl(wxMenu.getRepHqUrl()).build();
|
||||
}
|
||||
if (WxConsts.KefuMsgType.NEWS.equals(wxMenu.getRepType())) {
|
||||
List<WxMpXmlOutNewsMessage.Item> list = new ArrayList<>();
|
||||
List<JSONObject> listJSONObject = JSONUtil.toList(wxMenu.getContent().getJSONArray("articles"), 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(wxMenu.getRepName());
|
||||
wxMsg.setRepDesc(wxMenu.getRepDesc());
|
||||
wxMsg.setRepUrl(wxMenu.getRepUrl());
|
||||
wxMsg.setRepMediaId(wxMenu.getRepMediaId());
|
||||
wxMsg.setContent(wxMenu.getContent());
|
||||
wxMpXmlOutMessage = new NewsBuilder().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()).articles(list).build();
|
||||
}
|
||||
wxMsgMapper.insert(wxMsg);
|
||||
}
|
||||
return wxMpXmlOutMessage;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
|
||||
package com.starry.weichat.handler;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.starry.weichat.config.CommonConstants;
|
||||
import com.starry.weichat.constant.ConfigConstant;
|
||||
import com.starry.weichat.constant.WebSocketConstant;
|
||||
import com.starry.weichat.entity.WxAutoReply;
|
||||
import com.starry.weichat.entity.WxMsg;
|
||||
import com.starry.weichat.entity.WxUser;
|
||||
import com.starry.weichat.mapper.WxUserMapper;
|
||||
import com.starry.weichat.service.WxAutoReplyService;
|
||||
import com.starry.weichat.service.WxMsgService;
|
||||
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 admin
|
||||
*/
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class MsgHandler extends AbstractHandler {
|
||||
|
||||
private final WxAutoReplyService wxAutoReplyService;
|
||||
private final WxUserMapper wxUserMapper;
|
||||
private final WxMsgService wxMsgService;
|
||||
|
||||
/**
|
||||
* 组装回复消息,并记录消息
|
||||
*
|
||||
* @param wxMessage
|
||||
* @param listWxAutoReply
|
||||
* @return
|
||||
*/
|
||||
public static WxMpXmlOutMessage getWxMpXmlOutMessage(WxMpXmlMessage wxMessage, List<WxAutoReply> listWxAutoReply, WxUser wxUser, WxMsgService wxMsgService) {
|
||||
WxMpXmlOutMessage wxMpXmlOutMessage = null;
|
||||
// 记录接收消息
|
||||
WxMsg wxMsg = new WxMsg();
|
||||
wxMsg.setWxUserId(wxUser.getId());
|
||||
wxMsg.setNickName(wxUser.getNickName());
|
||||
wxMsg.setHeadimgUrl(wxUser.getHeadimgUrl());
|
||||
wxMsg.setType(ConfigConstant.WX_MSG_TYPE_1);
|
||||
wxMsg.setRepEvent(wxMessage.getEvent());
|
||||
wxMsg.setRepType(wxMessage.getMsgType());
|
||||
wxMsg.setRepMediaId(wxMessage.getMediaId());
|
||||
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());
|
||||
}
|
||||
wxMsg.setReadFlag(CommonConstants.NO);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
wxMsg.setCreateTime(now);
|
||||
wxMsgService.save(wxMsg);
|
||||
// 推送websocket
|
||||
String destination = WebSocketConstant.USER_DESTINATION_PREFIX + WebSocketConstant.WX_MSG + wxMsg.getWxUserId();
|
||||
if (listWxAutoReply != null && !listWxAutoReply.isEmpty()) {
|
||||
WxAutoReply wxAutoReply = listWxAutoReply.get(0);
|
||||
// 记录回复消息
|
||||
wxMsg = new WxMsg();
|
||||
wxMsg.setWxUserId(wxUser.getId());
|
||||
wxMsg.setNickName(wxUser.getNickName());
|
||||
wxMsg.setHeadimgUrl(wxUser.getHeadimgUrl());
|
||||
wxMsg.setCreateTime(now.plusSeconds(1));
|
||||
wxMsg.setType(ConfigConstant.WX_MSG_TYPE_2);
|
||||
wxMsg.setRepType(wxAutoReply.getRepType());
|
||||
|
||||
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<>();
|
||||
List<JSONObject> listJSONObject = wxAutoReply.getContent().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();
|
||||
}
|
||||
wxMsgService.save(wxMsg);
|
||||
}
|
||||
return wxMpXmlOutMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService, WxSessionManager sessionManager) {
|
||||
// 组装回复消息
|
||||
if (!wxMessage.getMsgType().equals(XmlMsgType.EVENT)) {
|
||||
WxMpXmlOutMessage rs;
|
||||
// TODO 可以选择将消息保存到本地
|
||||
WxUser wxUser = wxUserMapper.selectOne(Wrappers.<WxUser>lambdaQuery().eq(WxUser::getOpenId, wxMessage.getFromUser()));
|
||||
if (WxConsts.KefuMsgType.TEXT.equals(wxMessage.getMsgType())) {// 1、先处理是否有文本关键字回复
|
||||
// 先全匹配
|
||||
List<WxAutoReply> listWxAutoReply = wxAutoReplyService.list(Wrappers.<WxAutoReply>query().lambda().eq(WxAutoReply::getType, ConfigConstant.WX_AUTO_REPLY_TYPE_3).eq(WxAutoReply::getRepMate, ConfigConstant.WX_REP_MATE_1).eq(WxAutoReply::getReqKey, wxMessage.getContent()));
|
||||
if (listWxAutoReply != null && !listWxAutoReply.isEmpty()) {
|
||||
rs = this.getWxMpXmlOutMessage(wxMessage, listWxAutoReply, wxUser, wxMsgService);
|
||||
if (rs != null) {
|
||||
return rs;
|
||||
}
|
||||
}
|
||||
// 再半匹配
|
||||
listWxAutoReply = wxAutoReplyService.list(Wrappers.<WxAutoReply>query().lambda().eq(WxAutoReply::getType, ConfigConstant.WX_AUTO_REPLY_TYPE_3).eq(WxAutoReply::getRepMate, ConfigConstant.WX_REP_MATE_2).like(WxAutoReply::getReqKey, wxMessage.getContent()));
|
||||
if (listWxAutoReply != null && !listWxAutoReply.isEmpty()) {
|
||||
rs = this.getWxMpXmlOutMessage(wxMessage, listWxAutoReply, wxUser, wxMsgService);
|
||||
if (rs != null) {
|
||||
return rs;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2、再处理消息回复
|
||||
List<WxAutoReply> listWxAutoReply = wxAutoReplyService.list(Wrappers.<WxAutoReply>query().lambda().eq(WxAutoReply::getType, ConfigConstant.WX_AUTO_REPLY_TYPE_2).eq(WxAutoReply::getReqType, wxMessage.getMsgType()));
|
||||
rs = this.getWxMpXmlOutMessage(wxMessage, listWxAutoReply, wxUser, wxMsgService);
|
||||
return rs;
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
package com.starry.weichat.handler;
|
||||
|
||||
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 org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Component
|
||||
public class NullHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
package com.starry.weichat.handler;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
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 org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Component
|
||||
public class ScanHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, Map<String, Object> map,
|
||||
WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException {
|
||||
// 扫码事件处理
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
package com.starry.weichat.handler;
|
||||
|
||||
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 org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 门店审核事件处理
|
||||
*
|
||||
* @author admin
|
||||
*/
|
||||
@Component
|
||||
public class StoreCheckNotifyHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
// TODO 处理门店审核事件
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
|
||||
package com.starry.weichat.handler;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.starry.weichat.constant.ConfigConstant;
|
||||
import com.starry.weichat.entity.WxAutoReply;
|
||||
import com.starry.weichat.entity.WxUser;
|
||||
import com.starry.weichat.mapper.WxUserMapper;
|
||||
import com.starry.weichat.service.WxAutoReplyService;
|
||||
import com.starry.weichat.service.WxMsgService;
|
||||
import com.starry.weichat.utils.LocalDateTimeUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class SubscribeHandler extends AbstractHandler {
|
||||
private final WxAutoReplyService wxAutoReplyService;
|
||||
private final WxUserMapper wxUserMapper;
|
||||
private final WxMsgService wxMsgService;
|
||||
|
||||
public static void setWxUserValue(WxUser wxUser, WxMpUser userWxInfo) {
|
||||
wxUser.setAppType(ConfigConstant.WX_APP_TYPE_2);
|
||||
wxUser.setSubscribe(ConfigConstant.SUBSCRIBE_TYPE_YES);
|
||||
wxUser.setSubscribeScene(userWxInfo.getSubscribeScene());
|
||||
if (null != userWxInfo.getSubscribeTime()) {
|
||||
wxUser.setSubscribeTime(LocalDateTimeUtils.timestamToDatetime(userWxInfo.getSubscribeTime() * 1000));
|
||||
}
|
||||
wxUser.setOpenId(userWxInfo.getOpenId());
|
||||
wxUser.setLanguage(userWxInfo.getLanguage());
|
||||
wxUser.setRemark(userWxInfo.getRemark());
|
||||
wxUser.setUnionId(userWxInfo.getUnionId());
|
||||
wxUser.setGroupId(JSONUtil.toJsonStr(userWxInfo.getGroupId()));
|
||||
wxUser.setTagidList(userWxInfo.getTagIds());
|
||||
wxUser.setQrSceneStr(userWxInfo.getQrSceneStr());
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService weixinService, WxSessionManager sessionManager) {
|
||||
log.info("新关注用户 OPENID: " + wxMessage.getFromUser());
|
||||
// 获取微信用户基本信息
|
||||
try {
|
||||
WxMpUser userWxInfo = weixinService.getUserService().userInfo(wxMessage.getFromUser(), null);
|
||||
if (userWxInfo != null) {
|
||||
// TODO 添加关注用户到本地数据库
|
||||
WxUser wxUser = wxUserMapper.selectOne(Wrappers.<WxUser>lambdaQuery().eq(WxUser::getOpenId, userWxInfo.getOpenId()));
|
||||
if (wxUser == null) {
|
||||
// 第一次关注
|
||||
wxUser = new WxUser();
|
||||
wxUser.setSubscribeNum(1);
|
||||
setWxUserValue(wxUser, userWxInfo);
|
||||
// wxUser.setTenantId(wxApp.getTenantId());
|
||||
wxUserMapper.insert(wxUser);
|
||||
} else {
|
||||
// 曾经关注过
|
||||
wxUser.setSubscribeNum(wxUser.getSubscribeNum() + 1);
|
||||
setWxUserValue(wxUser, userWxInfo);
|
||||
// wxUser.setTenantId(wxApp.getTenantId());
|
||||
wxUserMapper.updateById(wxUser);
|
||||
}
|
||||
// 发送关注消息
|
||||
List<WxAutoReply> listWxAutoReply = wxAutoReplyService.list(Wrappers.<WxAutoReply>query().lambda().eq(WxAutoReply::getType, ConfigConstant.WX_AUTO_REPLY_TYPE_1));
|
||||
return MsgHandler.getWxMpXmlOutMessage(wxMessage, listWxAutoReply, wxUser, wxMsgService);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("用户关注出错:" + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
package com.starry.weichat.handler;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.starry.weichat.constant.ConfigConstant;
|
||||
import com.starry.weichat.entity.WxUser;
|
||||
import com.starry.weichat.mapper.WxUserMapper;
|
||||
import com.starry.weichat.service.WxMsgService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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 org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class UnsubscribeHandler extends AbstractHandler {
|
||||
|
||||
private final WxMsgService wxMsgService;
|
||||
private final WxUserMapper wxUserMapper;
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
String openId = wxMessage.getFromUser();
|
||||
log.info("取消关注用户 OPENID: " + openId);
|
||||
WxUser wxUser = wxUserMapper.selectOne(Wrappers.<WxUser>lambdaQuery()
|
||||
.eq(WxUser::getOpenId, openId));
|
||||
if (wxUser != null) {
|
||||
wxUser.setSubscribe(ConfigConstant.SUBSCRIBE_TYPE_NO);
|
||||
wxUser.setCancelSubscribeTime(LocalDateTime.now());
|
||||
wxUserMapper.updateById(wxUser);
|
||||
// 消息记录
|
||||
MsgHandler.getWxMpXmlOutMessage(wxMessage, null, wxUser, wxMsgService);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.starry.weichat.interceptor;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.starry.common.result.R;
|
||||
import com.starry.weichat.config.CommonConstants;
|
||||
import com.starry.weichat.constant.ConfigConstant;
|
||||
import com.starry.weichat.constant.MyReturnCode;
|
||||
import com.starry.weichat.constant.WxMaConstants;
|
||||
import com.starry.weichat.entity.ThirdSession;
|
||||
import com.starry.weichat.utils.ThirdSessionHolder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* ThirdSession拦截器,校验每个请求的ThirdSession
|
||||
*
|
||||
* @author admin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ThirdSessionInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Resource
|
||||
RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
// 获取header中的thirdSession
|
||||
String thirdSessionHeader = request.getHeader(ConfigConstant.HEADER_THIRDSESSION);
|
||||
if (StrUtil.isNotBlank(thirdSessionHeader)) {
|
||||
// 获取缓存中的ThirdSession
|
||||
String key = WxMaConstants.THIRD_SESSION_BEGIN + ":" + thirdSessionHeader;
|
||||
Object thirdSessionObj = redisTemplate.opsForValue().get(key);
|
||||
if (thirdSessionObj == null) {
|
||||
// session过期
|
||||
R r = R.error(MyReturnCode.ERR_60001.getCode(), MyReturnCode.ERR_60001.getMsg());
|
||||
this.writerPrint(response, r);
|
||||
return Boolean.FALSE;
|
||||
} else {
|
||||
String thirdSessionStr = String.valueOf(thirdSessionObj);
|
||||
ThirdSession thirdSession = JSONUtil.toBean(thirdSessionStr, ThirdSession.class);
|
||||
// 设置thirdSession
|
||||
ThirdSessionHolder.setThirdSession(thirdSession);
|
||||
}
|
||||
} else {
|
||||
R r = R.error(MyReturnCode.ERR_60002.getCode(), MyReturnCode.ERR_60002.getMsg());
|
||||
this.writerPrint(response, r);
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
private void writerPrint(HttpServletResponse response, R r) throws IOException {
|
||||
// 返回超时错误码,触发小程序重新登录
|
||||
response.setCharacterEncoding(CommonConstants.UTF8);
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.print(JSONUtil.parseObj(r));
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
package com.starry.weichat.mapper;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.starry.weichat.entity.WxAutoReply;
|
||||
|
||||
/**
|
||||
* 消息自动回复
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-04-18 15:40:39
|
||||
*/
|
||||
public interface WxAutoReplyMapper extends BaseMapper<WxAutoReply> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
package com.starry.weichat.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.starry.weichat.entity.WxMenu;
|
||||
|
||||
/**
|
||||
* 自定义菜单
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-27 16:52:10
|
||||
*/
|
||||
public interface WxMenuMapper extends BaseMapper<WxMenu> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
package com.starry.weichat.mapper;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.starry.weichat.entity.WxMsg;
|
||||
import com.starry.weichat.entity.WxMsgVO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 微信消息
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-05-28 16:12:10
|
||||
*/
|
||||
public interface WxMsgMapper extends BaseMapper<WxMsg> {
|
||||
|
||||
/**
|
||||
* 获取分组后的消息列表
|
||||
*
|
||||
* @param page
|
||||
* @param wxMsgVO
|
||||
* @return
|
||||
*/
|
||||
IPage listWxMsgMapGroup(Page<WxMsg> page, @Param("query") WxMsgVO wxMsgVO);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
package com.starry.weichat.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.starry.weichat.entity.WxUser;
|
||||
|
||||
/**
|
||||
* 微信用户
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-25 15:39:39
|
||||
*/
|
||||
public interface WxUserMapper extends BaseMapper<WxUser> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
package com.starry.weichat.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.starry.weichat.entity.WxAutoReply;
|
||||
|
||||
/**
|
||||
* 消息自动回复
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-04-18 15:40:39
|
||||
*/
|
||||
public interface WxAutoReplyService extends IService<WxAutoReply> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
package com.starry.weichat.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.starry.weichat.entity.WxMenu;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
|
||||
/**
|
||||
* 自定义菜单
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-27 16:52:10
|
||||
*/
|
||||
public interface WxMenuService extends IService<WxMenu> {
|
||||
|
||||
/***
|
||||
* 获取WxApp下的菜单
|
||||
* @return
|
||||
*/
|
||||
String getWxMenuButton();
|
||||
|
||||
/**
|
||||
* 保存并发布菜单
|
||||
*
|
||||
* @param
|
||||
*/
|
||||
void saveAndRelease(String strWxMenu) throws WxErrorException;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
package com.starry.weichat.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.starry.weichat.entity.WxMsg;
|
||||
import com.starry.weichat.entity.WxMsgVO;
|
||||
|
||||
/**
|
||||
* 微信消息
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-05-28 16:12:10
|
||||
*/
|
||||
public interface WxMsgService extends IService<WxMsg> {
|
||||
|
||||
/**
|
||||
* 获取分组后的消息列表
|
||||
*
|
||||
* @param page
|
||||
* @param wxMsgVO
|
||||
* @return
|
||||
*/
|
||||
IPage<WxMsg> listWxMsgMapGroup(Page<WxMsg> page, WxMsgVO wxMsgVO);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
package com.starry.weichat.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.starry.weichat.entity.WxOpenDataDTO;
|
||||
import com.starry.weichat.entity.WxUser;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
|
||||
/**
|
||||
* 微信用户
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-25 15:39:39
|
||||
*/
|
||||
public interface WxUserService extends IService<WxUser> {
|
||||
|
||||
/**
|
||||
* 同步微信用户
|
||||
*/
|
||||
void synchroWxUser() throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 修改用户备注
|
||||
*
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
boolean updateRemark(WxUser entity) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 认识标签
|
||||
*
|
||||
* @param taggingType
|
||||
* @param tagId
|
||||
* @param openIds
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
void tagging(String taggingType, Long tagId, String[] openIds) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 根据openId获取用户
|
||||
*
|
||||
* @param openId
|
||||
* @return
|
||||
*/
|
||||
WxUser getByOpenId(String openId);
|
||||
|
||||
/**
|
||||
* 小程序登录
|
||||
*
|
||||
* @param appId
|
||||
* @param jsCode
|
||||
* @return
|
||||
*/
|
||||
WxUser loginMa(String appId, String jsCode) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 新增、更新微信用户
|
||||
*
|
||||
* @param wxOpenDataDTO
|
||||
* @return
|
||||
*/
|
||||
WxUser saveOrUptateWxUser(WxOpenDataDTO wxOpenDataDTO);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
package com.starry.weichat.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.starry.weichat.entity.WxAutoReply;
|
||||
import com.starry.weichat.mapper.WxAutoReplyMapper;
|
||||
import com.starry.weichat.service.WxAutoReplyService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 消息自动回复
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-04-18 15:40:39
|
||||
*/
|
||||
@Service
|
||||
public class WxAutoReplyServiceImpl extends ServiceImpl<WxAutoReplyMapper, WxAutoReply> implements WxAutoReplyService {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
|
||||
package com.starry.weichat.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.starry.weichat.config.CommonConstants;
|
||||
import com.starry.weichat.entity.Menu;
|
||||
import com.starry.weichat.entity.MenuButton;
|
||||
import com.starry.weichat.entity.WxMenu;
|
||||
import com.starry.weichat.mapper.WxMenuMapper;
|
||||
import com.starry.weichat.service.WxMenuService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自定义菜单
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-27 16:52:10
|
||||
*/
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class WxMenuServiceImpl extends ServiceImpl<WxMenuMapper, WxMenu> implements WxMenuService {
|
||||
private final WxMpService wxService;
|
||||
|
||||
/***
|
||||
* 获取WxApp下的菜单树结构
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String getWxMenuButton() {
|
||||
// 查出一级菜单
|
||||
List<WxMenu> listWxMenu = baseMapper.selectList(Wrappers
|
||||
.<WxMenu>query().lambda()
|
||||
.eq(WxMenu::getParentId, CommonConstants.PARENT_ID).orderByAsc(WxMenu::getSort));
|
||||
Menu menu = new Menu();
|
||||
List<MenuButton> listMenuButton = new ArrayList<>();
|
||||
MenuButton menuButton;
|
||||
List<MenuButton> subButtons;
|
||||
MenuButton subButton;
|
||||
if (listWxMenu != null && !listWxMenu.isEmpty()) {
|
||||
for (WxMenu wxMenu : listWxMenu) {
|
||||
menuButton = new MenuButton();
|
||||
menuButton.setName(wxMenu.getName());
|
||||
String type = wxMenu.getType();
|
||||
if (StringUtils.isNotBlank(type)) {// 无二级菜单
|
||||
menuButton.setType(type);
|
||||
setButtonValue(menuButton, wxMenu);
|
||||
} else {// 有二级菜单
|
||||
// 查出二级菜单
|
||||
List<WxMenu> listWxMenu1 = baseMapper.selectList(Wrappers
|
||||
.<WxMenu>query().lambda()
|
||||
.eq(WxMenu::getParentId, wxMenu.getId()).orderByAsc(WxMenu::getSort));
|
||||
subButtons = new ArrayList<>();
|
||||
for (WxMenu wxMenu1 : listWxMenu1) {
|
||||
subButton = new MenuButton();
|
||||
String type1 = wxMenu1.getType();
|
||||
subButton.setName(wxMenu1.getName());
|
||||
subButton.setType(type1);
|
||||
setButtonValue(subButton, wxMenu1);
|
||||
subButtons.add(subButton);
|
||||
}
|
||||
menuButton.setSub_button(subButtons);
|
||||
}
|
||||
listMenuButton.add(menuButton);
|
||||
}
|
||||
}
|
||||
menu.setButton(listMenuButton);
|
||||
return menu.toString();
|
||||
}
|
||||
|
||||
void setButtonValue(MenuButton menuButton, WxMenu wxMenu) {
|
||||
menuButton.setKey(wxMenu.getId());
|
||||
menuButton.setUrl(wxMenu.getUrl());
|
||||
menuButton.setContent(wxMenu.getContent());
|
||||
menuButton.setRepContent(wxMenu.getRepContent());
|
||||
menuButton.setMedia_id(wxMenu.getRepMediaId());
|
||||
menuButton.setRepType(wxMenu.getRepType());
|
||||
menuButton.setRepName(wxMenu.getRepName());
|
||||
menuButton.setAppid(wxMenu.getMaAppId());
|
||||
menuButton.setPagepath(wxMenu.getMaPagePath());
|
||||
menuButton.setUrl(wxMenu.getUrl());
|
||||
menuButton.setRepUrl(wxMenu.getRepUrl());
|
||||
menuButton.setRepHqUrl(wxMenu.getRepHqUrl());
|
||||
menuButton.setRepDesc(wxMenu.getRepDesc());
|
||||
menuButton.setRepThumbMediaId(wxMenu.getRepThumbMediaId());
|
||||
menuButton.setRepThumbUrl(wxMenu.getRepThumbUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存并发布菜单
|
||||
*
|
||||
* @param
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveAndRelease(String strWxMenu) throws WxErrorException {
|
||||
Menu menu = Menu.fromJson(strWxMenu);
|
||||
List<MenuButton> buttons = menu.getButton();
|
||||
// 先删除
|
||||
baseMapper.delete(Wrappers
|
||||
.<WxMenu>query().lambda());
|
||||
WxMenu wxMenu = null;
|
||||
WxMenu wxMenu1 = null;
|
||||
int sort1 = 1;
|
||||
int sort2 = 1;
|
||||
// 入库
|
||||
for (MenuButton menuButton : buttons) {
|
||||
wxMenu = new WxMenu();
|
||||
setWxMenuValue(wxMenu, menuButton);
|
||||
wxMenu.setSort(sort1);
|
||||
wxMenu.setParentId(CommonConstants.PARENT_ID);
|
||||
baseMapper.insert(wxMenu);
|
||||
menuButton.setKey(wxMenu.getId());
|
||||
sort1++;
|
||||
for (MenuButton menuButton1 : menuButton.getSub_button()) {
|
||||
wxMenu1 = new WxMenu();
|
||||
setWxMenuValue(wxMenu1, menuButton1);
|
||||
wxMenu1.setSort(sort2);
|
||||
wxMenu1.setParentId(wxMenu.getId());
|
||||
baseMapper.insert(wxMenu1);
|
||||
menuButton1.setKey(wxMenu1.getId());
|
||||
sort2++;
|
||||
}
|
||||
}
|
||||
// 创建菜单
|
||||
wxService.getMenuService().menuCreate(menu.toString());
|
||||
}
|
||||
|
||||
void setWxMenuValue(WxMenu wxMenu, MenuButton menuButton) {
|
||||
wxMenu.setId(menuButton.getKey());
|
||||
wxMenu.setType(menuButton.getType());
|
||||
wxMenu.setName(menuButton.getName());
|
||||
wxMenu.setUrl(menuButton.getUrl());
|
||||
wxMenu.setRepMediaId(menuButton.getMedia_id());
|
||||
wxMenu.setRepType(menuButton.getRepType());
|
||||
wxMenu.setRepName(menuButton.getRepName());
|
||||
wxMenu.setMaAppId(menuButton.getAppid());
|
||||
wxMenu.setMaPagePath(menuButton.getPagepath());
|
||||
wxMenu.setRepContent(menuButton.getRepContent());
|
||||
wxMenu.setContent(menuButton.getContent());
|
||||
wxMenu.setRepUrl(menuButton.getRepUrl());
|
||||
wxMenu.setRepHqUrl(menuButton.getRepHqUrl());
|
||||
wxMenu.setRepDesc(menuButton.getRepDesc());
|
||||
wxMenu.setRepThumbMediaId(menuButton.getRepThumbMediaId());
|
||||
wxMenu.setRepThumbUrl(menuButton.getRepThumbUrl());
|
||||
menuButton.setRepUrl(null);
|
||||
menuButton.setRepDesc(null);
|
||||
menuButton.setRepHqUrl(null);
|
||||
menuButton.setContent(null);
|
||||
menuButton.setRepContent(null);
|
||||
menuButton.setRepType(null);
|
||||
menuButton.setRepName(null);
|
||||
menuButton.setRepThumbMediaId(null);
|
||||
menuButton.setRepThumbUrl(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
package com.starry.weichat.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.starry.weichat.entity.WxMsg;
|
||||
import com.starry.weichat.entity.WxMsgVO;
|
||||
import com.starry.weichat.mapper.WxMsgMapper;
|
||||
import com.starry.weichat.service.WxMsgService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 微信消息
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-05-28 16:12:10
|
||||
*/
|
||||
@Service
|
||||
public class WxMsgServiceImpl extends ServiceImpl<WxMsgMapper, WxMsg> implements WxMsgService {
|
||||
|
||||
@Override
|
||||
public IPage listWxMsgMapGroup(Page<WxMsg> page, WxMsgVO vo) {
|
||||
|
||||
// LambdaQueryWrapper<WxMsg> queryWrapper = new LambdaQueryWrapper<>();
|
||||
// if (StrUtil.isBlankIfStr(vo.getType())) {
|
||||
// queryWrapper.eq(WxMsg::getType, vo.getType());
|
||||
// }
|
||||
// if (StrUtil.isBlankIfStr(vo.getReadFlag())) {
|
||||
// queryWrapper.eq(WxMsg::getReadFlag, vo.getReadFlag());
|
||||
// }
|
||||
// if (StrUtil.isBlankIfStr(vo.getRepType())) {
|
||||
// queryWrapper.eq(WxMsg::getRepType, vo.getRepType());
|
||||
// }
|
||||
|
||||
return baseMapper.listWxMsgMapGroup(page, vo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
|
||||
package com.starry.weichat.service.impl;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaUserService;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.starry.weichat.config.WxMaConfiguration;
|
||||
import com.starry.weichat.constant.ConfigConstant;
|
||||
import com.starry.weichat.constant.WxMaConstants;
|
||||
import com.starry.weichat.entity.ThirdSession;
|
||||
import com.starry.weichat.entity.WxOpenDataDTO;
|
||||
import com.starry.weichat.entity.WxUser;
|
||||
import com.starry.weichat.handler.SubscribeHandler;
|
||||
import com.starry.weichat.mapper.WxUserMapper;
|
||||
import com.starry.weichat.service.WxUserService;
|
||||
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.api.WxMpUserService;
|
||||
import me.chanjar.weixin.mp.api.WxMpUserTagService;
|
||||
import me.chanjar.weixin.mp.bean.result.WxMpUser;
|
||||
import me.chanjar.weixin.mp.bean.result.WxMpUserList;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 微信用户
|
||||
*
|
||||
* @author admin
|
||||
* @since 2019-03-25 15:39:39
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class WxUserServiceImpl extends ServiceImpl<WxUserMapper, WxUser> implements WxUserService {
|
||||
|
||||
private final WxMpService wxService;
|
||||
private final RedisTemplate redisTemplate;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean updateRemark(WxUser entity) throws WxErrorException {
|
||||
String id = entity.getId();
|
||||
String remark = entity.getRemark();
|
||||
String openId = entity.getOpenId();
|
||||
entity = new WxUser();
|
||||
entity.setId(id);
|
||||
entity.setRemark(remark);
|
||||
super.updateById(entity);
|
||||
WxMpUserService wxMpUserService = wxService.getUserService();
|
||||
wxMpUserService.userUpdateRemark(openId, remark);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void tagging(String taggingType, Long tagId, String[] openIds) throws WxErrorException {
|
||||
WxMpUserTagService wxMpUserTagService = wxService.getUserTagService();
|
||||
WxUser wxUser;
|
||||
if ("tagging".equals(taggingType)) {
|
||||
for (String openId : openIds) {
|
||||
wxUser = baseMapper.selectOne(Wrappers.<WxUser>lambdaQuery()
|
||||
.eq(WxUser::getOpenId, openId));
|
||||
Long[] tagidList = wxUser.getTagidList();
|
||||
List<Long> list = Arrays.asList(tagidList);
|
||||
list = new ArrayList<>(list);
|
||||
if (!list.contains(tagId)) {
|
||||
list.add(tagId);
|
||||
tagidList = list.toArray(new Long[list.size()]);
|
||||
wxUser.setTagidList(tagidList);
|
||||
this.updateById(wxUser);
|
||||
}
|
||||
}
|
||||
wxMpUserTagService.batchTagging(tagId, openIds);
|
||||
}
|
||||
if ("unTagging".equals(taggingType)) {
|
||||
for (String openId : openIds) {
|
||||
wxUser = baseMapper.selectOne(Wrappers.<WxUser>lambdaQuery()
|
||||
.eq(WxUser::getOpenId, openId));
|
||||
Long[] tagidList = wxUser.getTagidList();
|
||||
List<Long> list = Arrays.asList(tagidList);
|
||||
list = new ArrayList<>(list);
|
||||
if (list.contains(tagId)) {
|
||||
list.remove(tagId);
|
||||
tagidList = list.toArray(new Long[list.size()]);
|
||||
wxUser.setTagidList(tagidList);
|
||||
this.updateById(wxUser);
|
||||
}
|
||||
}
|
||||
wxMpUserTagService.batchUntagging(tagId, openIds);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void synchroWxUser() throws WxErrorException {
|
||||
// 先将已关注的用户取关
|
||||
WxUser wxUser = new WxUser();
|
||||
wxUser.setSubscribe(ConfigConstant.SUBSCRIBE_TYPE_NO);
|
||||
this.baseMapper.update(wxUser, Wrappers.<WxUser>lambdaQuery()
|
||||
.eq(WxUser::getSubscribe, ConfigConstant.SUBSCRIBE_TYPE_YES));
|
||||
WxMpUserService wxMpUserService = wxService.getUserService();
|
||||
this.recursionGet(wxMpUserService, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归获取
|
||||
*
|
||||
* @param nextOpenid
|
||||
*/
|
||||
void recursionGet(WxMpUserService wxMpUserService, String nextOpenid) throws WxErrorException {
|
||||
WxMpUserList userList = wxMpUserService.userList(nextOpenid);
|
||||
List<WxUser> listWxUser = new ArrayList<>();
|
||||
List<WxMpUser> listWxMpUser = getWxMpUserList(wxMpUserService, userList.getOpenids());
|
||||
listWxMpUser.forEach(wxMpUser -> {
|
||||
WxUser wxUser = baseMapper.selectOne(Wrappers.<WxUser>lambdaQuery()
|
||||
.eq(WxUser::getOpenId, wxMpUser.getOpenId()));
|
||||
if (wxUser == null) {// 用户未存在
|
||||
wxUser = new WxUser();
|
||||
wxUser.setSubscribeNum(1);
|
||||
}
|
||||
SubscribeHandler.setWxUserValue(wxUser, wxMpUser);
|
||||
listWxUser.add(wxUser);
|
||||
});
|
||||
this.saveOrUpdateBatch(listWxUser);
|
||||
if (userList.getCount() >= 10000) {
|
||||
this.recursionGet(wxMpUserService, userList.getNextOpenid());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分批次获取微信粉丝信息 每批100条
|
||||
*
|
||||
* @param wxMpUserService
|
||||
* @param openidsList
|
||||
* @return
|
||||
* @throws WxErrorException
|
||||
* @author
|
||||
*/
|
||||
private List<WxMpUser> getWxMpUserList(WxMpUserService wxMpUserService, List<String> openidsList) throws WxErrorException {
|
||||
// 粉丝openid数量
|
||||
int count = openidsList.size();
|
||||
if (count <= 0) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<WxMpUser> list = Lists.newArrayList();
|
||||
List<WxMpUser> followersInfoList;
|
||||
int a = count % 100 > 0 ? count / 100 + 1 : count / 100;
|
||||
for (int i = 0; i < a; i++) {
|
||||
if (i + 1 < a) {
|
||||
log.debug("i:{},from:{},to:{}", i, i * 100, (i + 1) * 100);
|
||||
followersInfoList = wxMpUserService.userInfoList(openidsList.subList(i * 100, ((i + 1) * 100)));
|
||||
if (null != followersInfoList && !followersInfoList.isEmpty()) {
|
||||
list.addAll(followersInfoList);
|
||||
}
|
||||
} else {
|
||||
log.debug("i:{},from:{},to:{}", i, i * 100, count - i * 100);
|
||||
followersInfoList = wxMpUserService.userInfoList(openidsList.subList(i * 100, count));
|
||||
if (null != followersInfoList && !followersInfoList.isEmpty()) {
|
||||
list.addAll(followersInfoList);
|
||||
}
|
||||
}
|
||||
}
|
||||
log.debug("本批次获取微信粉丝数:{}", list.size());
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxUser getByOpenId(String openId) {
|
||||
return this.baseMapper.selectOne(Wrappers.<WxUser>lambdaQuery()
|
||||
.eq(WxUser::getOpenId, openId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public WxUser loginMa(String appId, String jsCode) throws WxErrorException {
|
||||
WxMaJscode2SessionResult jscode2session = WxMaConfiguration.getMaService(appId).jsCode2SessionInfo(jsCode);
|
||||
WxUser wxUser = this.getByOpenId(jscode2session.getOpenid());
|
||||
if (wxUser == null) {
|
||||
// 新增微信用户
|
||||
wxUser = new WxUser();
|
||||
wxUser.setAppType(ConfigConstant.WX_APP_TYPE_1);
|
||||
wxUser.setOpenId(jscode2session.getOpenid());
|
||||
wxUser.setSessionKey(jscode2session.getSessionKey());
|
||||
wxUser.setUnionId(jscode2session.getUnionid());
|
||||
try {
|
||||
this.save(wxUser);
|
||||
} catch (DuplicateKeyException e) {
|
||||
if (e.getMessage().contains("uk_appid_openid")) {
|
||||
wxUser = this.getByOpenId(wxUser.getOpenId());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 更新SessionKey
|
||||
wxUser.setAppType(ConfigConstant.WX_APP_TYPE_1);
|
||||
wxUser.setOpenId(jscode2session.getOpenid());
|
||||
wxUser.setSessionKey(jscode2session.getSessionKey());
|
||||
wxUser.setUnionId(jscode2session.getUnionid());
|
||||
this.updateById(wxUser);
|
||||
}
|
||||
|
||||
String thirdSessionKey = UUID.randomUUID().toString();
|
||||
ThirdSession thirdSession = new ThirdSession();
|
||||
thirdSession.setAppId(appId);
|
||||
thirdSession.setSessionKey(wxUser.getSessionKey());
|
||||
thirdSession.setWxUserId(wxUser.getId());
|
||||
thirdSession.setOpenId(wxUser.getOpenId());
|
||||
// 将3rd_session和用户信息存入redis,并设置过期时间
|
||||
String key = WxMaConstants.THIRD_SESSION_BEGIN + ":" + thirdSessionKey;
|
||||
redisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(thirdSession), WxMaConstants.TIME_OUT_SESSION, TimeUnit.HOURS);
|
||||
wxUser.setSessionKey(thirdSessionKey);
|
||||
return wxUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public WxUser saveOrUptateWxUser(WxOpenDataDTO wxOpenDataDTO) {
|
||||
WxMaUserService wxMaUserService = WxMaConfiguration.getMaService(wxOpenDataDTO.getAppId()).getUserService();
|
||||
WxMaUserInfo wxMaUserInfo = wxMaUserService.getUserInfo(wxOpenDataDTO.getSessionKey(), wxOpenDataDTO.getEncryptedData(), wxOpenDataDTO.getIv());
|
||||
WxUser wxUser = new WxUser();
|
||||
BeanUtil.copyProperties(wxMaUserInfo, wxUser);
|
||||
wxUser.setId(wxOpenDataDTO.getUserId());
|
||||
wxUser.setSex(wxMaUserInfo.getGender());
|
||||
wxUser.setHeadimgUrl(wxMaUserInfo.getAvatarUrl());
|
||||
baseMapper.updateById(wxUser);
|
||||
wxUser = baseMapper.selectById(wxUser.getId());
|
||||
return wxUser;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
package com.starry.weichat.utils;
|
||||
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
|
||||
/**
|
||||
* file工具
|
||||
* @author admin
|
||||
*/
|
||||
public class FileUtils {
|
||||
|
||||
/**
|
||||
* 将MultipartFile转为File
|
||||
*
|
||||
* @param mulFile
|
||||
* @return
|
||||
*/
|
||||
public static File multipartFileToFile(MultipartFile mulFile) throws IOException {
|
||||
InputStream ins = mulFile.getInputStream();
|
||||
String fileName = mulFile.getOriginalFilename();
|
||||
String prefix = getFileNameNoEx(fileName) + UUID.fastUUID();
|
||||
String suffix = "." + getExtensionName(fileName);
|
||||
File toFile = File.createTempFile(prefix, suffix);
|
||||
OutputStream os = Files.newOutputStream(toFile.toPath());
|
||||
int bytesRead;
|
||||
byte[] buffer = new byte[8192];
|
||||
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
|
||||
os.write(buffer, 0, bytesRead);
|
||||
}
|
||||
os.close();
|
||||
ins.close();
|
||||
return toFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件扩展名
|
||||
*/
|
||||
public static String getExtensionName(String filename) {
|
||||
if ((filename != null) && (!filename.isEmpty())) {
|
||||
int dot = filename.lastIndexOf('.');
|
||||
if ((dot > -1) && (dot < (filename.length() - 1))) {
|
||||
return filename.substring(dot + 1);
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取不带扩展名的文件名
|
||||
*/
|
||||
public static String getFileNameNoEx(String filename) {
|
||||
if ((filename != null) && (!filename.isEmpty())) {
|
||||
int dot = filename.lastIndexOf('.');
|
||||
if (dot > -1) {
|
||||
return filename.substring(0, dot);
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
package com.starry.weichat.utils;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* @author admin
|
||||
*/
|
||||
public class JsonUtils {
|
||||
public static String toJson(Object obj) {
|
||||
Gson gson = new GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
return gson.toJson(obj);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
|
||||
package com.starry.weichat.utils;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.temporal.ChronoField;
|
||||
|
||||
/**
|
||||
* LocalDateTime时间工具
|
||||
* @author admin
|
||||
*/
|
||||
public class LocalDateTimeUtils {
|
||||
|
||||
public static final String YYYY = "yyyy";
|
||||
public static final String YYYYMM = "yyyyMM";
|
||||
public static final String YYYYMMDD = "yyyyMMdd";
|
||||
public static final String YYYYMMDDHH = "yyyyMMddHH";
|
||||
public static final String YYYYMMDDHHMM = "yyyyMMddHHmm";
|
||||
public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
|
||||
public static final String YYYY_MM = "yyyy-MM";
|
||||
public static final String YYYY_MM_DD = "yyyy-MM-dd";
|
||||
public static final String YYYY_MM_DD_HH = "yyyy-MM-dd HH";
|
||||
public static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";
|
||||
public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
private static final String BASE_TIME_FORMAT = "[yyyyMMddHHmmss][yyyyMMddHHmm][yyyyMMddHH][yyyyMMdd][yyyyMM][yyyy][[-][/][.]MM][[-][/][.]dd][ ][HH][[:][.]mm][[:][.]ss][[:][.]SSS]";
|
||||
|
||||
/**
|
||||
* 【推荐】解析常用时间字符串,支持,并不局限于以下形式:
|
||||
* [yyyy][yyyy-MM][yyyy-MM-dd][yyyy-MM-dd HH][yyyy-MM-dd HH:mm][yyyy-MM-dd HH:mm:ss][yyyy-MM-dd HH:mm:ss:SSS]
|
||||
* [yyyy][yyyy/MM][yyyy/MM/dd][yyyy/MM/dd HH][yyyy/MM/dd HH:mm][yyyy/MM/dd HH:mm:ss][yyyy/MM/dd HH:mm:ss:SSS]
|
||||
* [yyyy][yyyy.MM][yyyy.MM.dd][yyyy.MM.dd HH][yyyy.MM.dd HH.mm][yyyy.MM.dd HH.mm.ss][yyyy.MM.dd HH.mm.ss.SSS]
|
||||
* [yyyy][yyyyMM][yyyyMMdd][yyyyMMddHH][yyyyMMddHHmm][yyyyMMddHHmmss]
|
||||
* [MM-dd]
|
||||
* 不支持yyyyMMddHHmmssSSS,因为本身DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")就不支持这个形式
|
||||
*
|
||||
* @param timeString
|
||||
* @return
|
||||
*/
|
||||
public static LocalDateTime parse(String timeString) {
|
||||
return LocalDateTime.parse(timeString, getDateTimeFormatterByPattern(BASE_TIME_FORMAT));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据传进来的pattern返回LocalDateTime,自动补齐
|
||||
*
|
||||
* @param timeString
|
||||
* @param pattern
|
||||
* @return
|
||||
*/
|
||||
public static LocalDateTime parseByPattern(String timeString, String pattern) {
|
||||
return LocalDateTime.parse(timeString, getDateTimeFormatterByPattern(pattern));
|
||||
}
|
||||
|
||||
private static DateTimeFormatter getDateTimeFormatterByPattern(String pattern) {
|
||||
return new DateTimeFormatterBuilder()
|
||||
.appendPattern(pattern)
|
||||
.parseDefaulting(ChronoField.YEAR_OF_ERA, LocalDateTime.now().getYear())
|
||||
.parseDefaulting(ChronoField.MONTH_OF_YEAR, LocalDateTime.now().getMonthValue())
|
||||
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
|
||||
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
|
||||
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
|
||||
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
|
||||
.parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
|
||||
.toFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将timestamp转为LocalDateTime
|
||||
*
|
||||
* @param timestamp
|
||||
* @return
|
||||
*/
|
||||
public static LocalDateTime timestamToDatetime(long timestamp) {
|
||||
Instant instant = Instant.ofEpochMilli(timestamp);
|
||||
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将LocalDataTime转为timestamp
|
||||
*
|
||||
* @param ldt
|
||||
* @return
|
||||
*/
|
||||
public static long datatimeToTimestamp(LocalDateTime ldt) {
|
||||
ZoneId zone = ZoneId.systemDefault();
|
||||
return ldt.atZone(zone).toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.starry.weichat.utils;
|
||||
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import com.starry.weichat.entity.ThirdSession;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
/**
|
||||
* @author thirdSession工具类
|
||||
*/
|
||||
@UtilityClass
|
||||
public class ThirdSessionHolder {
|
||||
|
||||
private final ThreadLocal<ThirdSession> THREAD_LOCAL_THIRD_SESSION = new TransmittableThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 获取TTL中的thirdSession
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ThirdSession getThirdSession() {
|
||||
return THREAD_LOCAL_THIRD_SESSION.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* TTL 设置thirdSession
|
||||
*
|
||||
* @param thirdSession
|
||||
*/
|
||||
public void setThirdSession(ThirdSession thirdSession) {
|
||||
THREAD_LOCAL_THIRD_SESSION.set(thirdSession);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
THREAD_LOCAL_THIRD_SESSION.remove();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户商城ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getWxUserId() {
|
||||
return THREAD_LOCAL_THIRD_SESSION.get().getWxUserId();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2018-2019
|
||||
~ All rights reserved, Designed By admin
|
||||
-->
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.starry.weichat.mapper.WxMsgMapper">
|
||||
<select id="listWxMsgMapGroup" resultType="com.baomidou.mybatisplus.core.metadata.IPage">
|
||||
select a.*,
|
||||
b.count_msg
|
||||
from
|
||||
wx_msg as a
|
||||
right join
|
||||
(select `wx_user_id`,
|
||||
max(`create_time`) as maxtime,
|
||||
count(`wx_user_id`) as count_msg
|
||||
from wx_msg
|
||||
<where>
|
||||
<if test="query.type != null and query.type != ''">
|
||||
AND `type` = #{query.type}
|
||||
</if>
|
||||
<if test="query.readFlag != null and query.readFlag != ''">
|
||||
AND `read_flag` = #{query.readFlag}
|
||||
</if>
|
||||
<if test="query.notInRepType != null and query.notInRepType != ''">
|
||||
AND `rep_type` NOT IN (#{query.notInRepType})
|
||||
</if>
|
||||
</where>
|
||||
group by `wx_user_id`) as b
|
||||
on a.`wx_user_id` = b.`wx_user_id`
|
||||
and a.`create_time` = b.maxtime
|
||||
order by a.`create_time` desc ;
|
||||
</select>
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user