企业微信第三方应用(三)基于springboot开发(获取Ticket,auth_code)

一、构建spring boot项目
1、新建项目
新建一个模块(module):enterprise-wechat
新建一个子模块(module):wechat
目录结构如下:

企业微信第三方应用(三)基于springboot开发(获取Ticket,auth_code)

结构描述:
common
-> WeChatConstants:存放企业微信一些常量,公用参数
-> WeChatUtils:存放企业微信第三方应用api
controller
-> SystemController:控制层,接收请求
entity
-> aes:目录下文件企业微信加解密包
service
-> IConfigService:调用企业微信服务层
pom.xml
-> 导入所需要的jar包

pom.xml中需要导入commons.codec包

<dependency>
   <groupid>commons-codec</groupid>
   <artifactid>commons-codec</artifactid>
   <version>1.9</version>
</dependency>

2、方法描述
1)doGetCallback:
① 接收验证请求,用于验证通用开发参数系统事件接收URL、数据回调URL、指令回调URL。
② 企业微信后台录入回调URL点击保存时,微信服务器会立即发送一条GET请求到对应URL,该函数就对URL的signature进行验证。

2)doPostCallback:
① 用于获取 suite_ticket,安装应用时企业微信传递过来的auth_code: 指令回调URL
② 当刷新ticket传递【SuitID】: 指令回调URL
③ 当打开应用时传递【CorpID】: 数据回调URL

3、代码编写
1)企业微信配置类:WeChatConstants

package com.wechat.common;

/**
 * &#x4F01;&#x4E1A;&#x5FAE;&#x4FE1;
 */
public class WeChatConstants {

    // &#x4F01;&#x4E1A;&#x5FAE;&#x4FE1;&#x6388;&#x6743;&#x7801;&#x83B7;&#x53D6;&#x65F6;&#x95F4;
    public static final Long EXPIRES_IN = 24 * 60 * 60 * 1000L;
    //24 * 60 * 60 * 1000L 7200L * 1000

    /**
     * &#x670D;&#x52A1;&#x5546;CorpID
     */
    public static final String CORP_ID = "ww14438c6c07a317f2";
    /**
     * &#x670D;&#x52A1;&#x5546;&#x8EAB;&#x4EFD;&#x7684;&#x8C03;&#x7528;&#x51ED;&#x8BC1;
     */
    public static final String PROVIDER_SECRET = "RH7PehRJX3LIcw4axad_H2T9HSUG1finOBEpnLTVIioBrP-zgZrGsqJ9pHVw5vVj";

    /**
     * &#x5E94;&#x7528;&#x7684;&#x552F;&#x4E00;&#x8EAB;&#x4EFD;&#x6807;&#x8BC6;
     */
    public static final String SUITE_ID = "ww4f66fa544a32f920";
    /**
     * &#x5E94;&#x7528;&#x7684;&#x8C03;&#x7528;&#x8EAB;&#x4EFD;&#x5BC6;&#x94A5;
     */
    public static final String SUITE_SECRET = "vVv8JzaBlEVCTQkHKqmr57EAMs65AILWiI_4ANc25T4";

    /**
     * &#x5E94;&#x7528;&#x7684;ticket
     */
    public static final String SUITE_TICKET = "SUITE_TICKET";

    /**
     * &#x5E94;&#x7528;&#x7684;auth_code
     */
    public static final String AUTH_CODE = "AUTH_CODE";

    /**
     * &#x7B2C;&#x4E09;&#x65B9;&#x5E94;&#x7528;&#x51ED;&#x8BC1;token
     */
    public static final String SUITE_TOKEN = "suiteToken";

    /**
     * &#x6388;&#x6743;&#x65B9;&#xFF08;&#x4F01;&#x4E1A;&#xFF09;token
     */
    public static final String ACCESS_TOKEN = "ACCESS_TOKEN";

    /**
     * &#x63D0;&#x4F9B;&#x5546; &#x6388;&#x6743;&#x65B9;&#x670D;&#x52A1;token
     */
    public static final String PROVIDER_ACCESS_TOKEN = "PROVIDER_ACCESS_TOKEN";

    /**
     * &#x5E94;&#x7528;&#x4F01;&#x4E1A;corpid
     */
    public static final String AUTH_CORPID = "AUTH_CORPID";

