Procházet zdrojové kódy

企业微信增加支持多个企业微信账户

pzc před 4 roky
rodič
revize
d14dd33c92

+ 2 - 4
mpwechatApp/mpwechatApp.iml

@@ -25,8 +25,6 @@
     </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="library" name="Maven: com.alibaba:druid-spring-boot-starter:1.1.17" level="project" />
-    <orderEntry type="library" name="Maven: com.alibaba:druid:1.1.17" level="project" />
     <orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-starter-netflix-eureka-client:2.0.0.RELEASE" level="project" />
     <orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-starter:2.0.0.RELEASE" level="project" />
     <orderEntry type="library" name="Maven: org.springframework.cloud:spring-cloud-context:2.0.0.RELEASE" level="project" />
@@ -195,8 +193,8 @@
     <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.0.6.RELEASE" level="project" />
     <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.0.6.RELEASE" level="project" />
     <orderEntry type="library" name="Maven: com.zaxxer:HikariCP:2.7.9" level="project" />
-    <orderEntry type="library" name="Maven: com.alibaba:druid-spring-boot-starter:1.1.17" level="project" />
-    <orderEntry type="library" name="Maven: com.alibaba:druid:1.1.17" level="project" />
+    <orderEntry type="library" name="Maven: com.alibaba:druid-spring-boot-starter:1.1.10" level="project" />
+    <orderEntry type="library" name="Maven: com.alibaba:druid:1.1.10" level="project" />
     <orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.25" level="project" />
     <orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-support:2.1.9" level="project" />
     <orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:1.3.1" level="project" />

+ 0 - 7
mpwechatApp/pom.xml

@@ -176,13 +176,6 @@
             <artifactId>okhttp</artifactId>
             <version>4.0.0</version>
         </dependency>
-
-        <!-- 阿里巴巴的连接池 -->
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>druid-spring-boot-starter</artifactId>
-            <version>1.1.17</version>
-        </dependency>
     </dependencies>
 
     <build>

+ 63 - 0
qiyewechatApp/src/main/java/com/liangjiang11/wx/cp/config/WxCpConfigsProperties.java

@@ -0,0 +1,63 @@
+package com.liangjiang11.wx.cp.config;
+
+import com.liangjiang11.wx.cp.utils.JsonUtils;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.List;
+
+/**
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@Getter
+@Setter
+@Data
+@ConfigurationProperties(prefix = "wechat.cp.configs")
+public class WxCpConfigsProperties {
+  /**
+   * 设置微信企业号的配置
+   */
+  private List<WxCpProperties> configs;
+
+    @Data
+    public static class WxCpProperties {
+        /**
+         * 设置微信企业号的corpId
+         */
+        private String corpId;
+
+        private List<com.liangjiang11.wx.cp.config.WxCpProperties.AppConfig> appConfigs;
+
+        @Getter
+        @Setter
+        public static class AppConfig {
+            /**
+             * 设置微信企业应用的AgentId
+             */
+            private Integer agentId;
+
+            /**
+             * 设置微信企业应用的Secret
+             */
+            private String secret;
+
+            /**
+             * 设置微信企业号的token
+             */
+            private String token;
+
+            /**
+             * 设置微信企业号的EncodingAESKey
+             */
+            private String aesKey;
+
+        }
+    }
+
+  @Override
+  public String toString() {
+    return JsonUtils.toJson(this);
+  }
+}

+ 57 - 25
qiyewechatApp/src/main/java/com/liangjiang11/wx/cp/config/WxCpConfiguration.java

