精华内容
下载资源
问答
  • 企业微信开发

    2018-10-02 17:11:49
    企业微信开发Demo
  • 充分理解企业微信第三方应用开发流程,带你快速避坑躲雷节约时间精力,从0到1全流程完成企业微信第...另有《企业微信开发概述篇》免费视频系统,对企业微信开发不了解的可前往https://edu.csdn.net/course/detail/30386
  • 企业微信开发Demo

    2018-04-18 15:54:24
    企业微信 开发 实例 公众平台开发 Demo
  • 总结了开发企业微信过程中遇到的各种问题及解决办法,有效的提升开发能力
  • 腾讯企微微信服务商考试,开发实操题答案,不多说,实在货,面试能不能过就看这个文文档
  • Java企业微信开发源码框架,获取AccessToken,发送消息. 当前应用于公司的企业微信监控报警系统. 微信企业号管理系统源码框架 使用springboot框架 基础签名验证,附加强加密算法jar 获取accessToken 发送消息 扩展对接...
  • 微信公众平台之企业微信 开发教程.zip
  • 企业微信开发工具包

    2018-06-08 17:25:39
    获取accessToken后最好保存起来, 方便后边取, 不要每次都调用接口获取, 接口有频率限制 PS:之前忘记传了
  • 企业微信开发概述篇

    2021-06-22 06:30:07
    1,了解企业微信开发是怎么回事,企业微信开发是开发什么,怎么接入企业微信,接入企业微信能获取什么能力? 2,了解企业微信api及应用类别,自建内部应用与第三方应用有什么区别,适用场景是什么,我该怎么选应用...
  • 该项目是基于SpringBoot2.1.3版本来实现的,算是比较新的。该项目中用到了SpringBoot2.0之后的拦截器,yml配置jsp,整合Mybatis-Plus,以及使用了其一对多,多对多的查询特性,还集成了Ehcache缓存技术等
  • 主要介绍了vue 开发企业微信整合,结合具体案例形式分析了vue.js使用企业微信JSSDK实现手机端程序可以和企业微信进行整合功能的相关操作技巧,需要的朋友可以参考下
  • 1) 登录企业微信 2)在应用管理下方的自建应用中,找到你要推送消息的应用信息 3) 如下图所示 企业ID(CORPID) 1) 点击“我的企业” 2) 在企业信息中,最下方有个企业ID,如下图所示 待推送的企业微信...

    准备事项

    1. 企业应用ID(AGENTID)和密钥(SECRET)
      1) 登录企业微信
      2)在应用管理下方的自建应用中,找到你要推送消息的应用信息,如下图所示
      在这里插入图片描述

    2. 企业ID(CORPID)
      1) 点击“我的企业”
      2) 在企业信息中,最下方有个企业ID,如下图所示
      在这里插入图片描述

    3. 待推送的企业微信用户ID(wechatId)
      1)通讯录中,找到成员信息,点击查看详情
      2)此处的账号信息,就是企业微信ID,如下图所示
      在这里插入图片描述

    测试步骤

    1. 进入企业微信接口调试工具网址

    2. 点击建立连接,输入corpid(企业ID)和corpsecret(此处是应用的密钥,每个应用密钥不同,一定要注意

    3. 点击调用接口,获取相应的access_token信息,如下图所示(access_token信息无需复制,只要依然停留在接口调试页面,进入其他功能时,access_token信息会自动带入
      在这里插入图片描述

    4. 点击发送消息-发送应用消息
      在这里插入图片描述
      注意事项:
      1、tourser:用上文中查到的用户企业微信ID,多个ID之间用“|”分割
      2、msgtype:应用消息中支持多种消息类型,此处记得要修改,消息类型可以在 企业微信API中查询
      3、agentid:就是你想要推送消息的应用ID

    5. 修改body中的数据后,点击调用接口按钮,就可以在企业微信中,查看相关应用的推送消息
      在这里插入图片描述

    6. 在企业微信APP中查看推送的消息
      在这里插入图片描述

    注意事项:如果调试的时候不成功,可以在企业微信错误码查询工具中查看错误码的含义

    展开全文
  • 使用工具类 ... ...-- 企业微信工具集 https://mvnrepository.com/artifact/com.github.binarywang/wx-java --> <dependency> <groupId>com.github.binarywang</groupId>...

     

     

    使用工具类

    https://gitee.com/binary/weixin-java-tools

     

    1 pom引用

            <!-- 企业微信工具集 https://mvnrepository.com/artifact/com.github.binarywang/wx-java -->
            <dependency>
                <groupId>com.github.binarywang</groupId>
                <artifactId>weixin-java-cp</artifactId>
                <version>3.9.0</version>
            </dependency>

     

    2 增加配置 application.yml

    普通企业微信不需要配置baseApiUrl / oauth2redirectUri

    # 微信相关
    wechat:
      # 私有部署企业微信
      privatecp:
        corpId: wwxxxxxxxxxx
        baseApiUrl: http://127.0.0.1:161
        oauth2redirectUri: http://127.0.0.1:161
        # 应用配置
        appConfigs:
          - agentId: 1000001
            secret: xxxxxxxxxxxxxxxxxxxxx
          - agentId: 1000002
            secret: xxxxxxxxxxxxxxxxxxxxx

     

    3 增加配置信息类

    package com.xxx.auth.config;
    
    import java.util.List;
    
    import com.xxx.auth.urils.JsonUtils;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    import lombok.Getter;
    import lombok.Setter;
    
    /**
     * @author GuanWeiMail@163.com
     */
    @Getter
    @Setter
    @ConfigurationProperties(prefix = "wechat.privatecp")
    public class WxCpPrivateProperties {
        /**
         * 设置微信企业号的corpId
         */
        private String corpId;
    
        /**
         * 基础api域名
         */
        private String baseApiUrl;
    
        /**
         * oauth2 网页授权请求域名
         */
        private String oauth2redirectUri;
    
        /**
         * 应用配置集合
         */
        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;
    
        }
    
        @Override
        public String toString() {
            return JsonUtils.toJson(this);
        }
    }

     

    工具类

    package com.tpln.auth.urils;
    
    import com.fasterxml.jackson.annotation.JsonInclude.Include;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.SerializationFeature;
    
    /**
     *
     *  Json工具类
     *  @author
     */
    public class JsonUtils {
        private static final ObjectMapper JSON = new ObjectMapper();
    
        static {
            JSON.setSerializationInclusion(Include.NON_NULL);
            JSON.configure(SerializationFeature.INDENT_OUTPUT, Boolean.TRUE);
        }
    
        public static String toJson(Object obj) {
            try {
                return JSON.writeValueAsString(obj);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
    
            return null;
        }
    }

     

     

    4 增加配置类

    普通企业微信不需要配置baseApiUrl / oauth2redirectUri

    package com.xxx.auth.config;
    
    import java.util.Map;
    import java.util.stream.Collectors;
    import javax.annotation.PostConstruct;
    
    import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Configuration;
    
    import com.google.common.collect.Maps;
    import lombok.val;
    import me.chanjar.weixin.cp.api.WxCpService;
    import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
    import me.chanjar.weixin.cp.message.WxCpMessageRouter;
    
    /**
     * @Title: 私有部署企业微信配置类
     * @Description: 集成企业微信认证
     * @Version: v1.0
     * @Author: Mr.Guan
     * @Mail GuanWeiMail@163.com
     * @DateTime: 2020-09-08 20:01:04
     * @Package com.xxx.auth.config
     */
    @Configuration
    @EnableConfigurationProperties(WxCpPrivateProperties.class)
    public class WxCpPrivateConfiguration {
    
        /**
         * 配置信息
         */
        private WxCpPrivateProperties properties;
    
        private static Map<Integer, WxCpMessageRouter> routers = Maps.newHashMap();
        private static Map<Integer, WxCpService> cpServices = Maps.newHashMap();
    
        @Autowired
        public WxCpPrivateConfiguration(WxCpPrivateProperties properties) {
            this.properties = properties;
        }
    
    
        public static Map<Integer, WxCpMessageRouter> getRouters() {
            return routers;
        }
    
        public static WxCpService getCpService(Integer agentId) {
            return cpServices.get(agentId);
        }
    
        /**
         * 初始化Services
         * 初始化多个企业应用
         */
        @PostConstruct
        public void initServices() {
            cpServices = this.properties.getAppConfigs().stream().map(appConfig -> {
                val configStorage = new WxCpDefaultConfigImpl();
    
                //普通企业微信不需要配置baseApiUrl / oauth2redirectUri
                configStorage.setBaseApiUrl(this.properties.getBaseApiUrl());
                configStorage.setOauth2redirectUri(this.properties.getOauth2redirectUri());
    
    
                configStorage.setCorpId(this.properties.getCorpId());
                configStorage.setAgentId(appConfig.getAgentId());
                configStorage.setCorpSecret(appConfig.getSecret());
                configStorage.setToken(appConfig.getToken());
                configStorage.setAesKey(appConfig.getAesKey());
                val service = new WxCpServiceImpl();
                service.setWxCpConfigStorage(configStorage);
                routers.put(appConfig.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);
    
            return newRouter;
        }
    }

     

    5 网页授权地址

    http://127.0.0.1:161/connect/oauth2/authorize?appid=wwxxxxxxxxxx&redirect_uri=http://服务器ip:8889/auth/callback/WECHAT_ENTERPRISE&response_type=code&scope=SCOPE&agentid=1000001&state=STATE#wechat_redirect

     

    参考

    package com.xxx.auth.controller;
    
    import cn.hutool.core.util.StrUtil;
    import cn.hutool.json.JSONUtil;
    import com.xxx.auth.config.WxCpPrivateConfiguration;
    import com.xxx.auth.emnu.SourceInfoEnum;
    import me.chanjar.weixin.cp.api.WxCpService;
    import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo;
    import me.chanjar.weixin.cp.bean.WxCpUser;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.Map;
    
    /**
     * @Title: 认证Controller
     * @Description: 描述
     * @Version: v1.0
     * @Author: Mr.Guan
     * @Mail GuanWeiMail@163.com
     * @DateTime: 2020-08-24 20:01:04
     */
    @RestController
    @RequestMapping("auth")
    public class AuthController {
    
        public static void main(String[] args) {
    
    
            System.out.println(SourceInfoEnum.valueOf("WECHAT_ENTERPRISE"));
    
        }
    
        /**
         * auth平台中配置的授权回调地址
         * 以本项目为例,在创建"企业微信"授权应用时的回调地址应为:http://127.0.0.1:8443/auth/callback/wechat_enterprise?callback=
         * 企业微信免登陆
         * 获取企业用户信息 关联子系统用户 实现免登
         * @param request
         * @param source    请求来源:WECHAT_ENTERPRISE:企业微信
         * @return
         * @throws Exception
         */
        @RequestMapping("callback/{source}")
        public Object login(HttpServletRequest request, @PathVariable("source") String source) throws Exception{
    
            //获取请求参数
            Map<String, String[]> parameterMap = request.getParameterMap();
            System.out.println(JSONUtil.parse(parameterMap).toStringPretty());
    
            if(StrUtil.isBlank(source)){
                return "error";
            }
    
    
            switch (SourceInfoEnum.valueOf(source)){
                // 企业微信
                case WECHAT_ENTERPRISE:
    
                    String code = parameterMap.get("code")[0];
    
    
                    //获取微信服务
                    WxCpService wxCpService = WxCpPrivateConfiguration.getCpService(1000001);
    
                    //获取用户ID
                    WxCpOauth2UserInfo userInfo = wxCpService.getOauth2Service().getUserInfo(code);
                    System.out.println(JSONUtil.parse(userInfo).toStringPretty());
    
                    //获取通讯录
    //                List<WxCpDepart> list = wxCpService.getDepartmentService().list(1L);
    //                for (WxCpDepart wxCpDepart : list) {
    //                    List<WxCpUser> wxCpUsers = wxCpService.getUserService().listByDepartment(wxCpDepart.getId(), false, 0);
    //                    System.out.println(JSONUtil.parse(wxCpDepart).toStringPretty());
    //                    System.out.println(JSONUtil.parse(wxCpUsers).toStringPretty());
    //                }
    
    
                    //获取用户明细信息
                    WxCpUser byId = wxCpService.getUserService().getById(userInfo.getUserId());
    
                    System.out.println(byId);
    
    
                    //判断子系统是否存在该用户, 存在则直接免登, 生成 token 存入session / redis
                    //不存在则创建用户
    
                    break;
                default:
                    break;
            }
    
    
    
            return "ok";
        }
    
    }
    

     

     

     

     

     

     

     

     

     

    展开全文
  • 企业微信项目搭建起来的前提是key文件,但是jdk1.8的加解密字符串长度貌似不够,需要替换里面的jar包。
  • 手把手教你springboot企业微信开发(二)1、企业微信开发第一步2、weixin-java-cp-demo-master1)、引入thymeleaf改造项目2)增加Configuration3)回到企业号4)穿透内外网5)完善 从这一篇开始,开始从实际项目探索...


    从这一篇开始,开始从实际项目探索企业微信开发。

    1、企业微信开发第一步

    看一下企业微信的开发者文档: 企业微信开发者文档.

    在开发文档的首页中,我们看到:企业&定制化服务商开发流程

    1. 获取企业号CorpID&Secret: 企业管理员建立管理组,获取CorpID&Secret
    2. 开发对接相关接口: 开发测试应用,对接企业号接口,接口文档qydev.weixin.qq.com

    企业号的CorpID和Secret,在上一篇已经讲解了,这里不赘述。对接接口的内容,在后面也会使用,暂时按下不表。

    看【主动调用】,文档中有个醒目的获取AccessToken而且备注是:你应该审慎配置管理组的权限,够用即好,权限过大会增加误操作可能性及信息安全隐患。对于我们开发者而言:做好缓存、注意有时间限制7200s。下面还说频率的问题等等,这个也做到心中有数吧。

    我们先把关注点集中在获取access_token上。在项目中,使用get请求获取access_token,请求地址为:https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=id&corpsecret=secrect

    【回调模式】在开发中用的也很多,使用的时候按照文档来吧。

    我在一个项目中,写了一个微信开发的WeixinUtil,java写的未必那么完美。它的作用就是基于主动调用的,来看一下,这里一个推送的实现:

    /**
    	 * 企业号推送文章
    	 */
    sentPushMsg(List<String> userIds , PushMsgEntity pushMsg) {
    		String appid = sysConfigService.getWeixinAppid();
        	String secret = sysConfigService.getWeixinSecret();
    		String agentId = sysConfigService.getParamValue("agentId");
    		
    		String qytoken = apiRedis.getWeAccessToken(appid); //从缓存中获取token
    		if(qytoken == null) {
    			TokenResponse tokenResponse = WeixinUtil.token(appid,secret);
    			try {
    				qytoken = tokenResponse.getAccessToken();
    				apiRedis.setWeAccessToken(appid , qytoken);
    			}catch(Exception e) {
    				return R.error(ErrorCode.WEIXIN_API_GET_TOKEN_ERROR, "微信获取AccessToken失败,请重新获取!");
    			}
    		}
    		MessageCustomArticle article = new MessageCustomArticle();
    		
    		article.setTitle(pushMsg.getTitle());
    		article.setDescription(pushMsg.getMessage());
    		article.setUrl(pushMsg.getUrl());
    		article.setPicurl(pushMsg.getPicurl());
    		
    		MessageCustomSendRequest  messageCustomSendRequest  = WeixinUtil.getMessageCustomSendRequest(userIds , article);
    		if(!StringUtil.isBlank(agentId)) {
    			messageCustomSendRequest.setAgentid(new Integer(agentId));
    		}
    		
    		Response res = WeixinUtil.messageCustomSend(qytoken , messageCustomSendRequest);
    		if(res == null) {
    			//....略去了业务代码
    			return R.error( ErrorCode.SENT_TEMPLATE_MSG_ERROR, "消息发送失败");
    		}else {
    			//....略去了业务代码
    			return R.ok(res.getErrMsg()).put("code", res.getErrCode());
    		}
    		
    	}
    

    大家在自己的项目中,也一定会有自己封装的方式。

    接着上一篇,这里用的是什么呢?我在上一篇里说到,引入weixin-java-cp的Jar包了,这个jar包有非常强悍的作用。

    2、weixin-java-cp-demo-master

    1)、引入thymeleaf改造项目

    在pom.xml中引入spring-boot-starter-thymeleaf

    		<dependency>
    		    <groupId>org.springframework.boot</groupId>
    		    <artifactId>spring-boot-starter-thymeleaf</artifactId>
    		</dependency>
    

    引入之后,application.yml中配置解析html:

    spring:
      thymeleaf:
        prefix: classpath:/templates/
        suffix: .html
        mode: HTML5
        encoding: UTF-8
        servlet:
            content-type: text/html
        cache: false
    

    稍微解释一下,前缀prefix是地址,工程的相对路径,这边是404错误的根据地了吧,哈哈哈,得注意编译和请求得路径啊;后缀suffix需要spring解析的模板后缀,这里是html。mode、encoding、wevlet、cache就不说了哦。

    在thymeleaf目录下,新建一个文件夹,thymeleaf,在文件夹中,新建一个first.html

    <!DOCTYPE HTML>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>first</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    </head>
    <body>
    <p th:text="'Url:' + ${Url}"/>
    <p th:text="'Error:' + ${Error}"/>
    <p th:text="'Message:' + ${Message}"/>
    <p th:text="'Exception:' + ${Exception}"/>
    <p th:text="'Path:' + ${Path}"/>
    <p th:text="'Status:' + ${Status}"/>
    <p th:text="'Timestamp:' + ${Timestamp}"/>
    </body>
    </html>
    

    看一下文件目录结构:

    在这里插入图片描述
    新建一个ThemleafController.java,内容是:

    package com.github.binarywang.demo.wx.cp.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    @RequestMapping("/thymeleaf")
    public class ThemleafController {
    
    	  @GetMapping(value = "/first")
    	  public String first(Model model) {
    		model.addAttribute("Url", "thymeleaf/first");
    		model.addAttribute("Error", "0");
    		model.addAttribute("Path", "");
    		model.addAttribute("Message", "");
    		model.addAttribute("Exception", "");
    		model.addAttribute("Status", "");
    		model.addAttribute("Timestamp", System.currentTimeMillis());
    	    return "/thymeleaf/first";
    	  }
    
    }
    

    改一手application.yml

    server:
      port: 8080
    

    debug模式启动WxCpDemoApplication.java
    在浏览器中输入http://localhost:8080/thymeleaf/first

    在这里插入图片描述
    出来它就可以了。

    2)增加Configuration

    springboot在很多配置项简洁得让人摸不着头脑,这里是基于springboot不得不说的就是这个,先上代码,然后解释:

    package com.github.binarywang.demo.wx.cp.config;
    
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    public class WebMvcConfig implements WebMvcConfigurer{
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
        }
    }
    

    这个Java文件的意思是以静态资源的形式访问/static/文件夹下的所有文件。
    /static/**使用了**作为通配符。但是,并没有static文件夹,对吗?建立一个static文件夹,看一下项目结构:
    在这里插入图片描述

    在里面放个txt文件文件名叫who_love_who.txt,文件里面写上自己喜欢的人的名字,文件名的话用我们的代码来试试看TA对你是否有意,哈哈哈。我的文件里面写的是:天赐我爱-love-天赐我爱。写好了测试文件,现在的项目结构是:
    在这里插入图片描述

    重新debug
    WxCpDemoApplication.java
    启动好了之后,在浏览器输入:
    http://localhost:8080/who_love_who.txt
    我这边的是:
    在这里插入图片描述
    看到是乱码,我就放心了,她是爱谁谁,与我这单身技术狗无关!差不多了哦!配置起作用了。

    3)回到企业号

    回到企业号。找到上篇手把手教你springboot企业微信开发(一)中的应用配置页:
    在这里插入图片描述
    拉到下面:
    【开发者接口】–》点开【网页授权及JS-SDK】
    在这里插入图片描述
    点,【 下载文件】的链接,下载了一个txt文件吧?好!这个文件,放到我之前说的那个static文件夹!现在的static文件夹:
    在这里插入图片描述
    是否疑问,我在大费周章在搞thymeleaf、txt静态资源是为了什么呢?下面细细说这个。

    4)穿透内外网

    访问链接: https://natapp.cn/login.
    注册~~~购买,不不不申请免费隧道:
    在这里插入图片描述
    天底下最好的东西,一定的免费的,阳光是免费的、空气是免费的,爱也是免费的。点开刚刚申请的隧道:
    在这里插入图片描述
    端口用个8080;authtoken复制备用。下载客户端:
    在这里插入图片描述
    自己选择吧。
    下载完了,自己创建一个文件夹,就叫natapp得了,在里面放个文件,文件名config.ini在里面的配置:

    #将本文件放置于natapp同级目录 程序将读取 [default] 段
    #在命令行参数模式如 natapp -authtoken=xxx 等相同参数将会覆盖掉此配置
    #命令行参数 -config= 可以指定任意config.ini文件
    [default]
    authtoken=myauthtoken                     #对应一条隧道的authtoken
    clienttoken=                    #对应客户端的clienttoken,将会忽略authtoken,若无请留空,
    log=none                        #log 日志文件,可指定本地文件, none=不做记录,stdout=直接屏幕输出 ,默认为none
    loglevel=ERROR                  #日志等级 DEBUG, INFO, WARNING, ERROR 默认为 DEBUG
    http_proxy=                     #代理设置 如 http://10.123.10.10:3128 非代理上网用户请务必留空
    

    刚才我说复制的authtoken,粘贴在这里。打开natapp.exe有木有什么?
    在这里插入图片描述
    有类似这个吗?如果是那行的意思是:现在这个域名,已经穿透到了你本地的8080端口。
    好,把我画线的部分复制到浏览器:
    是不是有这样的画面:
    在这里插入图片描述
    有的话,说明穿透成功了。把http://域名/thymeleaf/first复制下来,编码:
    链接: url编码.把编码后的这段复制备用。把域名(不带http://的)复制下来备用。

    5)完善

    在pom.xml中引入jar包:

    		<dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.45</version>
            </dependency>
    

    引入这个fastjson是为了解析返回的字符串。

    自动注入:

    @Autowired
    WxCpProperties wxCpProperties;
    

    修改first方法:

     @GetMapping(value = "/first")
    	  public String first(ServletRequest request, ServletResponse response, Model model) {
    		  
    		  HttpServletRequest servletRequest = ((HttpServletRequest) request);
    		  String userAgent = servletRequest.getHeader("user-agent");
    		  
    		  final WxCpService wxCpService = WxCpConfiguration
    					.getCpService(wxCpProperties.getAppConfigs().get(0).getAgentId());
    
    			
    			String queryString = servletRequest.getQueryString();
    			String backString = "";
    			try {
    				backString = HttpRequest.sendGet("https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token="
    						+ wxCpService.getAccessToken() + "&" + queryString, null);
    			} catch (WxErrorException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    			JSONObject json_test = JSONObject.parseObject(backString);  
    		  
    		model.addAttribute("Url", "thymeleaf/first");
    		model.addAttribute("Error", "0");
    		model.addAttribute("Path", "");
    		model.addAttribute("Message", "");
    		model.addAttribute("Exception", "");
    		model.addAttribute("Status", "");
    		model.addAttribute("Timestamp", System.currentTimeMillis());
    	    return "/thymeleaf/first";
    	  }
    

    这里用的HttpRequest.java是我自己写的:

    package com.github.binarywang.demo.wx.cp.utils;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.URL;
    import java.net.URLConnection;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLSession;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class HttpRequest {
    	
    	public static Logger logger = LoggerFactory.getLogger(HttpRequest.class);
    	
    	/**
    	 * 向指定URL发送GET方法的请求
    	 * 
    	 * @param url
    	 *            发送请求的URL
    	 * @param param
    	 *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
    	 * @return URL 所代表远程资源的响应结果
    	 */
    	public static String sendGet(String url, Map params) {
    		return sendGet(url,"", params);
    	}
    	/**
    	 * 向指定URL发送GET方法的请求
    	 * 
    	 * @param url
    	 *            发送请求的URL
    	 * @param param
    	 *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
    	 * @return URL 所代表远程资源的响应结果
    	 */
    	public static String sendGet(String url,String interfaceName, Map params) {
    		String result = "";
    		BufferedReader in = null;
    		StringBuffer strBufParamsSet = new StringBuffer();
    		
    		if(params!=null) {
    			Set<String> paramsSet = params.keySet();
    			
    			for(String parma:paramsSet) {
    				if(strBufParamsSet.length()>0) {
    					strBufParamsSet.append("&").append(parma).append("=").append(params.get(parma));
    				}else {
    					strBufParamsSet.append("?").append(parma).append("=").append(params.get(parma));
    				}
    			}
    		}else {
    			strBufParamsSet.append("");
    		}
    		
    		
    		try {
    			String urlNameString = "";
    			if(interfaceName==null || "".contains(interfaceName.trim())) {
    				urlNameString = url + strBufParamsSet.toString();
    			}else {
    				urlNameString = url +"/"+ interfaceName + strBufParamsSet.toString();
    			}
    			urlNameString = urlNameString.replaceAll("\r\n", "");
    			trustAllHttpsCertificates();
    			logger.info("请求路径:" + urlNameString);
    			URL realUrl = new URL(urlNameString);
    			// 打开和URL之间的连接
    			URLConnection connection = realUrl.openConnection();
    			// 设置通用的请求属性
    			connection.setRequestProperty("accept", "*/*");
    			connection.setRequestProperty("connection", "Keep-Alive");
    			connection.setRequestProperty("Accept-Charset", "UTF-8");
    			connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
    			// 建立实际的连接
    			connection.connect();
    			// 获取所有响应头字段
    			Map<String, List<String>> map = connection.getHeaderFields();
    //			// 遍历所有的响应头字段
    //			for (String key : map.keySet()) {
    //				System.out.println(key + "--->" + map.get(key));
    //			}
    			// 定义 BufferedReader输入流来读取URL的响应
    			in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    			String line;
    			while ((line = in.readLine()) != null) {
    				result += line;
    			}
    		} catch (Exception e) {
    			logger.debug("发送 get请求出现异常!获取文件流失败:" + e);
    			
    		}
    		// 使用finally块来关闭输入流
    		finally {
    			try {
    				if (in != null) {
    					in.close();
    				}
    			} catch (Exception e2) {
    				logger.debug("发送 get请求出现异常!获取文件流失败:" + e2);
    			}
    		}
    		return result;
    	}
    
    	
    
    	private static void trustAllHttpsCertificates() throws Exception {  
            javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];  
            javax.net.ssl.TrustManager tm = new miTM();  
            trustAllCerts[0] = tm;  
            javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext  
                    .getInstance("SSL");  
            sc.init(null, trustAllCerts, null);  
            javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc  
    				                .getSocketFactory());
    
    		HostnameVerifier hv = new HostnameVerifier() {
    			public boolean verify(String urlHostName, SSLSession session) {
    				System.out.println("Warning: URL Host: " + urlHostName + " vs. "
    								   + session.getPeerHost());
    				return true;
    			}
        	};
    		HttpsURLConnection.setDefaultHostnameVerifier(hv);
        }  
    			  
        static class miTM implements javax.net.ssl.TrustManager,
    			            javax.net.ssl.X509TrustManager {  
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {  
                return null;  
            }  
      
            public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) {
                return true;  
            }  
      
            public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) {
                return true;  
            }  
      
            public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
                    throws java.security.cert.CertificateException {  
                return;  
            }  
      
            public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
                    throws java.security.cert.CertificateException {  
                return;  
            }  
        }  
    }
    

    到了这一步,把
    再回企业微信应用配置的页面,复制这个:

    https://open.weixin.qq.com/connect/oauth2/authorize?appid=appIdf&redirect_uri=编码后的域名&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
    复制到:【工作台应用主页】里面去。
    复制域名到【网页授权及JS-SDK】:
    在这里插入图片描述
    勾选【已上传域名归属校验文件】,【确定】!
    点:【企业微信授权登录】已启用–》Web网页–》
    在这里插入图片描述
    编辑填入域名
    好了之后,debug重启:WxCpDemoApplication.java并且在这行打断点:
    在这里插入图片描述

    在企业微信中打开:
    在这里插入图片描述
    点进去自己的应用,如果进断点,看backString,是不是与我类似:
    在这里插入图片描述
    如果看到返回值与我类似的,恭喜,已经完成了!!!如果有疑问或者需要讨论,或者报错的不好解决的话,给我留言即可。
    附上我这边最终的画面:
    在这里插入图片描述
    另外,稍微看一下natapp的情况,那里有请求的情况:
    在这里插入图片描述
    好了,这一篇也结束了。

    展开全文
  • 用最简单的Servlet实现企业微信通用开发配置,有需要的小伙伴可以看看!
  • 企业微信开发升级版

    2019-01-07 11:22:19
    此资源是上次的升级版,囊括了helloworld的发送,图片的发送,图片上传到微信服务器,发送新闻消息等
  • 企业微信开发总结-获取通讯录

    千次阅读 2020-08-17 11:02:08
    企业微信开发总结-获取通讯录 最近遇到个项目需求,需要能够获取到用户企业的通讯录,同步到我们系统中,这样就不用重复输入一批企业人员了。一开始想的很简单,实际研究下来发现企业微信比个人微信对接起来复杂多了...

    企业微信开发总结-获取通讯录
    最近遇到个项目需求,需要能够获取到用户企业的通讯录,同步到我们系统中,这样就不用重复输入一批企业人员了。一开始想的很简单,实际研究下来发现企业微信比个人微信对接起来复杂多了, 也许是微信平台考虑到企业数据的安全性,特意设计的很复杂吧。话不多说,直奔主题。
    PS: 本项目代码是基于java语言springboot框架开发的,使用工具是IDEA, jdk1.8。如果看官您采用的是其他语言,那只能参考下本文的思路了。
    一、 前期企业微信准备

    1. 先注册个企业微信,这个按照官方指引来就行了。进入服务商平台-服务商信息-基本信息,查看corpId, 保存备用。 同时需要设置IP白名单。不然后面的API接口调用会失败哦。
      在这里插入图片描述

    2. 进入应用管理,选择应用类型。 我这里做的是H5网页,所以选择网页应用。创建一个。注意应用类型,有普通应用和通讯录应用两种。 这里有个坑,普通应用的说明里也可以访问通讯录,但是他没有说无法获取到人员手机号码和姓名,只有人员的id,部门什么的。 这个和我的需求显然是不匹配的。 自己也是踏过这个坑,后面发现调用获取人员详情接口时,没有手机号码返回,一查看接口说明才发现这个问题。 所以新手就不用再犯同样的错误了,节约时间。创建完查看应用详情。
      在这里插入图片描述

    SuiteID和Secret需要记录下来,这是第三方应用获取授权企业信息时需要的参数。
    可信域名要填写我们应用的域名,如果没有需要去申请。建议配置https。还有安装完成回调域名,业务设置URL都写好。
    接下来还有回调配置
    在这里插入图片描述

    数据回调URL是用于企业微信的通信消息的,比如谁发信息给谁了,会推送到这个地址。我们这里虽然不需要,但还是写个接口响应一下吧,不然会无法进行安装测试。
    指令回调URL是非业务的交互指令通知,比如企业对我们的应用完成授权的时候,而这个正是我们需要的。我们需要在这里取到企业的临时授权码,用来换取永久授权码,进而取到企业的AccessToken, 获取通讯录数据。其实拿到永久授权码的数据返回中也有AccessToken,可以直接用。 存储永久授权码是为了以后再调取企业接口,直接使用永久授权去换取AccessToken。
    Token自己填写或者自动生成,EncodingAESKey也是。这两个是用于验证和微信平台的数据交互的安全性。
    接口得先写好,调通后这里的回调填写保存才能成功。所以下面开始撸代码。
    二、 业务代码
    application.properties中配置相关参数

    suitId=这里是应用的suiteID
    suitSecret=这里是应用的Secret
    #平台作为服务商的参数
    corpId=服务商corpId
    token=应用回调token
    encodingAesKey=应用回调encodingAESKey
    

    创建表wx_corp_info,用于存储授权企业的信息。用的是mysql数据库。

    然后mybatis-plus逆向生成相关的代码
    编写主类
    WeiXinCorpController

    package xxx;
    
    import com.alibaba.fastjson.JSONArray;
    import com.alibaba.fastjson.JSONObject;
    import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    import com.github.pagehelper.util.StringUtil;
    import com.hssx.cloudmodel.constant.Constant;
    import com.hssx.cloudmodel.entity.SysParam;
    import com.hssx.cloudmodel.entity.User;
    import com.hssx.cloudmodel.entity.WxCorpInfo;
    import com.hssx.cloudmodel.mapper.SysParamMapper;
    import com.hssx.cloudmodel.mapper.UserMapper;
    import com.hssx.cloudmodel.mapper.WxCorpInfoMapper;
    import com.hssx.cloudmodel.util.HttpRespMsg;
    import com.hssx.cloudmodel.util.JsapiTicketUtil;
    import com.hssx.cloudmodel.util.Sha1Util;
    import com.qq.weixin.mp.aes.AesException;
    import com.qq.weixin.mp.aes.WXBizMsgCrypt;
    import io.swagger.annotations.ApiOperation;
    import lombok.extern.slf4j.Slf4j;
    import org.json.XML;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.http.*;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.client.RestTemplate;
    
    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;
    import java.io.UnsupportedEncodingException;
    import java.net.URLDecoder;
    import java.net.URLEncoder;
    import java.time.LocalDateTime;
    import java.util.Date;
    import java.util.SortedMap;
    import java.util.TreeMap;
    
    @RestController
    @RequestMapping("/wxcorp")
    @Slf4j
    public class WeiXinCorpController {
        public static final String GET_SUITE_ACCESS_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token";
        public static final String GET_PREAUTH_CODE_URL = "https://qyapi.weixin.qq.com/cgi-bin/service/get_pre_auth_code?suite_access_token=SUITE_ACCESS_TOKEN";
        //获取企业永久授权码
        public static final String GET_CORP_PERMANENT_CODE_URL = "https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code?suite_access_token=SUITE_ACCESS_TOKEN";
        //获取成员详情
        public static final String GET_USER_INFO_URL = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&userid=USERID";
        //获取部门列表
        public static final String GET_DEPARTMENT_URL = "https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=ACCESS_TOKEN&id=";
        //获取部门成员详情
        public static final String GET_DEPARTMENT_USER_DETAIL_URL = "https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token=ACCESS_TOKEN&department_id=DEPARTMENT_ID&fetch_child=1";
    
        public static final String AUTH_CALLBACK_URL = "http://ymhh.yunsu.cn/wxcorp/authcallback";
        @Value("${suitId}")
        private String suitId;
        @Value("${suitSecret}")
        private String suitSecret;
        @Value("${token}")
        private String token;
        @Value("${encodingAesKey}")
        private String encodingAesKey;
        @Value("${corpId}")
        private String corpId;
    
        @Autowired
        RestTemplate restTemplate;
    
        public static String SUITE_ACCESS_TOKEN = null;
        public static long suiteTokenExpireTime = 0L;
    
        public static String PRE_AUTH_CODE = null;
        public static long expireTime = 0L;
    
        @Resource
        SysParamMapper sysParamMapper;
        @Resource
        WxCorpInfoMapper wxCorpInfoMapper;
        @Resource
        UserMapper userMapper;
    
    
        @ApiOperation(value = "企业微信数据回调", notes = "企业微信数据回调")
        @RequestMapping(value = "/dataCallback/{corpId}", method = RequestMethod.GET)
        @ResponseBody
        public String dataCallback(@PathVariable String corpId, String msg_signature, String timestamp, String nonce, String echostr) {
            System.out.println("========dataCallback========="+corpId);
            try {
                String sVerifyMsgSig = msg_signature;
                String sVerifyTimeStamp = timestamp;
                String sVerifyNonce = nonce;
                String sVerifyEchoStr = echostr;
                WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAesKey, corpId);
                String sEchoStr = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,
                        sVerifyNonce, sVerifyEchoStr);//需要返回的明文
                System.out.println("verifyurl echostr: " + sEchoStr);
                return sEchoStr;
                // 验证URL成功,将sEchoStr返回
                // HttpUtils.SetResponse(sEchoStr);
            }  catch (AesException e) {
                e.printStackTrace();
            }
    
            return "success";
        }
    
        @ApiOperation(value = "企业微信数据回调", notes = "企业微信数据回调")
        @RequestMapping(value = "/dataCallback/{corpId}", method = RequestMethod.POST)
        @ResponseBody
        public String dataCallbackPost(@PathVariable String corpId, @RequestBody String requestBody, String msg_signature, String timestamp, String nonce) {
            log.info("========dataCallback========="+corpId);
            // String sReqMsgSig = HttpUtils.ParseUrl("msg_signature");
            String sReqMsgSig = msg_signature;
            // String sReqTimeStamp = HttpUtils.ParseUrl("timestamp");
            String sReqTimeStamp = timestamp;
            // String sReqNonce = HttpUtils.ParseUrl("nonce");
            String sReqNonce = nonce;
            // post请求的密文数据
            // sReqData = HttpUtils.PostData();
    //        String sReqData = "<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt><AgentID><![CDATA[218]]></AgentID></xml>";
            log.info("===========dataCallback POST=============" + msg_signature);
            log.info("===========corpId=====suitId========" + suitId);
    
            try {
                WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAesKey, suitId);
                String sMsg = wxcpt.DecryptMsg(sReqMsgSig, sReqTimeStamp, sReqNonce, requestBody);
                log.info("解密后===msg: " + sMsg);
    
            } catch (Exception e) {
                // TODO
                // 解密失败,失败原因请查看异常
                e.printStackTrace();
            }
            return "success";
        }
    
        @ApiOperation(value = "企业微信指令回调", notes = "企业微信指令回调, 处理回调验证")
        @RequestMapping(value = "/cmdCallback", method = RequestMethod.GET)
        @ResponseBody
        public String cmdCallbackGet(String msg_signature, String timestamp, String nonce, String echostr) {
            try {
                log.info("===========cmdCallback GET=============" + msg_signature);
                String sVerifyMsgSig = msg_signature;
                String sVerifyTimeStamp = timestamp;
                String sVerifyNonce = nonce;
                String sVerifyEchoStr = echostr;
                WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAesKey, corpId);
                String sEchoStr = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,
                        sVerifyNonce, sVerifyEchoStr);//需要返回的明文
                log.info("verifyurl echostr: " + sEchoStr);
                return sEchoStr;
                // 验证URL成功,将sEchoStr返回
                // HttpUtils.SetResponse(sEchoStr);
            }  catch (AesException e) {
                e.printStackTrace();
            }
    
            return "success";
        }
    
        @ApiOperation(value = "企业微信指令回调", notes = "企业微信指令回调, 处理消息体")
        @RequestMapping(value = "/cmdCallback", method = RequestMethod.POST)
        @ResponseBody
        public String cmdCallbackPost(@RequestBody(required = false) String requestBody, String msg_signature, String timestamp, String nonce) {
            // String sReqMsgSig = HttpUtils.ParseUrl("msg_signature");
            String sReqMsgSig = msg_signature;
            // String sReqTimeStamp = HttpUtils.ParseUrl("timestamp");
            String sReqTimeStamp = timestamp;
            // String sReqNonce = HttpUtils.ParseUrl("nonce");
            String sReqNonce = nonce;
            // post请求的密文数据
            // sReqData = HttpUtils.PostData();
    //        String sReqData = "<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt><AgentID><![CDATA[218]]></AgentID></xml>";
            log.info("===========企业微信指令回调 POST=============" + msg_signature);
            log.info("===========corpId=====suitId========" + suitId);
    
            try {
                WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAesKey, suitId);
                String sMsg = wxcpt.DecryptMsg(sReqMsgSig, sReqTimeStamp, sReqNonce, requestBody);
                log.info("解密后===msg: " + sMsg);
                // TODO: 解析出明文xml标签的内容进行处理
                org.json.JSONObject jsonObject = XML.toJSONObject(sMsg);
                log.info("json=="+jsonObject.toString());
                jsonObject = jsonObject.getJSONObject("xml");
                if (jsonObject.has("AuthCode")) {
                    //企业授权通知
                    String authCode = jsonObject.getString("AuthCode");
                    handleCorpAuth(authCode);
                } else if (jsonObject.has("SuiteTicket")) {
                    //ticket推送
                    String ticket = jsonObject.getString("SuiteTicket");
                    String timeStamp = jsonObject.getLong("TimeStamp")+"";
                    log.info("ticket=="+ticket);
                    //存储
                    SysParam param = sysParamMapper.selectOne(new QueryWrapper<SysParam>().eq("param_code", "suite_ticket"));
                    if (param == null) {
                        param = new SysParam();
                        param.setParamCode("suite_ticket");
                        param.setParamName(ticket);
                        param.setRemark(timeStamp);
                        sysParamMapper.insert(param);
                    } else {
                        param.setParamName(ticket);
                        param.setRemark(timeStamp);
                        sysParamMapper.updateById(param);
                    }
                }
            } catch (Exception e) {
                // TODO
                // 解密失败,失败原因请查看异常
                e.printStackTrace();
            }
            return "success";
        }
    
    
    
        @ApiOperation(value = "企业授权微信应用", notes = "企业授权微信应用")
        @RequestMapping("/getAuthPage")
        @ResponseBody
        public HttpRespMsg getAuthPage() {
            HttpRespMsg msg = new HttpRespMsg();
            String preAuthCode = getAuthCode();
    
            String url = "https://open.work.weixin.qq.com/3rdapp/install?suite_id=SUITE_ID&pre_auth_code=PRE_AUTH_CODE&redirect_uri=REDIRECT_URI&state=STATE";
            url = url.replace("SUITE_ID", suitId).replace("PRE_AUTH_CODE", preAuthCode)
                    .replace("REDIRECT_URI", URLEncoder.encode(AUTH_CALLBACK_URL));
            msg.data = url;
            return msg;
        }
    
    
        @ApiOperation(value = "企业授权后回调地址")
        @RequestMapping("/authcallback")
        @ResponseBody
        public HttpRespMsg authcallback(String auth_code, Integer expires_in, String state) {
            HttpRespMsg msg = new HttpRespMsg();
            log.info("authcallback收到: auth_code="+auth_code+", expires_in="+ expires_in+",state= "+state);
            handleCorpAuth(auth_code);
            return msg;
        }
    
        private void handleCorpAuth(String authCode) {
            String suitAccessToken = getSuiteAccessToken();
            String url = GET_CORP_PERMANENT_CODE_URL.replace("SUITE_ACCESS_TOKEN", suitAccessToken);
            //失效了,需要重新获取
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            JSONObject reqParam = new JSONObject();
            reqParam.put("auth_code",  authCode);
    
            HttpEntity<String> requestEntity = new HttpEntity<String>(reqParam.toJSONString(), headers);
            ResponseEntity<String> responseEntity = this.restTemplate.exchange(url,
                    HttpMethod.POST, requestEntity, String.class);
            if (responseEntity.getStatusCode() == HttpStatus.OK) {
                String resp = responseEntity.getBody();
                log.info(resp);
                JSONObject obj = JSONObject.parseObject(resp);
                if (obj.getIntValue("errcode") == 0) {
                    JSONObject corpInfo = obj.getJSONObject("auth_corp_info");
                    String corpId = corpInfo.getString("corpid");
                    WxCorpInfo data = wxCorpInfoMapper.selectById(corpId);
                    if (data == null) {//不存在的情况下,需要生成企业信息
                        data = new WxCorpInfo();
                        log.info("================create corp=========");
                        data.setCorpid(corpId);
                        String permanentCode = obj.getString("permanent_code");
                        String curCorpAccessToken = obj.getString("access_token");
                        LocalDateTime time = LocalDateTime.now();
                        time = time.plusSeconds(obj.getLong("expires_in"));
                        data.setAccessToken(curCorpAccessToken);
                        data.setCorpFullName(corpInfo.getString("corp_full_name"));
                        data.setCorpIndustry(corpInfo.getString("corp_industry"));
                        data.setCorpName(corpInfo.getString("corp_name"));
                        data.setCorpScale(corpInfo.getString("corp_scale"));
                        data.setCorpSubIndustry(corpInfo.getString("corp_sub_industry"));
                        data.setExpireTime(time);
                        data.setLocation(corpInfo.getString("location"));
                        data.setPermanentCode(permanentCode);
                        //取到当前授权人,按照授权人与企业进行匹配
                        JSONObject authUserInfo = obj.getJSONObject("auth_user_info");
                        data.setAuthUsername(authUserInfo.getString("name"));
                        String userId = authUserInfo.getString("userid");//授权人的userid
                        JSONObject userDetail = getUserInfo(curCorpAccessToken, userId);
                        //按姓名和手机号进行匹配
                        log.info("===userDetail==" + userDetail.toJSONString());
                        User user = userMapper.selectOne(new QueryWrapper<User>().eq("account", userDetail.getString("mobile")).eq("username", userDetail.getString("name")));
                        if (user != null) {
                            //找到了匹配的企业
                            data.setCompanyId(user.getCompanyId());
                        }
                        wxCorpInfoMapper.insert(data);
    
    
                        //获取部门
                        JSONObject deptObj = getDepartments(curCorpAccessToken);
                        JSONArray deptObjJSONArray = deptObj.getJSONArray("department");
    
                        for (int i=0;i<deptObjJSONArray.size(); i++) {
                            int deptId = deptObjJSONArray.getJSONObject(i).getIntValue("id");
                            JSONArray userList = getDeptUserDetail(curCorpAccessToken, deptId);
                            for (int m=0;m<userList.size(); m++) {
                                JSONObject item = userList.getJSONObject(m);
                                log.info("userid="+item.getString("userid")+", name=" + item.getString("name")+", mobile="+item.getString("mobile"));
                                //不存在的人员, 进行插入
                                User employee = new User();
                                employee.setUsername(item.getString("name"));
                                employee.setAccount(item.getString("mobile"));
                                int count = userMapper.selectCount(new QueryWrapper<User>().eq("account", employee.getAccount()).eq("company_id", data.getCompanyId()));
                                if (count == 0) {
                                    //手机号不存在的,添加
                                    if (data.getCompanyId() != null) {
                                        employee.setCompanyId(data.getCompanyId());
                                        userMapper.insert(employee);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    
        private JSONArray getDeptUserDetail(String accessToken, int deptId) {
            String url = GET_DEPARTMENT_USER_DETAIL_URL.replace("ACCESS_TOKEN", accessToken).replace("DEPARTMENT_ID", ""+deptId);
            String result = restTemplate.getForObject(url, String.class);
            JSONObject obj = JSONObject.parseObject(result);
            JSONArray userlist = obj.getJSONArray("userlist");
    
            return userlist;
        }
    
        private JSONObject getDepartments(String accessToken) {
            String url = GET_DEPARTMENT_URL.replace("ACCESS_TOKEN", accessToken);
            String result = restTemplate.getForObject(url, String.class);
            JSONObject obj = JSONObject.parseObject(result);
            return obj;
        }
        private JSONObject getUserInfo(String accessToken, String userId) {
            String url = GET_USER_INFO_URL.replace("ACCESS_TOKEN", accessToken).replace("USERID", userId);
            String result = restTemplate.getForObject(url, String.class);
            JSONObject obj = JSONObject.parseObject(result);
            return obj;
        }
    
    
        //获取预授权码
        private String getAuthCode() {
            if (PRE_AUTH_CODE == null || expireTime < System.currentTimeMillis()) {
                //失效了,需要重新获取
                String resp = restTemplate.getForObject(GET_PREAUTH_CODE_URL.replaceAll("SUITE_ACCESS_TOKEN", getSuiteAccessToken()), String.class);
                log.info(resp);
                JSONObject obj = JSONObject.parseObject(resp);
                if (obj.getIntValue("errcode") == 0) {
                    PRE_AUTH_CODE = obj.getString("pre_auth_code");
                    expireTime = System.currentTimeMillis() + obj.getIntValue("expires_in")*1000;
                }
            }
            return PRE_AUTH_CODE;
        }
    
        //获取第三方应用临时凭证
        private String getSuiteAccessToken() {
            if (SUITE_ACCESS_TOKEN == null || suiteTokenExpireTime < System.currentTimeMillis()) {
                //失效了,需要重新获取
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                JSONObject reqParam = new JSONObject();
                reqParam.put("suite_id",  suitId);
                reqParam.put("suite_secret", suitSecret);
                SysParam param = sysParamMapper.selectOne(new QueryWrapper<SysParam>().eq("param_code", "suite_ticket"));
                if (param != null) {
                    reqParam.put("suite_ticket",param.getParamName());
                }
    
                HttpEntity<String> requestEntity = new HttpEntity<String>(reqParam.toJSONString(), headers);
                ResponseEntity<String> responseEntity = this.restTemplate.exchange(GET_SUITE_ACCESS_TOKEN_URL,
                        HttpMethod.POST, requestEntity, String.class);
                if (responseEntity.getStatusCode() == HttpStatus.OK) {
                    String resp = responseEntity.getBody();
                    log.info(resp);
                    JSONObject obj = JSONObject.parseObject(resp);
                    if (obj.getIntValue("errcode") == 0) {
                        SUITE_ACCESS_TOKEN = obj.getString("suite_access_token");
                        suiteTokenExpireTime = System.currentTimeMillis() + obj.getIntValue("expires_in")*1000;
                    }
                }
            }
            return SUITE_ACCESS_TOKEN;
        }
    }
    

    需要指导和代码的话,请联系qq:373132975

    展开全文
  • 1.概述 企业微信上是这样介绍的。不过经本人的研究测试,该工作流引擎的功能是比较有限的。...2.企业微信开发基础 文档链接: https://work.weixin.qq.com/api/doc#90000/90135/90665 corp...
  • 提供了企业微信注册的原生开发代码 包含注册,获取应用
  • 手把手教你springboot企业微信开发(一)

    千次阅读 热门讨论 2020-05-16 16:53:28
    手把手教你springboot企业微信开发(一)1、 配置企业号2、Springboot配置企业号 1、 配置企业号 企业号登录、设置,网址是: https://work.weixin.qq.com/wework_admin/loginpage_wx 微信扫码登录: 选一个,进入...
  • 获取 code 请看:企业微信开发:网页授权登录    2.获取 access_token 请看:企业微信开发:获取 access_token 根据已经获取的 access_token 和 code 换成员信息   请求方式: GET(HTTPS)   请求地址
  • 企业微信开发内部应用

    千次阅读 2020-03-23 18:03:38
    pom添加第三方企业微信sdk <!-- 企业微信SDK --> <dependency> <groupId>com.github.binarywang</groupId> <artifactId>weixin-java-cp</artifactId> <version>3.7.0...
  • 前言   本文主要实现目的目标需求为:企业微信登录获取人员信息   借鉴于:企业微信官方文档...  关于配置可信域名可以参考我的第一篇文章:企业微信开发:自建应用配置可信域名 OAuth2.0接入流程说明 请求连接
  • 企业微信和企业应用结合的二次开发案例解决方案,方案抽象度高,案例翔实,共29页
  • 企业微信开发,嵌入自定义项目,及JS-SDK的引用

    万次阅读 热门讨论 2018-07-24 20:38:14
     基于H5开发项目,嵌入到企业微信中,并接入js-sdk 并运用企业微信接口。 开发环境:  腾讯企业微信最新版本。后端环境不做要求,能跑通即可(这里我选用的是eclipse的maven项目,之前也出了一篇搭建后台项目的...
  •   先简单说一下什么 JS-SDK 的作用,企业微信 JS-SDK 是企业微信面向网页开发者提供的基于企业微信内的网页开发工具包,具体详情查看企业微信官方文档:JS-SDK   关于微信和企业微信调用屏蔽功能之间的区别:微信...
  • 企业微信开发之01-介绍篇

    千次阅读 2019-02-20 11:39:19
    从来没有接触过企业微信开发,先从企业微信官网api看起,简单了解了开发相关的基础内容。本身技术实力有限,去码云上找到了比较流行的开源项目,直接拿来作为操作微信api的底层实现。 想利用这个机会写个开发过程...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 110,799
精华内容 44,319
关键字:

企业微信开发