    /**
     * &#x4F01;&#x4E1A;&#x540D;&#x79F0;
     */
    public static final String CORP_NAME = "CORPNAME";

    /**
     * &#x6388;&#x6743;&#x65B9;&#x7684;&#x7F51;&#x9875;&#x5E94;&#x7528;ID&#xFF0C;&#x5728;&#x5177;&#x4F53;&#x7684;&#x7F51;&#x9875;&#x5E94;&#x7528;&#x4E2D;&#x67E5;&#x770B;
     */
    public static final String AGENT_ID = "AGENTID";

    /**
     * &#x7528;&#x6237;id
     */
    public static final String USER_ID = "userId";

    // &#x56DE;&#x8C03;&#x76F8;&#x5173;
    /**
     * &#x56DE;&#x8C03;/&#x901A;&#x7528;&#x5F00;&#x53D1;&#x53C2;&#x6570;Token, &#x4E24;&#x8005;&#x89E3;&#x5BC6;&#x7B97;&#x6CD5;&#x4E00;&#x6837;&#xFF0C;&#x6240;&#x4EE5;&#x4E3A;&#x65B9;&#x4FBF;&#x8BBE;&#x4E3A;&#x4E00;&#x6837;
     */
    public static final String TOKENS = "E0sOXx4LqeE5BmDvMTAz3x";

    /**
     * &#x56DE;&#x8C03;/&#x901A;&#x7528;&#x5F00;&#x53D1;&#x53C2;&#x6570;EncodingAESKey, &#x4E24;&#x8005;&#x89E3;&#x5BC6;&#x7B97;&#x6CD5;&#x4E00;&#x6837;&#xFF0C;&#x6240;&#x4EE5;&#x4E3A;&#x65B9;&#x4FBF;&#x8BBE;&#x4E3A;&#x4E00;&#x6837;
     */
    public static final String ENCODING_AES_KEY = "IESLPSyW4vyBB90jkzfwfYRtcMky6LIOevr4SVefz7I";

    public static final String REDIRECT_URI = "REDIRECT_URI";

    /**
     * &#x91CD;&#x5B9A;&#x5411;&#x5730;&#x5740;&#xFF0C;&#x81EA;&#x5DF1;&#x8BBE;&#x7F6E;
     */
    public static final String REDIRECT_URL = "www.baidu.com";

    // &#x7B2C;&#x4E09;&#x65B9;&#x5E94;&#x7528;id&#xFF08;&#x5373;ww&#x6216;wx&#x5F00;&#x5934;&#x7684;suite_id&#xFF09;
    public static final String APP_ID= "APPID";

    public static final String PERMANENT_CODE = "PERMANENT_CODE";

}

2)企业微信api:WeChatUtils

package com.wechat.common;

/**
 * &#x4F01;&#x4E1A;&#x5FAE;&#x4FE1;&#x5DE5;&#x5177;&#x7C7B;
 */
public class WeChatUtils {
    /**
     * &#x7B2C;&#x4E09;&#x65B9;&#x5E94;&#x7528;api start
     */
    // &#x83B7;&#x53D6;&#x7B2C;&#x4E09;&#x65B9;&#x5E94;&#x7528;&#x51ED;&#x8BC1;
    public final static String THIRD_BUS_WECHAT_SUITE_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token";

    // &#x83B7;&#x53D6;&#x4F01;&#x4E1A;&#x6C38;&#x4E45;&#x6388;&#x6743;&#x7801;
    public final static String THIRD_BUS_WECHAT_ACCESS_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code?suite_access_token=SUITE_ACCESS_TOKEN";

    // &#x7B2C;&#x4E09;&#x65B9; &#x6784;&#x9020;&#x626B;&#x7801;&#x767B;&#x5F55;&#x94FE;&#x63A5;
    public final static String THIRD_BUS_WECHAT_LOGIN = "https://open.work.weixin.qq.com/wwopen/sso/3rd_qrConnect?appid=CORPID&redirect_uri=REDIRECT_URI&state=web_login&usertype=member";

    // &#x7B2C;&#x4E09;&#x65B9; &#x83B7;&#x53D6;&#x767B;&#x5F55;&#x7528;&#x6237;&#x4FE1;&#x606F; POST
    public final static String THIRD_BUS_WECHAT_GET_LOGIN_INFO = "https://qyapi.weixin.qq.com/cgi-bin/service/get_login_info?access_token=PROVIDER_ACCESS_TOKEN";