@@ -46,10 +46,10 @@ public class WxCpConfiguration {
     private UnsubscribeHandler unsubscribeHandler;
     private SubscribeHandler subscribeHandler;
 
-    private WxCpProperties properties;
+    private WxCpConfigsProperties properties;
 
-    private static Map<Integer, WxCpMessageRouter> routers = Maps.newHashMap();
-    private static Map<Integer, WxCpService> cpServices = Maps.newHashMap();
+    private static Map<String, Map<Integer, WxCpMessageRouter>> routers = Maps.newConcurrentMap();
+    private static Map<String, Map<Integer, WxCpService>> cpServices = Maps.newConcurrentMap();
 
     @Autowired
     private ChannelPortMapper channelPortMapper;
@@ -57,7 +57,7 @@ public class WxCpConfiguration {
     @Autowired
     public WxCpConfiguration(LogHandler logHandler, NullHandler nullHandler, LocationHandler locationHandler,
                              MenuHandler menuHandler, MsgHandler msgHandler, UnsubscribeHandler unsubscribeHandler,
-                             SubscribeHandler subscribeHandler, WxCpProperties properties) {
+                             SubscribeHandler subscribeHandler, WxCpConfigsProperties properties) {
         this.logHandler = logHandler;
         this.nullHandler = nullHandler;
         this.locationHandler = locationHandler;
@@ -69,35 +69,39 @@ public class WxCpConfiguration {
     }
 
 
-    public static Map<Integer, WxCpMessageRouter> getRouters() {
+    public static Map<String, Map<Integer, WxCpMessageRouter>> getRouters() {
         return routers;
     }
 
-    public static WxCpService getCpService(Integer agentId) {
-        return cpServices.get(agentId);
+    public static Map<Integer, WxCpService> getCpService(String corpId) {
+        return cpServices.get(corpId);
+    }
+
+    public static WxCpService getCpService(String corpId,Integer agentId) {
+        return cpServices.get(corpId).get(agentId);
     }
 
     @PostConstruct
     public void initServices() {
 
-        List<ChannelPort> channelPorts = channelPortMapper.queryListByAllConfigInfo();
-        log.info("————————————标识——————————");
-        log.info(channelPorts.toString());
-        for (ChannelPort channelPort : channelPorts) {
-            for (ExtraInfo extraInfo : channelPort.getExtraInfoList()) {
-                val configStorage = new WxCpDefaultConfigImpl();
-                configStorage.setCorpId(channelPort.getEnterpriseWechatId());
-                configStorage.setAgentId(extraInfo.getAgentId());
-                configStorage.setCorpSecret(extraInfo.getFirmSecret());
-                configStorage.setToken(extraInfo.getFirmToken());
-                configStorage.setAesKey(extraInfo.getFirmAesKey());
-                val service = new WxCpServiceImpl();
-                service.setWxCpConfigStorage(configStorage);
-                routers.put(extraInfo.getAgentId(), this.newRouter(service));
-                cpServices.put(extraInfo.getAgentId(), service);
-            }
-        }
-        log.info(cpServices.toString());
+//        List<ChannelPort> channelPorts = channelPortMapper.queryListByAllConfigInfo();
+//        log.info("————————————标识——————————");
+//        log.info(channelPorts.toString());
+//        for (ChannelPort channelPort : channelPorts) {
+//            for (ExtraInfo extraInfo : channelPort.getExtraInfoList()) {
+//                val configStorage = new WxCpDefaultConfigImpl();
+//                configStorage.setCorpId(channelPort.getEnterpriseWechatId());
+//                configStorage.setAgentId(extraInfo.getAgentId());
+//                configStorage.setCorpSecret(extraInfo.getFirmSecret());
+//                configStorage.setToken(extraInfo.getFirmToken());
+//                configStorage.setAesKey(extraInfo.getFirmAesKey());
+//                val service = new WxCpServiceImpl();
+//                service.setWxCpConfigStorage(configStorage);
+//                routers.put(extraInfo.getAgentId(), this.newRouter(service));
+//                cpServices.put(extraInfo.getAgentId(), service);
+//            }
+//        }
+//        log.info(cpServices.toString());
 
 //        cpServices = this.properties.getAppConfigs().stream().map(a -> {
 //            val configStorage = new WxCpDefaultConfigImpl();
@@ -112,6 +116,34 @@ public class WxCpConfiguration {
 //            return service;
 //        }).collect(Collectors.toMap(service -> service.getWxCpConfigStorage().getAgentId(), a -> a));
 
+        cpServices = this.properties.getConfigs().stream().map(a1 -> {
+            Map<Integer, WxCpService> cpServicesA = Maps.newConcurrentMap();
+            Map<Integer, WxCpMessageRouter> routersA = Maps.newConcurrentMap();
+
+            Map<String, Map<Integer, WxCpService>> innerCpServices = Maps.newConcurrentMap();
+
+
+            cpServicesA = a1.getAppConfigs().stream().map(a -> {
+                val configStorage = new WxCpDefaultConfigImpl();
+                configStorage.setCorpId(a1.getCorpId());
+                configStorage.setAgentId(a.getAgentId());
+                configStorage.setCorpSecret(a.getSecret());
+                configStorage.setToken(a.getToken());
+                configStorage.setAesKey(a.getAesKey());
+
+                val service = new WxCpServiceImpl();
+                service.setWxCpConfigStorage(configStorage);
+
+                routersA.put(a.getAgentId(), this.newRouter(service));
+                return service;
+            }).collect(Collectors.toMap(service -> service.getWxCpConfigStorage().getAgentId(), a -> a));
+
+            routers.put(a1.getCorpId(),routersA);
+            innerCpServices.put(a1.getCorpId(),cpServicesA);
+            Map.Entry<String,Map<Integer, WxCpService>> entry = innerCpServices.entrySet().iterator().next();
+            return entry;
+        }).collect(Collectors.toMap(entry -> entry.getKey(),entry->entry.getValue()) );
+
     }
 
     private WxCpMessageRouter newRouter(WxCpService wxCpService) {

+ 14 - 5
qiyewechatApp/src/main/java/com/liangjiang11/wx/cp/controller/HomeController.java

@@ -25,6 +25,7 @@ import me.chanjar.weixin.cp.api.impl.WxCpUserServiceImpl;
 import me.chanjar.weixin.cp.bean.WxCpAgent;
 import me.chanjar.weixin.cp.bean.WxCpUser;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -35,6 +36,7 @@ import java.util.List;
 //import com.mihoyo.hk4e.wechat.service.SourceService;
 
 @RestController
+@RequestMapping("/home/{corpId}/{agentId}")
 public class HomeController {
 //    @Autowired
 //    private MessageService messageService;
@@ -43,17 +45,15 @@ public class HomeController {
 //    private FileService fileService;
 
 //    public static final Integer agentId = 1000004;
-    public static final Integer agentId = 741852;
+
+//    public static final Integer agentId = 741852;
 
     @Autowired
     private ChannelPortMapper channelPortMapper;
 
     @Autowired
     private ITokenService tokenService;
-    final WxCpService wxCpService = WxCpConfiguration.getCpService(agentId);
-    final WxCpUserService wxCpUserService = new WxCpUserServiceImpl(wxCpService);
 
-    final WxCpExternalContactService wxCpExternalContactService = new WxCpExternalContactServiceImpl(wxCpService);
 
     /**
      *
@@ -61,7 +61,16 @@ public class HomeController {
      * @throws WxErrorException
      */
     @RequestMapping("/test")
-    public List<WxCpAgent> index() throws WxErrorException {
+    public List<WxCpAgent> index(
+        @PathVariable String corpId,
+        @PathVariable Integer agentId
+    ) throws WxErrorException {
+
+        final WxCpService wxCpService = WxCpConfiguration.getCpService(corpId).get(agentId);
+        final WxCpUserService wxCpUserService = new WxCpUserServiceImpl(wxCpService);
+
+        final WxCpExternalContactService wxCpExternalContactService = new WxCpExternalContactServiceImpl(wxCpService);
+
         WxCpAgentService agentService = wxCpService.getAgentService();
         List<WxCpAgent> list = agentService.list();
         return list;

+ 7 - 4
qiyewechatApp/src/main/java/com/liangjiang11/wx/cp/controller/TagController.java

@@ -7,25 +7,28 @@ import me.chanjar.weixin.cp.api.WxCpTagService;
 import me.chanjar.weixin.cp.api.impl.WxCpTagServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 
 @Controller
-@RequestMapping("/wx/cp")
+@RequestMapping("/wx/cp/{corpId}/{agentId}")
 public class TagController {
 
 
     public static final Integer agentId = 1000004;
 
 
-    final WxCpService wxCpService = WxCpConfiguration.getCpService(agentId);
-    final WxCpTagService wxCpTagService = new WxCpTagServiceImpl(wxCpService);
 
     /**
      * just test if the service ok
      * @return
      */
     @RequestMapping("/taglist")
-    public String index() throws WxErrorException {
+    public String index(@PathVariable String corpId,
+                        @PathVariable Integer agentId) throws WxErrorException {
+
+        final WxCpService wxCpService = WxCpConfiguration.getCpService(corpId).get(agentId);
+        final WxCpTagService wxCpTagService = new WxCpTagServiceImpl(wxCpService);
 
         return "Just for test, the wechat platform simulator >_<";
     }

+ 10 - 8
qiyewechatApp/src/main/java/com/liangjiang11/wx/cp/controller/WxPortalController.java

@@ -22,12 +22,13 @@ import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
  * @author Binary Wang(https://github.com/binarywang)
  */
 @RestController
-@RequestMapping("/wx/cp/portal/{agentId}")
+@RequestMapping("/wx/cp/{corpId}/{agentId}")
 public class WxPortalController {
   private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
   @GetMapping(produces = "text/plain;charset=utf-8")
-  public String authGet(@PathVariable Integer agentId,
+  public String authGet(@PathVariable String corpId,
+                        @PathVariable Integer agentId,
                         @RequestParam(name = "msg_signature", required = false) String signature,
                         @RequestParam(name = "timestamp", required = false) String timestamp,
                         @RequestParam(name = "nonce", required = false) String nonce,
@@ -39,7 +40,7 @@ public class WxPortalController {
       throw new IllegalArgumentException("请求参数非法,请核实!");
     }
 
-    final WxCpService wxCpService = WxCpConfiguration.getCpService(agentId);
+    final WxCpService wxCpService = WxCpConfiguration.getCpService(corpId).get(agentId);
     if (wxCpService == null) {
       throw new IllegalArgumentException(String.format("未找到对应agentId=[%d]的配置,请核实!", agentId));
     }
@@ -52,7 +53,8 @@ public class WxPortalController {
   }
 
   @PostMapping(produces = "application/xml; charset=UTF-8")
-  public String post(@PathVariable Integer agentId,
+  public String post(@PathVariable String corpId,
+                    @PathVariable Integer agentId,
                      @RequestBody String requestBody,
                      @RequestParam("msg_signature") String signature,
                      @RequestParam("timestamp") String timestamp,
@@ -60,11 +62,11 @@ public class WxPortalController {
     this.logger.info("\n接收微信请求:[signature=[{}], timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
         signature, timestamp, nonce, requestBody);
 
-    final WxCpService wxCpService = WxCpConfiguration.getCpService(agentId);
+    final WxCpService wxCpService = WxCpConfiguration.getCpService(corpId).get(agentId);
     WxCpXmlMessage inMessage = WxCpXmlMessage.fromEncryptedXml(requestBody, wxCpService.getWxCpConfigStorage(),
         timestamp, nonce, signature);
     this.logger.debug("\n消息解密后内容为:\n{} ", JsonUtils.toJson(inMessage));
-    WxCpXmlOutMessage outMessage = this.route(agentId, inMessage);
+    WxCpXmlOutMessage outMessage = this.route(corpId, agentId, inMessage);
     if (outMessage == null) {
       return "";
     }
@@ -74,9 +76,9 @@ public class WxPortalController {
     return out;
   }
 
-  private WxCpXmlOutMessage route(Integer agentId, WxCpXmlMessage message) {
+  private WxCpXmlOutMessage route(String corpId,Integer agentId, WxCpXmlMessage message) {
     try {
-      return WxCpConfiguration.getRouters().get(agentId).route(message);
+      return WxCpConfiguration.getRouters().get(corpId).get(agentId).route(message);
     } catch (Exception e) {
       this.logger.error(e.getMessage(), e);
     }

+ 31 - 12
qiyewechatApp/src/main/java/com/liangjiang11/wx/cp/controller/WxaAddContactController.java

@@ -32,11 +32,10 @@ import java.util.Date;
 import java.util.List;
 
 @RestController
-@RequestMapping("/wx/cp/addcontact")
+@RequestMapping("/wx/cp/addcontact/{corpId}/{agentId}")
 public class WxaAddContactController {
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
-    private static Integer agentId=1000004;
-    final WxCpService wxCpService = WxCpConfiguration.getCpService(agentId);
+//    private static Integer agentId=1000004;
     @Autowired
     private ExternalUserService externalUserService;
     @Autowired
@@ -47,12 +46,16 @@ public class WxaAddContactController {
      * @return
      */
     @GetMapping("/authWx")
-    public String authGet(@RequestParam(name = "msg_signature", required = false) String signature,
+    public String authGet(@PathVariable String corpId,
+                          @PathVariable Integer agentId,
+        @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) {
         this.logger.info("\n1接收到来自微信服务器的认证消息:signature = [{}], timestamp = [{}], nonce = [{}], echostr = [{}]"+signature+timestamp+nonce+echostr);
 
+        final WxCpService wxCpService = WxCpConfiguration.getCpService(corpId,agentId);
+
         if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
             throw new IllegalArgumentException("请求参数非法,请核实!");
         }
@@ -77,13 +80,16 @@ public class WxaAddContactController {
      * @return
      */
     @PostMapping(value = "/authWx")
-    public String authPost(@RequestBody String requestBody,
+    public String authPost(@PathVariable String corpId,
+                           @PathVariable Integer agentId,
+        @RequestBody String requestBody,
                            @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) {
         this.logger.info("\n1接收到来自微信服务器的认证消息:"+signature+"--"+timestamp+"--"+nonce+"--"+echostr);
 
+        final WxCpService wxCpService = WxCpConfiguration.getCpService(corpId,agentId);
 
         //获取Token
         try {
@@ -91,7 +97,7 @@ public class WxaAddContactController {
             WxCpXmlMessage inMessage = WxCpXmlMessage.fromEncryptedXml(requestBody, wxCpService.getWxCpConfigStorage(),
                 timestamp, nonce, signature);
             this.logger.info("\n消息解密后内容为:\n{} "+JsonUtils.toJson(inMessage));
-            WxCpXmlOutMessage outMessage = this.route(agentId, inMessage);
+            WxCpXmlOutMessage outMessage = this.route(corpId,agentId, inMessage);
             if (outMessage == null) {
                 return "";
             }
@@ -213,9 +219,14 @@ public class WxaAddContactController {
      * @param res
      */
     @GetMapping(value = "/authWxInfo")
-    public void authWxInfoPost(@RequestParam(name = "code", required = false) String code,
+    public void authWxInfoPost(@PathVariable String corpId,
+                               @PathVariable Integer agentId,
+        @RequestParam(name = "code", required = false) String code,
                          @RequestParam(name = "state", required = false) String state, HttpServletResponse res) {
         this.logger.info("接收到来自微信服务器的用户授权消息:"+code+"--"+state);
+
+        final WxCpService wxCpService = WxCpConfiguration.getCpService(corpId,agentId);
+
         try {
             String url="http://coop.360lj.com:7000/client/index.html";
             //获取用户信息
@@ -233,12 +244,16 @@ public class WxaAddContactController {
 
 
     @GetMapping("/authUsers")
-    public String authUsersGet(@RequestParam(name = "msg_signature", required = false) String signature,
+    public String authUsersGet(@PathVariable String corpId,
+                               @PathVariable Integer agentId,
+        @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) {
         this.logger.info("\n1接收到来自微信服务器的认证消息:signature = [{}], timestamp = [{}], nonce = [{}], echostr = [{}]"+signature+timestamp+nonce+echostr+agentId);
 
+        final WxCpService wxCpService = WxCpConfiguration.getCpService(corpId,agentId);
+
         if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
             throw new IllegalArgumentException("请求参数非法,请核实!");
         }
@@ -254,20 +269,24 @@ public class WxaAddContactController {
     }
 
     @PostMapping(value = "/authUsers")
-    public String authUsersPost(@RequestBody String requestBody,
+    public String authUsersPost(@PathVariable String corpId,
+                                @PathVariable Integer agentId,
+        @RequestBody String requestBody,
                            @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) {
         this.logger.info("\n1接收到来自微信服务器的企业用户变更信息:"+signature+"--"+timestamp+"--"+nonce+"--"+echostr);
 
+        final WxCpService wxCpService = WxCpConfiguration.getCpService(corpId,agentId);
+
         //获取Token
         try {
             Date date = new Date();
             WxCpXmlMessage inMessage = WxCpXmlMessage.fromEncryptedXml(requestBody, wxCpService.getWxCpConfigStorage(),
                 timestamp, nonce, signature);
             this.logger.info("\n消息解密后内容为:\n{} "+JsonUtils.toJson(inMessage));
-            WxCpXmlOutMessage outMessage = this.route(agentId, inMessage);
+            WxCpXmlOutMessage outMessage = this.route(corpId,agentId, inMessage);
             if (outMessage == null) {
                 return "";
             }
@@ -338,9 +357,9 @@ public class WxaAddContactController {
     }
 
 
-    private WxCpXmlOutMessage route(Integer agentId, WxCpXmlMessage message) {
+    private WxCpXmlOutMessage route(String corpId,Integer agentId, WxCpXmlMessage message) {
         try {
-            return WxCpConfiguration.getRouters().get(agentId).route(message);
+            return WxCpConfiguration.getRouters().get(corpId).get(agentId).route(message);
         } catch (Exception e) {
             this.logger.error(e.getMessage(), e);
         }

+ 7 - 1
qiyewechatApp/src/main/resources/application-dev.yml

@@ -142,7 +142,13 @@ wechat:
           secret: 3whtB0Z8Px1iQ_9SDs4P65I-5apuuA1lJg4Wv90foIY
           token: Fh9jrzyLqL1
           aesKey: 6d7562bCSWGQy5V6fI2RwDWr9jIywr4lzjVPq2Ud2n7
-
+    configs:
+         - corpId: ww08ba7529fb06a064
+           appConfigs:
+              - agentId: 1000004
+                secret: 3whtB0Z8Px1iQ_9SDs4P65I-5apuuA1lJg4Wv90foIY
+                token: Fh9jrzyLqL1
+                aesKey: 6d7562bCSWGQy5V6fI2RwDWr9jIywr4lzjVPq2Ud2n7
 
 
 mybatis-plus: