办学质量监测教学评价系统
ageerle
2025-04-30 cd490aa0e5c208c90d00fabba3d4951fc8837aee
feat: 新增wechat模块
已修改3个文件
已添加20个文件
770 ■■■■■ 文件已修改
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatVxService.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatVxServiceImpl.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/pom.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/ISseService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/pom.xml 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/builder/AbstractBuilder.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/builder/ImageBuilder.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/builder/TextBuilder.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/config/WxCpConfiguration.java 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/config/WxCpProperties.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/controller/wxcplogin/WxPortalController.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/AbstractHandler.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/ContactChangeHandler.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/EnterAgentHandler.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/LocationHandler.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/LogHandler.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/MenuHandler.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/MsgHandler.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/NullHandler.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/ScanHandler.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/SubscribeHandler.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/UnsubscribeHandler.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatVxService.java
¶Ô±ÈÐÂÎļþ
@@ -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);
}
ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatVxServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -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();
    }
}
ruoyi-modules/pom.xml
@@ -21,6 +21,7 @@
        <module>ruoyi-chat</module>
        <module>ruoyi-system</module>
        <module>ruoyi-generator</module>
        <module>ruoyi-wechat</module>
    </modules>
    <properties>
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/ISseService.java
@@ -48,11 +48,4 @@
    UploadFileResponse upload(MultipartFile file);
    /**
     * ä¼ä¸šåº”用回复
     * @param prompt æç¤ºè¯
     * @return å›žå¤å†…容
     */
    String wxCpChat(String prompt);
}
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/SseServiceImpl.java
@@ -14,8 +14,6 @@
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;
@@ -269,22 +267,6 @@
            e.printStackTrace();
        }
        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();
    }
}
ruoyi-modules/ruoyi-wechat/pom.xml
¶Ô±ÈÐÂÎļþ
@@ -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>
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/builder/AbstractBuilder.java
¶Ô±ÈÐÂÎļþ
@@ -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);
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/builder/ImageBuilder.java
¶Ô±ÈÐÂÎļþ
@@ -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;
  }
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/builder/TextBuilder.java
¶Ô±ÈÐÂÎļþ
@@ -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;
  }
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/config/WxCpConfiguration.java
¶Ô±ÈÐÂÎļþ
@@ -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;
    }
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/config/WxCpProperties.java
¶Ô±ÈÐÂÎļþ
@@ -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;
  }
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/controller/wxcplogin/WxPortalController.java
¶Ô±ÈÐÂÎļþ
@@ -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;
  }
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/AbstractHandler.java
¶Ô±ÈÐÂÎļþ
@@ -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 {
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/ContactChangeHandler.java
¶Ô±ÈÐÂÎļþ
@@ -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);
    }
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/EnterAgentHandler.java
¶Ô±ÈÐÂÎļþ
@@ -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;
    }
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/LocationHandler.java
¶Ô±ÈÐÂÎļþ
@@ -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;
    }
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/LogHandler.java
¶Ô±ÈÐÂÎļþ
@@ -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;
    }
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/MenuHandler.java
¶Ô±ÈÐÂÎļþ
@@ -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();
  }
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/MsgHandler.java
¶Ô±ÈÐÂÎļþ
@@ -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);
    }
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/NullHandler.java
¶Ô±ÈÐÂÎļþ
@@ -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;
  }
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/ScanHandler.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package org.ruoyi.handler;
/**
 * @author <a href="https://github.com/binarywang">Binary Wang</a>
 */
public abstract class ScanHandler extends AbstractHandler {
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/SubscribeHandler.java
¶Ô±ÈÐÂÎļþ
@@ -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;
    }
}
ruoyi-modules/ruoyi-wechat/src/main/java/org/ruoyi/handler/UnsubscribeHandler.java
¶Ô±ÈÐÂÎļþ
@@ -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;
    }
}