    // &#x7B2C;&#x4E09;&#x65B9; &#x6784;&#x9020;&#x7F51;&#x9875;&#x6388;&#x6743;&#x94FE;&#x63A5;
    public final static String THIRD_BUS_WECHAT_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_privateinfo&state=STATE#wechat_redirect";

    // &#x7B2C;&#x4E09;&#x65B9; &#x83B7;&#x53D6;&#x8BBF;&#x95EE;&#x7528;&#x6237;&#x8EAB;&#x4EFD; GET
    public final static String THIRD_BUS_WECHAT_GET_USER_INFO = "https://qyapi.weixin.qq.com/cgi-bin/service/getuserinfo3rd?suite_access_token=SUITE_TOKEN&code=CODE";

    // &#x7B2C;&#x4E09;&#x65B9; &#x83B7;&#x53D6;&#x8BBF;&#x95EE;&#x7528;&#x6237;&#x654F;&#x611F;&#x4FE1;&#x606F; post
    public final static String THIRD_BUS_WECHAT_GET_USER_DETAIL3RD = "https://qyapi.weixin.qq.com/cgi-bin/service/getuserdetail3rd?suite_access_token=SUITE_ACCESS_TOKEN";

    // &#x7B2C;&#x4E09;&#x65B9; &#x83B7;&#x53D6;&#x90E8;&#x95E8;&#x5217;&#x8868;
    public final static String THIRD_BUS_WECHAT_DEPART_LIST = "https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=ACCESS_TOKEN&id=ID";

    // &#x7B2C;&#x4E09;&#x65B9; &#x83B7;&#x53D6;&#x90E8;&#x95E8;&#x6210;&#x5458;
    public final static String THIRD_BUS_WECHAT_DEPART_USER = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?access_token=ACCESS_TOKEN&department_id=DEPARTMENT_ID&fetch_child=FETCH_CHILD";

    // &#x7B2C;&#x4E09;&#x65B9; &#x83B7;&#x53D6;&#x90E8;&#x95E8;&#x6210;&#x5458;&#x8BE6;&#x60C5;
    public final static String THIRD_BUS_WECHAT_DEPART_USER_DETAIL = "https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token=ACCESS_TOKEN&department_id=DEPARTMENT_ID&fetch_child=FETCH_CHILD";

    // &#x7B2C;&#x4E09;&#x65B9; &#x8BFB;&#x53D6;&#x6210;&#x5458; GET
    public final static String THIRD_BUS_WECHAT_GET_USER = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&userid=USERID";

    // &#x670D;&#x52A1;&#x5546;&#x7684;token
    public final static String THIRD_BUS_WECHAT_GET_PROVIDER_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/service/get_provider_token";

    // &#x83B7;&#x53D6;&#x4F01;&#x4E1A;&#x51ED;&#x8BC1;
    public final static String THIRD_BUS_WECHAT_GET_CORP_TOKEN = "https://qyapi.weixin.qq.com/cgi-bin/service/get_corp_token?suite_access_token=SUITE_ACCESS_TOKEN";

    // &#x53D1;&#x9001;&#x5E94;&#x7528;&#x6D88;&#x606F;
    public final static String THIRD_BUS_WECHAT_SEND = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN";

    // &#x83B7;&#x53D6;&#x5E94;&#x7528;&#x7684;jsapi_ticket
    public final static String THIRD_BUS_GET_JSAPI_TICKET = "https://qyapi.weixin.qq.com/cgi-bin/ticket/get?access_token=ACCESS_TOKEN&type=agent_config";

    // &#x83B7;&#x53D6;&#x4F01;&#x4E1A;&#x7684;jsapi_ticket
    public final static String THIRD_BUS_GET_JSAPI_TICKET_BUS = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=ACCESS_TOKEN";
    /**
     * &#x7B2C;&#x4E09;&#x65B9;&#x5E94;&#x7528;api end
     */

}

3)controller层:SystemController

package com.wechat.controller;

import com.wechat.service.IConfigService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 * &#x63A7;&#x5236;&#x5C42;
 */
@Slf4j
@RestController
@RequestMapping(value = "system")
public class SystemController {

    @Autowired
    private IConfigService configService;

