mirror of
https://gitcode.com/ageerle/ruoyi-ai.git
synced 2026-03-25 10:33:43 +08:00
feat: 新增wechat模块
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package org.ruoyi.service;
|
||||
|
||||
/**
|
||||
* 企业微信聊天管理Service接口
|
||||
*
|
||||
* @author ageerle
|
||||
* @date 2025-04-08
|
||||
*/
|
||||
public interface IChatVxService {
|
||||
|
||||
|
||||
/**
|
||||
* 企业微信应用回复
|
||||
* @param prompt 提示词
|
||||
* @return 回复内容
|
||||
*/
|
||||
String chat(String prompt);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.ruoyi.service.impl;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatCompletion;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatCompletionResponse;
|
||||
import org.ruoyi.common.chat.entity.chat.Message;
|
||||
import org.ruoyi.common.chat.openai.OpenAiStreamClient;
|
||||
import org.ruoyi.service.IChatVxService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class ChatVxServiceImpl implements IChatVxService {
|
||||
|
||||
private final OpenAiStreamClient openAiStreamClient;
|
||||
|
||||
@Override
|
||||
public String chat(String prompt) {
|
||||
List<Message> messageList = new ArrayList<>();
|
||||
Message message = Message.builder().role(Message.Role.USER).content(prompt).build();
|
||||
messageList.add(message);
|
||||
ChatCompletion chatCompletion = ChatCompletion
|
||||
.builder()
|
||||
.messages(messageList)
|
||||
.model("gpt-4o-mini")
|
||||
.stream(false)
|
||||
.build();
|
||||
ChatCompletionResponse chatCompletionResponse = openAiStreamClient.chatCompletion(chatCompletion);
|
||||
return chatCompletionResponse.getChoices().get(0).getMessage().getContent().toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,6 +21,7 @@
|
||||
<module>ruoyi-chat</module>
|
||||
<module>ruoyi-system</module>
|
||||
<module>ruoyi-generator</module>
|
||||
<module>ruoyi-wechat</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -48,11 +48,4 @@ public interface ISseService {
|
||||
UploadFileResponse upload(MultipartFile file);
|
||||
|
||||
|
||||
/**
|
||||
* 企业应用回复
|
||||
* @param prompt 提示词
|
||||
* @return 回复内容
|
||||
*/
|
||||
String wxCpChat(String prompt);
|
||||
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@ import org.ruoyi.chat.util.IpUtil;
|
||||
import org.ruoyi.chat.util.SSEUtil;
|
||||
import org.ruoyi.common.chat.config.LocalCache;
|
||||
import org.ruoyi.common.chat.entity.Tts.TextToSpeech;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatCompletion;
|
||||
import org.ruoyi.common.chat.entity.chat.ChatCompletionResponse;
|
||||
import org.ruoyi.common.chat.entity.chat.Message;
|
||||
import org.ruoyi.common.chat.entity.files.UploadFileResponse;
|
||||
import org.ruoyi.common.chat.entity.whisper.WhisperResponse;
|
||||
@@ -271,20 +269,4 @@ public class SseServiceImpl implements ISseService {
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String wxCpChat(String prompt) {
|
||||
List<Message> messageList = new ArrayList<>();
|
||||
Message message = Message.builder().role(Message.Role.USER).content(prompt).build();
|
||||
messageList.add(message);
|
||||
ChatCompletion chatCompletion = ChatCompletion
|
||||
.builder()
|
||||
.messages(messageList)
|
||||
.model("gpt-4o-mini")
|
||||
.stream(false)
|
||||
.build();
|
||||
ChatCompletionResponse chatCompletionResponse = openAiStreamClient.chatCompletion(chatCompletion);
|
||||
return chatCompletionResponse.getChoices().get(0).getMessage().getContent().toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
28
ruoyi-modules/ruoyi-wechat/pom.xml
Normal file
28
ruoyi-modules/ruoyi-wechat/pom.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
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>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>ruoyi-wechat</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.ruoyi</groupId>
|
||||
<artifactId>ruoyi-chat-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.ruoyi.builder;
|
||||
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public abstract class AbstractBuilder {
|
||||
public abstract WxCpXmlOutMessage build(String content, WxCpXmlMessage wxMessage, WxCpService service);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.ruoyi.builder;
|
||||
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutImageMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public class ImageBuilder extends AbstractBuilder {
|
||||
|
||||
@Override
|
||||
public WxCpXmlOutMessage build(String content, WxCpXmlMessage wxMessage,
|
||||
WxCpService service) {
|
||||
|
||||
WxCpXmlOutImageMessage m = WxCpXmlOutMessage.IMAGE().mediaId(content)
|
||||
.fromUser(wxMessage.getToUserName()).toUser(wxMessage.getFromUserName())
|
||||
.build();
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.ruoyi.builder;
|
||||
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutTextMessage;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public class TextBuilder extends AbstractBuilder {
|
||||
|
||||
@Override
|
||||
public WxCpXmlOutMessage build(String content, WxCpXmlMessage wxMessage,
|
||||
WxCpService service) {
|
||||
WxCpXmlOutTextMessage m = WxCpXmlOutMessage.TEXT().content(content)
|
||||
.fromUser(wxMessage.getToUserName()).toUser(wxMessage.getFromUserName())
|
||||
.build();
|
||||
return m;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package org.ruoyi.config;
|
||||
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.val;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
|
||||
import me.chanjar.weixin.cp.constant.WxCpConsts;
|
||||
import me.chanjar.weixin.cp.message.WxCpMessageHandler;
|
||||
import me.chanjar.weixin.cp.message.WxCpMessageRouter;
|
||||
import org.ruoyi.handler.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 单实例配置
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(WxCpProperties.class)
|
||||
public class WxCpConfiguration {
|
||||
private final LogHandler logHandler;
|
||||
private NullHandler nullHandler;
|
||||
private LocationHandler locationHandler;
|
||||
private MenuHandler menuHandler;
|
||||
private MsgHandler msgHandler;
|
||||
private final UnsubscribeHandler unsubscribeHandler;
|
||||
private SubscribeHandler subscribeHandler;
|
||||
private WxCpProperties properties;
|
||||
|
||||
private static Map<Integer, WxCpMessageRouter> routers = Maps.newHashMap();
|
||||
private static Map<Integer, WxCpService> cpServices = Maps.newHashMap();
|
||||
|
||||
@Autowired
|
||||
public WxCpConfiguration(LogHandler logHandler, NullHandler nullHandler, LocationHandler locationHandler,
|
||||
MenuHandler menuHandler, MsgHandler msgHandler, UnsubscribeHandler unsubscribeHandler,
|
||||
SubscribeHandler subscribeHandler, WxCpProperties properties) {
|
||||
this.logHandler = logHandler;
|
||||
this.nullHandler = nullHandler;
|
||||
this.locationHandler = locationHandler;
|
||||
this.menuHandler = menuHandler;
|
||||
this.msgHandler = msgHandler;
|
||||
this.unsubscribeHandler = unsubscribeHandler;
|
||||
this.subscribeHandler = subscribeHandler;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
|
||||
public static Map<Integer, WxCpMessageRouter> getRouters() {
|
||||
return routers;
|
||||
}
|
||||
|
||||
public static WxCpService getCpService(Integer agentId) {
|
||||
return cpServices.get(agentId);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void initServices() {
|
||||
cpServices = this.properties.getAppConfigs().stream().map(a -> {
|
||||
val configStorage = new WxCpDefaultConfigImpl();
|
||||
configStorage.setCorpId(this.properties.getCorpId());
|
||||
configStorage.setAgentId(a.getAgentId());
|
||||
configStorage.setCorpSecret(a.getSecret());
|
||||
configStorage.setToken(a.getToken());
|
||||
configStorage.setAesKey(a.getAesKey());
|
||||
val service = new WxCpServiceImpl();
|
||||
service.setWxCpConfigStorage(configStorage);
|
||||
routers.put(a.getAgentId(), this.newRouter(service));
|
||||
return service;
|
||||
}).collect(Collectors.toMap(service -> service.getWxCpConfigStorage().getAgentId(), a -> a));
|
||||
}
|
||||
|
||||
private WxCpMessageRouter newRouter(WxCpService wxCpService) {
|
||||
final val newRouter = new WxCpMessageRouter(wxCpService);
|
||||
|
||||
// 记录所有事件的日志 (异步执行)
|
||||
newRouter.rule().handler(this.logHandler).next();
|
||||
|
||||
// 自定义菜单事件
|
||||
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
|
||||
.event(WxConsts.MenuButtonType.CLICK).handler(this.menuHandler).end();
|
||||
|
||||
// 点击菜单链接事件(这里使用了一个空的处理器,可以根据自己需要进行扩展)
|
||||
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
|
||||
.event(WxConsts.MenuButtonType.VIEW).handler(this.nullHandler).end();
|
||||
|
||||
// 关注事件
|
||||
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
|
||||
.event(WxConsts.EventType.SUBSCRIBE).handler(this.subscribeHandler)
|
||||
.end();
|
||||
|
||||
// 取消关注事件
|
||||
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
|
||||
.event(WxConsts.EventType.UNSUBSCRIBE)
|
||||
.handler((WxCpMessageHandler) this.unsubscribeHandler).end();
|
||||
|
||||
// 上报地理位置事件
|
||||
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.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(WxConsts.XmlMsgType.EVENT)
|
||||
.event(WxConsts.EventType.SCAN).handler((WxCpMessageHandler) this.nullHandler).end();
|
||||
|
||||
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
|
||||
.event(WxCpConsts.EventType.CHANGE_CONTACT).handler(new ContactChangeHandler()).end();
|
||||
|
||||
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
|
||||
.event(WxCpConsts.EventType.ENTER_AGENT).handler(new EnterAgentHandler()).end();
|
||||
|
||||
// 默认
|
||||
newRouter.rule().async(false).handler(this.msgHandler).end();
|
||||
|
||||
return newRouter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.ruoyi.config;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Data
|
||||
public class WxCpProperties {
|
||||
/**
|
||||
* 设置企业微信的corpId
|
||||
*/
|
||||
private String corpId;
|
||||
|
||||
private List<AppConfig> appConfigs;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class AppConfig {
|
||||
/**
|
||||
* 设置企业微信应用的AgentId
|
||||
*/
|
||||
private Integer agentId;
|
||||
|
||||
/**
|
||||
* 设置企业微信应用的Secret
|
||||
*/
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* 设置企业微信应用的token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 设置企业微信应用的EncodingAESKey
|
||||
*/
|
||||
private String aesKey;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.ruoyi.controller.wxcplogin;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
|
||||
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.ruoyi.common.core.utils.JsonUtils;
|
||||
|
||||
import org.ruoyi.config.WxCpConfiguration;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/wx/cp")
|
||||
@Slf4j
|
||||
public class WxPortalController {
|
||||
|
||||
@Value("${wechat.cp.appConfigs[0].agentId}")
|
||||
private Integer agentId;
|
||||
|
||||
|
||||
@GetMapping(produces = "text/plain;charset=utf-8")
|
||||
public String authGet(
|
||||
@RequestParam(name = "msg_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 = [{}]",
|
||||
signature, timestamp, nonce, echostr);
|
||||
|
||||
if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
|
||||
throw new IllegalArgumentException("请求参数非法,请核实!");
|
||||
}
|
||||
|
||||
final WxCpService wxCpService = WxCpConfiguration.getCpService(agentId);
|
||||
if (wxCpService == null) {
|
||||
throw new IllegalArgumentException(String.format("未找到对应agentId=[%d]的配置,请核实!", agentId));
|
||||
}
|
||||
|
||||
if (wxCpService.checkSignature(signature, timestamp, nonce, echostr)) {
|
||||
return new WxCpCryptUtil(wxCpService.getWxCpConfigStorage()).decrypt(echostr);
|
||||
}
|
||||
|
||||
return "非法请求";
|
||||
}
|
||||
|
||||
@PostMapping(produces = "application/xml; charset=UTF-8")
|
||||
public String post(
|
||||
@RequestBody String requestBody,
|
||||
@RequestParam("msg_signature") String signature,
|
||||
@RequestParam("timestamp") String timestamp,
|
||||
@RequestParam("nonce") String nonce) {
|
||||
log.info("\n接收微信请求:[signature=[{}], timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
|
||||
signature, timestamp, nonce, requestBody);
|
||||
|
||||
final WxCpService wxCpService = WxCpConfiguration.getCpService(1000002);
|
||||
WxCpXmlMessage inMessage = WxCpXmlMessage.fromEncryptedXml(requestBody, wxCpService.getWxCpConfigStorage(),
|
||||
timestamp, nonce, signature);
|
||||
log.debug("\n消息解密后内容为:\n{} ", JsonUtils.toJson(inMessage));
|
||||
WxCpXmlOutMessage outMessage = this.route(1000002, inMessage);
|
||||
if (outMessage == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String out = outMessage.toEncryptedXml(wxCpService.getWxCpConfigStorage());
|
||||
log.debug("\n组装回复信息:{}", out);
|
||||
return out;
|
||||
}
|
||||
|
||||
private WxCpXmlOutMessage route(Integer agentId, WxCpXmlMessage message) {
|
||||
try {
|
||||
return WxCpConfiguration.getRouters().get(agentId).route(message);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.ruoyi.handler;
|
||||
|
||||
import me.chanjar.weixin.cp.message.WxCpMessageHandler;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public abstract class AbstractHandler implements WxCpMessageHandler {
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.ruoyi.handler;
|
||||
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
|
||||
import org.ruoyi.builder.TextBuilder;
|
||||
import org.ruoyi.common.core.utils.JsonUtils;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 通讯录变更事件处理器.
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ContactChangeHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService cpService,
|
||||
WxSessionManager sessionManager) {
|
||||
String content = "收到通讯录变更事件,内容:" + JsonUtils.toJson(wxMessage);
|
||||
log.info(content);
|
||||
|
||||
return new TextBuilder().build(content, wxMessage, cpService);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.ruoyi.handler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
*
|
||||
* Created by Binary Wang on 2018/8/27.
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Slf4j
|
||||
public class EnterAgentHandler extends AbstractHandler {
|
||||
private static final int TEST_AGENT = 1000002;
|
||||
|
||||
@Override
|
||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService wxCpService, WxSessionManager sessionManager) throws WxErrorException {
|
||||
// do something
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.ruoyi.handler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
|
||||
import org.ruoyi.builder.TextBuilder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class LocationHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService cpService,
|
||||
WxSessionManager sessionManager) {
|
||||
if (wxMessage.getMsgType().equals(WxConsts.XmlMsgType.LOCATION)) {
|
||||
//TODO 接收处理用户发送的地理位置消息
|
||||
try {
|
||||
String content = "感谢反馈,您的的地理位置已收到!";
|
||||
return new TextBuilder().build(content, wxMessage, null);
|
||||
} catch (Exception e) {
|
||||
log.error("位置消息接收处理失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//上报地理位置事件
|
||||
log.info("\n上报地理位置,纬度 : {}\n经度 : {}\n精度 : {}",
|
||||
wxMessage.getLatitude(), wxMessage.getLongitude(), String.valueOf(wxMessage.getPrecision()));
|
||||
|
||||
//TODO 可以将用户地理位置信息保存到本地数据库,以便以后使用
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.ruoyi.handler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
|
||||
import org.ruoyi.common.core.utils.JsonUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class LogHandler extends AbstractHandler {
|
||||
@Override
|
||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService cpService,
|
||||
WxSessionManager sessionManager) {
|
||||
log.info("\n接收到请求消息,内容:{}", JsonUtils.toJson(wxMessage));
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.ruoyi.handler;
|
||||
|
||||
import me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Component
|
||||
public class MenuHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService cpService,
|
||||
WxSessionManager sessionManager) {
|
||||
|
||||
String msg = String.format("type:%s, event:%s, key:%s",
|
||||
wxMessage.getMsgType(), wxMessage.getEvent(),
|
||||
wxMessage.getEventKey());
|
||||
if (MenuButtonType.VIEW.equals(wxMessage.getEvent())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return WxCpXmlOutMessage.TEXT().content(msg)
|
||||
.fromUser(wxMessage.getToUserName()).toUser(wxMessage.getFromUserName())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.ruoyi.handler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
|
||||
|
||||
import org.ruoyi.builder.TextBuilder;
|
||||
import org.ruoyi.service.IChatVxService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class MsgHandler extends AbstractHandler {
|
||||
|
||||
private final IChatVxService chatVxService;
|
||||
|
||||
@Override
|
||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService cpService,
|
||||
WxSessionManager sessionManager) {
|
||||
final String msgType = wxMessage.getMsgType();
|
||||
if (msgType == null) {
|
||||
// 如果msgType没有,就自己根据具体报文内容做处理
|
||||
}
|
||||
|
||||
if (!msgType.equals(WxConsts.XmlMsgType.EVENT)) {
|
||||
//TODO 可以选择将消息保存到本地
|
||||
}
|
||||
//TODO 组装回复消息
|
||||
String content = chatVxService.chat(wxMessage.getContent());
|
||||
|
||||
return new TextBuilder().build(content, wxMessage, cpService);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.ruoyi.handler;
|
||||
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Component
|
||||
public class NullHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService cpService,
|
||||
WxSessionManager sessionManager) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.ruoyi.handler;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public abstract class ScanHandler extends AbstractHandler {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.ruoyi.handler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.WxCpUser;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
|
||||
import org.ruoyi.builder.TextBuilder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SubscribeHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService cpService,
|
||||
WxSessionManager sessionManager) throws WxErrorException {
|
||||
|
||||
log.info("新关注用户 OPENID: " + wxMessage.getFromUserName());
|
||||
|
||||
// 获取微信用户基本信息
|
||||
WxCpUser userWxInfo = cpService.getUserService().getById(wxMessage.getFromUserName());
|
||||
|
||||
if (userWxInfo != null) {
|
||||
// TODO 可以添加关注用户到本地
|
||||
}
|
||||
|
||||
WxCpXmlOutMessage responseResult = null;
|
||||
try {
|
||||
responseResult = handleSpecial(wxMessage);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (responseResult != null) {
|
||||
return responseResult;
|
||||
}
|
||||
|
||||
try {
|
||||
return new TextBuilder().build("感谢关注", wxMessage, cpService);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理特殊请求,比如如果是扫码进来的,可以做相应处理
|
||||
*/
|
||||
private WxCpXmlOutMessage handleSpecial(WxCpXmlMessage wxMessage) {
|
||||
//TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.ruoyi.handler;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
|
||||
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class UnsubscribeHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> context, WxCpService cpService,
|
||||
WxSessionManager sessionManager) {
|
||||
String openId = wxMessage.getFromUserName();
|
||||
log.info("取消关注用户 OPENID: " + openId);
|
||||
// TODO 可以更新本地数据库为取消关注状态
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user