    /**
     * &#x9A8C;&#x8BC1;&#x901A;&#x7528;&#x5F00;&#x53D1;&#x53C2;&#x6570;&#x53CA;&#x5E94;&#x7528;&#x56DE;&#x8C03;
     * @param: request
     * @param: response
     * @returns: void
     */
    @ApiOperation(value = "&#x9A8C;&#x8BC1;&#x901A;&#x7528;&#x5F00;&#x53D1;&#x53C2;&#x6570;&#x53CA;&#x5E94;&#x7528;&#x56DE;&#x8C03;")
    @GetMapping(value = "getEchostr")
    public void doGetCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // &#x5FAE;&#x4FE1;&#x52A0;&#x5BC6;&#x7B7E;&#x540D;
        String msgSignature = request.getParameter("msg_signature");
        // &#x65F6;&#x95F4;&#x6233;
        String timestamp = request.getParameter("timestamp");
        // &#x968F;&#x673A;&#x6570;
        String nonce = request.getParameter("nonce");
        // &#x968F;&#x673A;&#x5B57;&#x7B26;&#x4E32;
        // &#x5982;&#x679C;&#x662F;&#x5237;&#x65B0;&#xFF0C;&#x9700;&#x8FD4;&#x56DE;&#x539F;echostr
        String echoStr = request.getParameter("echostr");
        String sEchoStr=  "";
        PrintWriter out;
        log.debug("msgSignature: " + msgSignature+"timestamp="+timestamp+"nonce="+nonce+"echoStr="+echoStr);
        try {
            sEchoStr = configService.doGetCallback(msgSignature,timestamp,nonce,echoStr); //&#x9700;&#x8981;&#x8FD4;&#x56DE;&#x7684;&#x660E;&#x6587;;
            log.debug("doGetCallback-> echostr: " + sEchoStr);
            // &#x9A8C;&#x8BC1;URL&#x6210;&#x529F;&#xFF0C;&#x5C06;sEchoStr&#x8FD4;&#x56DE;
            out = response.getWriter();
            out.print(sEchoStr);
        } catch (Exception e) {
            //&#x9A8C;&#x8BC1;URL&#x5931;&#x8D25;&#xFF0C;&#x9519;&#x8BEF;&#x539F;&#x56E0;&#x8BF7;&#x67E5;&#x770B;&#x5F02;&#x5E38;
            e.printStackTrace();
        }
    }

    /**
     * &#x5237;&#x65B0;ticket&#xFF0C;AuthCode
     */
    @ApiOperation(value = "&#x5237;&#x65B0;ticket&#xFF0C;AuthCode")
    @PostMapping(value = "getEchostr")
    public String doPostCallback(HttpServletRequest request) throws Exception {
        // &#x5FAE;&#x4FE1;&#x52A0;&#x5BC6;&#x7B7E;&#x540D;
        String msgSignature = request.getParameter("msg_signature");
        // &#x65F6;&#x95F4;&#x6233;
        String timestamp = request.getParameter("timestamp");
        // &#x968F;&#x673A;&#x6570;
        String nonce = request.getParameter("nonce");
        // &#x7C7B;&#x578B;
        String type = request.getParameter("type");
        // &#x4F01;&#x4E1A;id
        String corpId = request.getParameter("corpid");
        ServletInputStream in = request.getInputStream();
        // &#x5237;&#x65B0;ticket&#xFF0C;AuthCode
        String success = configService.doPostCallback(msgSignature, timestamp, nonce, type, corpId, in);
        return success;
    }
}

4)Service层:IConfigService

package com.wechat.service;

import javax.servlet.ServletInputStream;

/**
 * &#x4F01;&#x4E1A;&#x5FAE;&#x4FE1;&#x7B2C;&#x4E09;&#x65B9;&#x670D;&#x52A1;service
 */
public interface IConfigService {

    /**
     * &#x9A8C;&#x8BC1;&#x901A;&#x7528;&#x5F00;&#x53D1;&#x53C2;&#x6570;&#x53CA;&#x5E94;&#x7528;&#x56DE;&#x8C03;
     * @returns: java.lang.String
     */
    String doGetCallback(String msgSignature, String timestamp, String nonce, String echoStr);

    /**
     * &#x83B7;&#x53D6;SuiteTicket&#xFF0C;AuthCode
     */
    String doPostCallback(String msgSignature, String timestamp, String nonce, String type, String corpId, ServletInputStream in);
}

5)service实现类:ConfigServiceImpl

package com.wechat.service.impl;

import com.alibaba.druid.support.json.JSONUtils;
import com.wechat.common.StringUtils;
import com.wechat.common.WeChatConstants;
import com.wechat.common.WxUtil;
import com.wechat.common.cache.CacheData;
import com.wechat.entity.aes.AesException;
import com.wechat.entity.aes.WXBizMsgCrypt;
import com.wechat.service.IConfigService;
import com.wechat.service.IWeChatService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Map;

/**
 * &#x56DE;&#x8C03;service
 */
@Slf4j
@Service
public class ConfigServiceImpl implements IConfigService {

    @Autowired
    private IWeChatService weChatService;

    /**
     * &#x9A8C;&#x8BC1;&#x901A;&#x7528;&#x5F00;&#x53D1;&#x53C2;&#x6570;&#x53CA;&#x5E94;&#x7528;&#x56DE;&#x8C03;
     * @returns: java.lang.String
     */
    @Override
    public String doGetCallback(String msgSignature, String timestamp, String nonce, String echoStr) {
        //&#x9700;&#x8981;&#x8FD4;&#x56DE;&#x7684;&#x660E;&#x6587;
        String sEchoStr="";
        try {
            log.debug(WeChatConstants.TOKENS, WeChatConstants.ENCODING_AES_KEY, WeChatConstants.CORP_ID);
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(WeChatConstants.TOKENS, WeChatConstants.ENCODING_AES_KEY, WeChatConstants.CORP_ID);
            sEchoStr = wxcpt.VerifyURL(msgSignature, timestamp, nonce, echoStr);
        } catch (AesException e) {
            e.printStackTrace();
        }
        return sEchoStr;
    }

    /**
     * &#x83B7;&#x53D6;SuiteTicket&#xFF0C;AuthCode
     * @param: msgSignature &#x5FAE;&#x4FE1;&#x52A0;&#x5BC6;&#x7B7E;&#x540D;
     * @param: timestamp &#x65F6;&#x95F4;&#x6233;
     * @param: nonce  &#x968F;&#x673A;&#x6570;
     * @param: type &#x7C7B;&#x578B;
     * @param: corpId &#x4F01;&#x4E1A;id
     * @param: in
     * @returns: java.lang.String
     */
    @Override
    public String doPostCallback(String msgSignature, String timestamp, String nonce, String type, String corpId, ServletInputStream in) {
        String id = "";
        // &#x8BBF;&#x95EE;&#x5E94;&#x7528;&#x548C;&#x4F01;&#x4E1A;&#x56DE;&#x8C03;&#x4F20;&#x4E0D;&#x540C;&#x7684;ID
        if(!StringUtils.isNull(type) && type.equals("data")){
            id = corpId;
            log.debug("======corpId==="+id);
        } else {
            id = WeChatConstants.SUITE_ID;
            log.debug("======SuiteId===" + id);
        }
        try {
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(WeChatConstants.TOKENS, WeChatConstants.ENCODING_AES_KEY, id);
            String postData="";   // &#x5BC6;&#x6587;&#xFF0C;&#x5BF9;&#x5E94;POST&#x8BF7;&#x6C42;&#x7684;&#x6570;&#x636E;
            //1.&#x83B7;&#x53D6;&#x52A0;&#x5BC6;&#x7684;&#x8BF7;&#x6C42;&#x6D88;&#x606F;&#xFF1A;&#x4F7F;&#x7528;&#x8F93;&#x5165;&#x6D41;&#x83B7;&#x5F97;&#x52A0;&#x5BC6;&#x8BF7;&#x6C42;&#x6D88;&#x606F;postData
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            String tempStr = "";   //&#x4F5C;&#x4E3A;&#x8F93;&#x51FA;&#x5B57;&#x7B26;&#x4E32;&#x7684;&#x4E34;&#x65F6;&#x4E32;&#xFF0C;&#x7528;&#x4E8E;&#x5224;&#x65AD;&#x662F;&#x5426;&#x8BFB;&#x53D6;&#x5B8C;&#x6BD5;
            while(null != (tempStr=reader.readLine())){
                postData+=tempStr;
            }
            log.debug("====msg_signature===="+msgSignature+"====timestamp==="+timestamp+"====nonce==="+nonce+"====postData==="+postData);
            String suiteXml = wxcpt.DecryptMsg(msgSignature, timestamp, nonce, postData);
            log.debug("suiteXml: " + suiteXml);
            Map suiteMap = WxUtil.parseXml(suiteXml);
            log.debug("==suiteMap=="+ JSONUtils.toJSONString(suiteMap));
            if(suiteMap.get("SuiteTicket") != null) {
                String suiteTicket = (String) suiteMap.get("SuiteTicket");
                CacheData.put(WeChatConstants.SUITE_TICKET, suiteTicket);
                log.debug("====SuiteTicket=====" + suiteTicket);
            } else if(suiteMap.get("AuthCode") != null){
                String authCode = (String) suiteMap.get("AuthCode");
                log.debug("doPostValid->AuthCode:" + authCode);
                //&#x6839;&#x636E;authcode&#x83B7;&#x53D6;&#x4F01;&#x4E1A;&#x6C38;&#x4E45;&#x6388;&#x6743;&#x7801;
                weChatService.getPermanentCode(authCode);
                CacheData.put(WeChatConstants.AUTH_CODE, authCode);

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "success";
    }
}

pom.xml

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelversion>4.0.0</modelversion>
    <!--<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.5</version>
        <relativePath/>

    </parent>-->
    <parent>
        <groupid>org.example</groupid>
        <artifactid>third-wechat</artifactid>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <groupid>com.wechat</groupid>
    <artifactid>wechat</artifactid>
    <version>0.0.1-SNAPSHOT</version>
    <name>wechat</name>
    <description>wechat</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-jdbc</artifactid>
        </dependency>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-thymeleaf</artifactid>
        </dependency>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-web</artifactid>
        </dependency>
        <dependency>
            <groupid>org.mybatis.spring.boot</groupid>
            <artifactid>mybatis-spring-boot-starter</artifactid>
            <version>2.2.2</version>
        </dependency>

        <dependency>
            <groupid>mysql</groupid>
            <artifactid>mysql-connector-java</artifactid>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-test</artifactid>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupid>org.dom4j</groupid>
            <artifactid>dom4j</artifactid>
            <version>2.0.0</version>
        </dependency>

        <dependency>
            <groupid>commons-codec</groupid>
            <artifactid>commons-codec</artifactid>
            <version>1.9</version>
        </dependency>

        <dependency>
            <groupid>org.apache.commons</groupid>
            <artifactid>commons-lang3</artifactid>
            <version>3.10</version>
        </dependency>

        <dependency>
            <groupid>org.projectlombok</groupid>
            <artifactid>lombok</artifactid>
            <version>1.18.16</version>
        </dependency>
        <dependency>
            <groupid>com.alibaba</groupid>
            <artifactid>druid</artifactid>
            <version>1.2.4</version>
        </dependency>
        <dependency>
            <groupid>io.swagger</groupid>
            <artifactid>swagger-annotations</artifactid>
            <version>1.5.24</version>
        </dependency>

        <dependency>
            <groupid>cn.hutool</groupid>
            <artifactid>hutool-all</artifactid>
            <version>5.7.5</version>
        </dependency>

        <dependency>
            <groupid>org.aspectj</groupid>
            <artifactid>aspectjrt</artifactid>
            <version>1.9.6</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupid>org.springframework.boot</groupid>
                <artifactid>spring-boot-maven-plugin</artifactid>
            </plugin>
        </plugins>
    </build>

</project>

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanperiod="60 seconds" debug="false">
    <!-- 日志存放路径 -->
    <property name="log.path" value="logs/wechat">
   <!-- 日志输出格式 -->
    <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n">

    <!-- 控制台输出 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
    </appender>

    <!-- 系统日志输出 -->
    <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/info.log</file>
        <!-- 循环政策:基于时间创建日志文件 -->
        <rollingpolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志文件名格式 -->
            <filenamepattern>${log.path}/info.%d{yyyy-MM-dd}.log</filenamepattern>
            <!-- 日志最大的历史 60天 -->
            <maxhistory>60</maxhistory>
        </rollingpolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 过滤的级别 -->
            <level>INFO</level>
            <!-- 匹配时的操作:接收(记录) -->
            <onmatch>ACCEPT</onmatch>
            <!-- 不匹配时的操作:拒绝(不记录) -->
            <onmismatch>DENY</onmismatch>
        </filter>
    </appender>

    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}/error.log</file>
        <!-- 循环政策:基于时间创建日志文件 -->
        <rollingpolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志文件名格式 -->
            <filenamepattern>${log.path}/error.%d{yyyy-MM-dd}.log</filenamepattern>
            <!-- 日志最大的历史 60天 -->
            <maxhistory>60</maxhistory>
        </rollingpolicy>
        <encoder>
            <pattern>${log.pattern}</pattern>
        </encoder>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 过滤的级别 -->
            <level>ERROR</level>
            <!-- 匹配时的操作:接收(记录) -->
            <onmatch>ACCEPT</onmatch>
            <!-- 不匹配时的操作:拒绝(不记录) -->
            <onmismatch>DENY</onmismatch>
        </filter>
    </appender>

    <!-- 系统模块日志级别控制  -->
    <logger name="com.wechat" level="debug">
    <!-- Spring日志级别控制  -->
    <logger name="org.springframework" level="warn">

    <!--<root level="info">
        <appender-ref ref="console" />
    </root>-->

    <root level="debug">
        <appender-ref ref="console">
    </appender-ref></root>

    <!--系统操作日志-->
    <root level="info">
        <appender-ref ref="file_info">
        <appender-ref ref="file_error">
    </appender-ref></appender-ref></root>
</logger></logger></property></property></configuration>

4、验证
以上代码编写完成后,就可以打包到环境上面进行测试验证:
①:echostr验证

企业微信第三方应用(三)基于springboot开发(获取Ticket,auth_code)
企业微信第三方应用(三)基于springboot开发(获取Ticket,auth_code)

返回结果:返回 echostr,并显示已验证

16:11:46.940 [http-nio-9205-exec-7] INFO  c.q.w.s.c.SystemController - [doGetValid,94] - doGetCallback->echostr: 577115934236344259
16:11:46.969 [http-nio-9205-exec-3] INFO  c.q.w.s.c.SystemController - [doGetValid,94] - doGetCallback->echostr: 5267604771365158379

②:刷新Ticket:获取Ticket有两种方式,一是点击 按钮获取,二是企业微信 每15分钟会调用回调接口获取一次

企业微信第三方应用(三)基于springboot开发(获取Ticket,auth_code)
点击”刷新Ticket” 会弹出如下图,然后点击确定
企业微信第三方应用(三)基于springboot开发(获取Ticket,auth_code)
Ticket 有效期为30分钟; 建议把Ticket放到数据库或者redis中
企业微信第三方应用(三)基于springboot开发(获取Ticket,auth_code)
③:获取auth_code
安装第三方应用的时候,会获取auth_code
企业微信第三方应用(三)基于springboot开发(获取Ticket,auth_code)

④:安装测试流程

企业微信第三方应用(三)基于springboot开发(获取Ticket,auth_code)
企业微信第三方应用(三)基于springboot开发(获取Ticket,auth_code)
通过企业微信扫码进行安装
企业微信第三方应用(三)基于springboot开发(获取Ticket,auth_code)
企业微信第三方应用(三)基于springboot开发(获取Ticket,auth_code)
上面就是验证通过,及获取Ticket和auth_code

5、总结
在第三方应用开发中,主要围绕三种类型的access_token(见企业微信地方应用(二) https://www.cnblogs.com/why0703/p/15983925.html)

provider_access_token:服务商的token
suite_access_token:获取第三方应用凭证
access_token:授权方(企业)access_token

通过上面的代码及配置,我们获取到了suiteTicket和auth_code。
接下来我们要通过这些值获取到上面token,通过springboot开发实现”企业微信第三方应用(二)api使用测试”

Original: https://www.cnblogs.com/why0703/p/15983995.html
Author: why0703
Title: 企业微信第三方应用(三)基于springboot开发(获取Ticket,auth_code)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/580928/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • springboot操作es

    转载:https://blog.csdn.net/qq_40018541/article/details/124839238?utm_medium=distribute.pc_re…

    Java 2023年5月30日
    072
  • 四大函数式接口

    四大函数式接口 Fuction 函数型接口,有一个输入参数,有一个输出参数 函数型接口:输入一个参数,输出输入的参数 //Function 函数型接口 public class D…

    Java 2023年6月5日
    063
  • Spring Cloud认知学习(三):声明式调用Feign的使用

    Feign 使用示例 1.导入依赖: 2.新建Feign Interface 3.创建服务消费者 4.测试 补充: 💡上一篇介绍微服务构建起来后,使用Ribbon来解决多个服务的负…

    Java 2023年5月30日
    079
  • 图解用户登录验证流程,写得太好了!

    原文:juejin.cn/post/7025768845075808286 前言 本文通过图示及代码的方式介绍用户登录流程及技术实现,内容包括用户登录,用户验证,如何获取操作用户的…

    Java 2023年5月29日
    072
  • Linux常用命令整理:文件目录管理

    据说,你要对Linux文件做的事情,98%都记录在这篇文章里了。 1.ls命令 最常见的命令,相信刚进入linux命令行界面的时候,都要用这个命令看看当前目录下都有哪些文件吧。 名…

    Java 2023年6月5日
    083
  • Java四大引用详解:强引用、软引用、弱引用、虚引用

    面试官考察Java引用会问到强引用、弱引用、软引用、虚引用,具体有什么区别?本篇单独来详解 @mikechen Java引用 从JDK 1.2版本开始,对象的引用被划分为4种级别,…

    Java 2023年6月15日
    093
  • Java Date 和 Calendar 实例

    Java 之 Date 和 Calendar 实例 package com.homer.learn; import java.text.DateFormat; import jav…

    Java 2023年5月29日
    061
  • 为什么说Java8的Stream并行流底层使用了Fork/Join框架

    先说结论 Stream 是支持串行和并行执行这两种方式的 调用parallel方法即可 Stream.of(1, 2, 3, 4, 5).parallel() 先写一个Java8S…

    Java 2023年5月29日
    065
  • SpringBoot整合atomikos实现跨库事务

    背景 框架之前完成了多数据源的动态切换及事务的处理,想更近一步提供一个简单的跨库事务处理功能,经过网上的搜索调研,大致有XA事务/SEGA事务/TCC事务等方案,因为业务主要涉及政…

    Java 2023年6月15日
    066
  • Elasticsearch的cmd窗口乱码问题(windows)

    elasticsearch 7.6.0 windows版日志乱码问题解决 修改jvm.options,如何重启es即可 新增 -Dfile.encoding=GBK Origina…

    Java 2023年6月16日
    065
  • 深入详解Mybatis的架构原理与6大核心流程

    MyBatis 是 Java 生态中非常著名的一款 ORM 框架,目前在一线互联网大厂中应用广泛,Mybatis已经成为了一个必会框架。 如果你想要进入一线大厂,能够熟练使用 My…

    Java 2023年6月15日
    082
  • JVM内存模型和结构详解(五大模型图解)

    JVM内存模型和Java内存模型都是面试的热点问题,名字看感觉都差不多,实际上他们之间差别还是挺大的。 通俗点说,JVM内存结构是与JVM的内部存储结构相关,而Java内存模型是与…

    Java 2023年6月15日
    061
  • 软件装在D盘,实测有效

    C盘容量小,希望把所有软件都装到D盘,试过很多次,没什么作用。今天装MS全家桶的时候看到了个帖子,实测有效,Visio、Word、Excel、PowerPoint都装到了D盘原贴链…

    Java 2023年6月9日
    0144
  • Starting MySQL… ERROR! The server quit without updating PID file 问题解决

    今天遇到一个mysql起不来,不知为啥挂了,启动是下面的报错Starting MySQL… ERROR! The server quit without updatin…

    Java 2023年6月5日
    054
  • 云E办接口文档

    简介: 云E办接口文档 HOST:localhost:8081 联系人:wanglufei Version:1.0 接口路径:/v2/api-docs 验证码 接口描述: 接口地址…

    Java 2023年6月5日
    069
  • 含源码解析,深入Java 线程池原理

    从池化技术到底层实现,一篇文章带你贯通线程池技术。 1、池化技术简介 在系统开发过程中,我们经常会用到池化技术来减少系统消耗,提升系统性能。在编程领域,比较典型的池化技术有:线程池…

    Java 2023年5月29日
    061
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球