JAVA 微信公众号授权给开放平台(第三方平台)开发流程及第三方平台代公众号实现业务

一 、开放平台账户注册及开发配置请参考我之前的文章 开发前准备工作。

二、授权流程 官方文档细节比较多 我说的比较直白
(1)首先 启动票据推送服务
(2)接收消息→解密→验证并获取票据→保存票据 component_verify_ticket
(3)获取第三方平台调用凭证 component_access_token
(4)通过 component_access_token 获取预授权码 pre_auth_code
(5)通过 pre_auth_code 自建 PC授权链接 或 H5授权链接
(6)访问授权链接进入授权页面完成公众号授权;

三、授权实现 (直接贴代码)

package com.zaiyun.wechat.controller;

import com.alibaba.fastjson2.JSONObject;
import com.qq.weixin.mp.aes.AesException;
import com.zaiyun.common.core.controller.BaseController;
import com.zaiyun.common.core.domain.AjaxResult;
import com.zaiyun.common.annotation.Anonymous;
import com.zaiyun.wechat.service.ThirdPartyTicketService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * 第三方平台调用凭证
 */
@Anonymous
@RestController
@RequestMapping("/ticket")
public class ThirdPartyTicketController extends BaseController {
    @Resource
    ThirdPartyTicketService thirdPartyTicketService;

    private static final Logger wechatLogger = LoggerFactory.getLogger("extend-wechat");

    /**
     * 消息与事件接收配置
     */
    @RequestMapping("/{appId}/callback")
    public String callback() {
        return "success";
    }

    /**
     * 启动票据推送服务
     */
    @PostMapping("/start/push")
    public AjaxResult startPushTicket() {
        JSONObject resultObj = thirdPartyTicketService.startPushTicket();
        if (resultObj.getInteger("errcode") == 0) {
            return success(resultObj.getString("errmsg"));
        }
        return error(resultObj.toString());
    }

    /**
     * 验证票据
     *
     * @param msgSignature 微信加密签名
     * @param timeStamp    时间戳
     * @param nonce        随机数
     * @param postData     消息体
     * @return 结果
     * @throws AesException 异常提现
     */
    @PostMapping("/verify")
    public String componentVerifyTicket(@RequestParam("timestamp") String timeStamp, @RequestParam("nonce") String nonce, @RequestParam("msg_signature") String msgSignature, @RequestBody String postData) throws AesException {
        try {
            thirdPartyTicketService.componentVerifyTicket(msgSignature, timeStamp, nonce, postData);
        } catch (Exception e) {
            wechatLogger.info("消息推送异常", e);
            e.printStackTrace();
        }
        return "success";
    }

    /**
     * 获取令牌component_access_token
     */
    @RequestMapping("/component/access/token")
    public AjaxResult getComponentAccessToken() {
        JSONObject accessToken = thirdPartyTicketService.getComponentAccessToken();
        return success(accessToken);
    }

    /**
     * 获取预授权码
     */
    @RequestMapping("/pre/auth/code")
    public AjaxResult getPreAuthCode() {
        JSONObject authCode = thirdPartyTicketService.getPreAuthCode();
        return success(authCode);
    }

    /**
     * 获取刷新令牌
     *
     * @param authorizationCode 授权码
     */
    @PostMapping("/get/refresh/token")
    public AjaxResult getAuthorizerRefreshToken(@RequestParam("authorizationCode") String authorizationCode) {
        JSONObject refreshToken = thirdPartyTicketService.getAuthorizerRefreshToken(authorizationCode);
        return success(refreshToken);
    }

    /**
     * 获取授权账号调用令牌
     *
     * @param authorizerAppid 授权方公众号APPID
     */
    @PostMapping("/get/access/token")
    public AjaxResult getAuthorizerAccessToken(@RequestParam("authorizerAppid") String authorizerAppid) {
        String authorizerRefreshToken = "refreshtoken@@@Gr8Kl0v10e0B8SrIBmlXfB2PXjcn4TA-RPUqkg1Iu5I";
        JSONObject authorizerAccessToken = thirdPartyTicketService.getAuthorizerAccessToken(authorizerAppid, authorizerRefreshToken);
        return success(authorizerAccessToken);
    }
}

(1)首先启动票据推送

	/**
     * 启动票据推送服务
     */
    public JSONObject startPushTicket() {
        String url = "https://api.weixin.qq.com/cgi-bin/component/api_start_push_ticket";
        HashMap<String, String> paramHeader = new HashMap<>();//请求头参数
        paramHeader.put("Content-Type", "application/json");

        HashMap<String, String> paramBody = new HashMap();//请求体
        paramBody.put("component_appid", weixinConfig.getThirdPartyAppId());
        paramBody.put("component_secret", weixinConfig.getThirdPartyAppSecret());
        Object bodyParam = ConvertUtils.mapToObject(paramBody);

        ResponseEntity<String> responseEntity = restTemplateUtils.post(url, paramHeader, bodyParam, String.class);
        return JSON.parseObject(String.valueOf(responseEntity.getBody()));
    }

在这里插入图片描述

(2)验证票据并缓存 component_verify_ticket 这个很重要、非常重要、必须保存好;
Ticket的有效时间为12小时, 每隔10分钟以 POST 的方式推送,推送的加密消息如下(这是我打印的日志)

10:13:49.990 [http-nio-8090-exec-70] INFO  wechat - [callback,34] - 消息与事件
<xml>
    <ToUserName><![CDATA[gh_138c7a943970]]></ToUserName>
    <Encrypt><![CDATA[0jexJT/7Vc4g1cwSYSuROJCpXki1j5reusgy/O43RNadB9dHFCUQ/B9XDXfIYGOrIURyP5ZbQ4SNk8c+YS0lozlIZxSzVMRPg36K74frTCFqODs0F7GDhTT1cMk13JwJBOtdpQwKR9QRrRZPU4h41WkU3M2X2aMN9eXOws/RV+VJzVzPcNXLC9Z8LnuPiz+JoXTFVM3yOIypxu1zi7cl6eh8Lookl025ZuMIc8OmxZKHW4UiyI49v8D1bc4elTt2eI5Sl4C0uYzYYIBlgfnoyStManqAL+c/MODABu0HzenvbRmpZ0iZEpGfjFghRirABvIaaT9H7ok989Fkx+J9DUAuyT0aCEcBNY3w/JP81wmi3Y9x8MM0KWyN5XIELDA6A7LZz/8BQ3NFkgMevNAO87U0z7XFo+VweOb7W01si1+Z3Z/uLqv40VFtFdGNXhYvuA1C/4u/b7y+OtJZrO14AB5y8aT3hUwpGuUTBZMcZnXYKuslEldLGmIug+bPrcSv]]></Encrypt>
</xml>

(3)接收到此消息后需要解密 官方解密文档 官方解密示例 官方解密代码示例包

    /**
     * 验证票据
     *
     * @param msgSignature 微信加密签名
     * @param timeStamp    时间戳
     * @param nonce        随机数
     * @param postData     消息体
     * @return 结果
     * @throws AesException 异常
     */
    public String componentVerifyTicket(String msgSignature, String timeStamp, String nonce, String postData) throws AesException {
        //这个类是微信官网提供的解密类,需要用到消息校验Token 消息加密Key和服务平台appid
        WXBizMsgCrypt pc = new WXBizMsgCrypt(weixinConfig.getThirdPartyToken(), weixinConfig.getThirdPartyKey(), weixinConfig.getThirdPartyAppId());
        String xml = pc.decryptMsg(msgSignature, timeStamp, nonce, postData);
        Map<String, String> result = XmlToMapUtils.xmlToMap(xml);// 将xml转为map
        String infoType = MapUtils.getString(result, "InfoType");//消息通知类型
        if (infoType.equals("unauthorized")) {//取消授权
            String authorizerAppid = MapUtils.getString(result, "AuthorizerAppid");//公众号APPID
            wechatLogger.info("取消授权APPID:" + authorizerAppid);
            authorizedAccountUtils.updateAuthor(authorizerAppid);//更新授权状态
        } else if (infoType.equals("authorized")) {//授权成功
            String authorizerAppid = MapUtils.getString(result, "AuthorizerAppid");//公众号APPID
            wechatLogger.info("授权成功APPID:" + authorizerAppid);
            authorizedAccountUtils.insertOrUpdate(authorizerAppid);//更新授权数据
        } else if (infoType.equals("updateauthorized")) {//更新授权
            String authorizerAppid = MapUtils.getString(result, "AuthorizerAppid");//公众号APPID
            wechatLogger.info("更新授权APPID:" + authorizerAppid);
            authorizedAccountUtils.insertOrUpdate(authorizerAppid);//更新授权数据
        } else if (infoType.equals("component_verify_ticket")) {
            String componentVerifyTicket = MapUtils.getString(result, "ComponentVerifyTicket");
            thirdPartyUtils.saveTicketToRedis(componentVerifyTicket);//存储平台授权票据,保存ticket
            wechatLogger.info("componentVerifyTicket缓存成功:" + componentVerifyTicket);
        } else {
            throw new RuntimeException("微信消息推送l类型未知!");
        }
        return "success";
    }

(4)获取第三方平台调用凭证 component_access_token 这个也很重要!!!
令牌的获取是有限制的,令牌的有效期为 2 小时,做好令牌的管理在令牌快过期时(比如1小时50分)重新调用接口获取。

package com.zaiyun.wechat.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.zaiyun.common.config.WeixinConfig;
import com.zaiyun.common.constant.CacheConstants;
import com.zaiyun.common.core.redis.RedisCache;
import com.zaiyun.common.utils.ConvertUtils;
import com.zaiyun.common.utils.http.RestTemplateUtils;
import com.zaiyun.common.utils.spring.SpringUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * 微信开放平台工具类
 */
@Component
public class ThirdPartyUtils {
    @Resource
    WeixinConfig weixinConfig;

    @Resource
    private RestTemplateUtils restTemplateUtils;

    /**
     * 微信第三方令牌缓存KEY
     */
    private static final String TOKEN_REDIS_KEY = CacheConstants.WE_CHAT_KEY + "component_access_token." + WeixinConfig.getThirdPartyAppId();

    /**
     * 微信第三方票据缓存KEY
     */
    private static final String TICKET_REDIS_KEY = CacheConstants.WE_CHAT_KEY + "component_verify_ticket." + WeixinConfig.getThirdPartyAppId();

    /**
     * 存储平台授权票据ticket到缓存
     */
    public String saveTicketToRedis(String ticketValue) {
        SpringUtils.getBean(RedisCache.class).setCacheObject(TICKET_REDIS_KEY, ticketValue, 600, TimeUnit.MINUTES);
        return ticketValue;
    }

    /**
     * 获取component_access_token
     */
    public JSONObject getComponentAccessToken() {
        String url = "https://api.weixin.qq.com/cgi-bin/component/api_component_token";
        HashMap<String, String> paramHeader = new HashMap<>();//请求头参数
        paramHeader.put("Content-Type", "application/json");

        String verifyTicket = SpringUtils.getBean(RedisCache.class).getCacheObject(TICKET_REDIS_KEY);//获取缓存
        HashMap<String, String> paramBody = new HashMap();//请求体
        paramBody.put("component_appid", weixinConfig.getThirdPartyAppId()); //第三方平台 appid
        paramBody.put("component_appsecret", weixinConfig.getThirdPartyAppSecret());//第三方平台 appsecret
        paramBody.put("component_verify_ticket", verifyTicket);//微信后台推送的 ticket
        Object bodyParam = ConvertUtils.mapToObject(paramBody);

        ResponseEntity<String> responseEntity = restTemplateUtils.post(url, paramHeader, bodyParam, String.class);
        if (responseEntity.getStatusCodeValue() == 200) {
            return JSON.parseObject(String.valueOf(responseEntity.getBody()));
        }
        return new JSONObject();
    }

    /**
     * 从缓存中获取component_access_token
     */
    public String getComponentAccessTokenToRides() {
        String componentAccessToken = SpringUtils.getBean(RedisCache.class).getCacheObject(TOKEN_REDIS_KEY);//获取缓存
        if (componentAccessToken != null) {
            return componentAccessToken;
        }
        JSONObject resultObj = getComponentAccessToken();//重新获取component_access_token
        String accessToken = "";
        if (!resultObj.isEmpty()) {
            accessToken = resultObj.getString("component_access_token");
            //令牌的有效期为120分钟,提前30分钟重新生成
            SpringUtils.getBean(RedisCache.class).setCacheObject(TOKEN_REDIS_KEY, accessToken, 90, TimeUnit.MINUTES);
        }
        return accessToken;
    }

    /**
     * 获取预授权码
     */
    public JSONObject getPreAuthCode() {
        String url = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?access_token=" + getComponentAccessTokenToRides();
        HashMap<String, String> paramHeader = new HashMap<>();//请求头参数
        paramHeader.put("Content-Type", "application/json");

        HashMap<String, String> paramBody = new HashMap();//请求体
        paramBody.put("component_appid", weixinConfig.getThirdPartyAppId()); //第三方平台 appid
        Object bodyParam = ConvertUtils.mapToObject(paramBody);

        ResponseEntity<String> responseEntity = restTemplateUtils.post(url, paramHeader, bodyParam, String.class);
        return JSON.parseObject(String.valueOf(responseEntity.getBody()));
    }

    /**
     * 获取刷新令牌
     *
     * @param authorizationCode 微信公众号授权后携带的参数
     */
    public JSONObject getAuthorizerRefreshToken(String authorizationCode) {
        String url = "https://api.weixin.qq.com/cgi-bin/component/api_query_auth?access_token=" + getComponentAccessTokenToRides();
        HashMap<String, String> paramHeader = new HashMap<>();//请求头参数
        paramHeader.put("Content-Type", "application/json");

        HashMap<String, String> paramBody = new HashMap();//请求体
        paramBody.put("component_appid", weixinConfig.getThirdPartyAppId()); //第三方平台 appid
        paramBody.put("authorization_code", authorizationCode); //公众号授权后的授权码
        Object bodyParam = ConvertUtils.mapToObject(paramBody);

        ResponseEntity<String> responseEntity = restTemplateUtils.post(url, paramHeader, bodyParam, String.class);
        return JSON.parseObject(String.valueOf(responseEntity.getBody()));
    }

    /**
     * 获取授权账号调用令牌
     *
     * @param authorizerAppid        授权方公众号APPID
     * @param authorizerRefreshToken 刷新令牌
     */
    public JSONObject getAuthorizerAccessToken(String authorizerAppid, String authorizerRefreshToken) {
        String url = "https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token=" + getComponentAccessTokenToRides();
        HashMap<String, String> paramHeader = new HashMap<>();//请求头参数
        paramHeader.put("Content-Type", "application/json");

        HashMap<String, String> paramBody = new HashMap();//请求体
        paramBody.put("component_appid", weixinConfig.getThirdPartyAppId()); //第三方平台 appid
        paramBody.put("authorizer_appid", authorizerAppid); //授权方公众号APPID
        paramBody.put("authorizer_refresh_token", authorizerRefreshToken); //刷新令牌,获取授权信息时得到
        Object bodyParam = ConvertUtils.mapToObject(paramBody);

        ResponseEntity<String> responseEntity = restTemplateUtils.post(url, paramHeader, bodyParam, String.class);
        if (responseEntity.getStatusCodeValue() == 200) {
            return JSON.parseObject(String.valueOf(responseEntity.getBody()));
        }
        return new JSONObject();
    }

    /**
     * 从缓存获取 authorizer_access_token
     *
     * @param authorizerAppid        授权方公众号APPID
     * @param authorizerRefreshToken 刷新令牌
     */
    public String getAuthorizerAccessTokenToRedis(String authorizerAppid, String authorizerRefreshToken) {
        String authorizerAccessTokenKey = CacheConstants.WE_CHAT_KEY + "authorizer_access_token." + authorizerAppid;//缓存Key
        String authorizerAccessToken = SpringUtils.getBean(RedisCache.class).getCacheObject(authorizerAccessTokenKey);//获取缓存
        if (authorizerAccessToken != null) {
            return authorizerAccessToken;
        }
        JSONObject resultObj = getAuthorizerAccessToken(authorizerAppid, authorizerRefreshToken);//重新获取authorizer_access_token
        String accessToken = "";
        if (resultObj != null) {
            accessToken = resultObj.getString("authorizer_access_token");
            //令牌的有效期为120分钟,提前30分钟重新生成
            SpringUtils.getBean(RedisCache.class).setCacheObject(authorizerAccessTokenKey, accessToken, 90, TimeUnit.MINUTES);
        }
        return accessToken;
    }

    /**
     * 获取授权账号详情
     *
     * @param authorizerAppid 授权的公众号或者小程序的appid
     * @return 结果
     */
    public JSONObject getAuthorizerInfo(String authorizerAppid) {
        String url = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?access_token=" + getComponentAccessTokenToRides();
        HashMap<String, String> paramHeader = new HashMap<>();//请求头参数
        paramHeader.put("Content-Type", "application/json");

        HashMap<String, String> paramBody = new HashMap();//请求体
        paramBody.put("authorizer_appid", authorizerAppid);//授权的公众号或者小程序的appid
        paramBody.put("component_appid", weixinConfig.getThirdPartyAppId());//第三方平台 appid
        Object bodyParam = ConvertUtils.mapToObject(paramBody);

        ResponseEntity<String> responseEntity = restTemplateUtils.post(url, paramHeader, bodyParam, String.class);
        return JSON.parseObject(String.valueOf(responseEntity.getBody()));
    }

}

(5)通过 component_verify_ticket、component_access_token 这两个数据就可以自建 PC授权链接、H5授权链接,用微信扫码授权;

/**
     * 自建PC授权链接
     *
     * @return 结果
     */
    public String builtPcLink() {
        String componentAppid = weixinConfig.getThirdPartyAppId();//第三方平台方 appid
        String preAuthCode = thirdPartyUtils.getPreAuthCode().getString("pre_auth_code");//预授权码
        String redirectUri = "http://keduo.com/index.html#/home";//授权后回调地址

        String link = "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=" + componentAppid
                + "&pre_auth_code=" + preAuthCode + "&redirect_uri=" + redirectUri + "&auth_type=3";
        return link;
    }

    /**
     * 自建H5授权链接
     *
     * @return 结果
     */
    public String builtH5Link() {
        String componentAppid = weixinConfig.getThirdPartyAppId();//第三方平台方 appid
        String preAuthCode = thirdPartyUtils.getPreAuthCode().getString("pre_auth_code");//预授权码
        String redirectUri = "http://keduo.com/index.html#/home";//授权后回调地址

        String link = "https://open.weixin.qq.com/wxaopen/safe/bindcomponent?action=bindcomponent&no_scan=1&component_appid=" + componentAppid
                + "&pre_auth_code=" + preAuthCode + "&redirect_uri=" + redirectUri + "&auth_type=3" + "#wechat_redirect";
        return link;
    }

在这里插入图片描述

扫码授权后,至此公众号授权流程已完成。

四、第三方平台代公众号实现业务,首先要有这几个令牌和票据

在这里插入图片描述

(1)微信授权 (获取微信 昵称、头像、openid)
(2)获取JSSDK (jssdk 一般用于网页 支付、分享、定位等等)
(3)普通公众号的 JS SDK 的使用步骤 这个是前端的活

package com.zaiyun.wechat.controller;

import com.alibaba.fastjson2.JSONObject;
import com.zaiyun.common.annotation.Anonymous;
import com.zaiyun.common.config.WeixinConfig;
import com.zaiyun.common.core.controller.BaseController;
import com.zaiyun.common.core.domain.AjaxResult;
import com.zaiyun.common.core.domain.model.LoginUser;
import com.zaiyun.common.oto.entity.ZyConsumerUser;
import com.zaiyun.framework.web.service.TokenService;
import com.zaiyun.oto.service.ZyConsumerUserService;
import com.zaiyun.wechat.utils.ThirdPartyJsSdkUtils;
import com.zaiyun.wechat.utils.ThirdPartyAchieveUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Map;

/**
 * 第三方平台代公众号实现业务
 */

@Anonymous
@RestController
@RequestMapping("/wechat")
public class ThirdPartyAchieveController extends BaseController {
    @Resource
    WeixinConfig weixinConfig;
    @Autowired
    private TokenService tokenService;
    @Resource
    private ThirdPartyJsSdkUtils thirdPartyJsSdkUtils;
    @Resource
    private ThirdPartyAchieveUtils thirdPartyAchieveUtils;

    @Autowired
    private ZyConsumerUserService consumerUserService;

    private static final Logger wechatLogger = LoggerFactory.getLogger("extend-wechat");

    private String domainName;//系统域名

    /**
     * 用户同意授权,获取code
     *
     * @return 结果
     */
    @GetMapping("/authorize")
    public AjaxResult authorize(HttpServletResponse response, HttpServletRequest request, @RequestParam("token") String token, @RequestParam("url") String url) throws Exception {
        //String domainName = request.getServerName();//客户端请求域名
        LoginUser loginUser = tokenService.getLoginUserByToken(token);
        if (loginUser == null) {
            return AjaxResult.error(201, "token失效");
        }
        long userId = loginUser.getUserId();
        if (url == null) {
            return AjaxResult.error(201, "授权后重定向URL不能为空");
        }
        HttpSession session = request.getSession();
        session.setAttribute("callback", domainName + url);//将重定向地址存入session

        String thirdAppId = weixinConfig.getThirdPartyAppId();//第三方APPID
        String accountAppId = thirdPartyAchieveUtils.replaceAccountAppId(); //公众号APPID
        String uri = URLEncoder.encode(domainName + "/wechat/access/token", "utf-8");
        String redirectUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + accountAppId +
                "&redirect_uri=" + uri + "&response_type=code&scope=snsapi_userinfo&state=" + userId +
                "&component_appid=" + thirdAppId + "#wechat_redirect";
        response.sendRedirect(redirectUrl);
        return success();
    }

    /**
     * 通过code换取网页授权access_token
     */
    @GetMapping("/access/token")
    public void accessToken(HttpServletResponse response, HttpServletRequest request) throws Exception {
        String code = request.getParameter("code");
        JSONObject data = thirdPartyAchieveUtils.getAccessToken(code);
        String openid = data.getString("openid"); //授权用户唯一标识
        String accessToken = data.getString("access_token"); //接口调用凭证
        JSONObject user = thirdPartyAchieveUtils.getUserinfo(accessToken, openid);
        String userId = request.getParameter("state");//当前用户ID
        String nickname = user.getString("nickname");
        String headimgurl = user.getString("headimgurl");

        HttpSession session = request.getSession();
        String callback = session.getAttribute("callback").toString();//从session获取重定向地址

        wechatLogger.info("userId:" + userId);
        wechatLogger.info("callback:" + callback);
        wechatLogger.info("code:" + code);
        wechatLogger.info("openid:" + openid);
        wechatLogger.info("accessToken:" + accessToken);
        wechatLogger.info("通过code换取网页授权access_token:" + data);
        wechatLogger.info("user" + user);

        String nickname2 = new String(nickname.getBytes("ISO-8859-1"), "UTF-8");
        ZyConsumerUser consumerUser = new ZyConsumerUser();
        consumerUser.setUserId(Long.parseLong(userId));
        consumerUser.setWeixinOpenid(openid);
        consumerUser.setWeixinNickname(nickname2);
        consumerUser.setLogo(headimgurl);
        consumerUserService.update(consumerUser);//更新授权微信信息

        response.sendRedirect(callback);//授权后重定向
    }

    /**
     * 开放平台JsSdk
     *
     * @param body url 当前网页的URL,不包含#及其后面部分
     * @return
     */
    @PostMapping("/js/sdk")
    public AjaxResult jseSdk(@RequestBody JSONObject body) {
        try {
            String url = body.getString("url");
            if (url == null || url.isEmpty()) {
                return AjaxResult.error(201, "参数错误url");
            }
            String accountAppId = thirdPartyAchieveUtils.replaceAccountAppId(); //公众号APPID
            String ticket = thirdPartyJsSdkUtils.getJsapiTicketToRides(accountAppId);
            Map<String, Object> res = thirdPartyJsSdkUtils.sign(ticket, URLDecoder.decode(url, "UTF-8"));
            res.put("appId", accountAppId);
            return success(res);
        } catch (Exception e) {
            return AjaxResult.error(201, e.getMessage());
        }
    }
}

第三方平台代公众号实现业务工具类

package com.zaiyun.wechat.utils;

import java.util.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.TimeUnit;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.zaiyun.common.constant.CacheConstants;
import com.zaiyun.common.core.redis.RedisCache;
import com.zaiyun.common.utils.http.RestTemplateUtils;
import com.zaiyun.common.utils.spring.SpringUtils;
import com.zaiyun.common.utils.uuid.UUID;
import com.zaiyun.wechat.mapper.AuthorizedAccountMapper;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import com.zaiyun.wechat.domain.AuthorizedAccount;

import javax.annotation.Resource;

/**
 * 第三方平台代公众号实现业务工具类
 */
@Component
public class ThirdPartyJsSdkUtils {
    @Resource
    private ThirdPartyUtils thirdPartyUtils;
    @Resource
    private RestTemplateUtils restTemplateUtils;
    @Resource
    private ThirdPartyAchieveUtils thirdPartyAchieveUtils;
    @Resource
    AuthorizedAccountMapper authorizedAccountMapper;

    /**
     * JS-SDK jsapi_ticket 缓存KEY
     */
    private static final String JSAPI_TICKET_KEY = CacheConstants.WE_CHAT_KEY + "authorizer_jsapi_ticket.";

    /**
     * 获取jsapi_ticket
     */
    public JSONObject getJsapiTicket() {
        String accountAppId = thirdPartyAchieveUtils.replaceAccountAppId(); //公众号APPID
        AuthorizedAccount info = authorizedAccountMapper.findAuthorizerAppid(accountAppId);
        String authorizerAccessToken = thirdPartyUtils.getAuthorizerAccessTokenToRedis(accountAppId, info.getAuthorizerRefreshToken());//授权账号调用令牌

        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=" + authorizerAccessToken;
        ResponseEntity<String> responseEntity = restTemplateUtils.get(url, String.class);
        JSONObject result = JSON.parseObject(String.valueOf(responseEntity.getBody()));
        if (result.getInteger("errcode") == 0) {
            return JSON.parseObject(String.valueOf(responseEntity.getBody()));
        }
        return new JSONObject();
    }

    /**
     * 从缓存中获取jsapi_ticket
     */
    public String getJsapiTicketToRides(String appid) {
        String jsapiTicket = SpringUtils.getBean(RedisCache.class).getCacheObject(JSAPI_TICKET_KEY + appid);//获取缓存
        if (jsapiTicket != null) {
            return jsapiTicket;
        }
        JSONObject resultObj = getJsapiTicket();//重新获取jsapi_ticket
        String jsTicket = "";
        if (!resultObj.isEmpty()) {
            jsTicket = resultObj.getString("ticket");
            //有效期为120分钟,提前30分钟重新生成
            SpringUtils.getBean(RedisCache.class).setCacheObject(JSAPI_TICKET_KEY + appid, jsTicket, 90, TimeUnit.MINUTES);
        }
        return jsTicket;
    }

    /**
     * 签名
     *
     * @param jsapi_ticket jsapi_ticket
     * @param url          当前网页的URL,不包含#及其后面部分
     * @return 结果
     */
    public static Map<String, Object> sign(String jsapi_ticket, String url) {
        Map<String, Object> ret = new HashMap<String, Object>();
        String nonce_str = create_nonce_str();
        String timestamp = create_timestamp();
        String string1;
        String signature = "";

        //注意这里参数名必须全部小写,且必须有序
        string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str + "&timestamp=" + timestamp + "&url=" + url;
        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        ret.put("url", url);
        ret.put("jsapi_ticket", jsapi_ticket);
        ret.put("nonceStr", nonce_str);
        ret.put("timestamp", timestamp);
        ret.put("signature", signature);

        return ret;
    }

    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    private static String create_nonce_str() {
        return UUID.fastUUID().toString(true);
        //return UUID.randomUUID().toString();
    }

    private static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
}

六、到此已大功告成,祝你好运!!!

  • 22
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java微信公众号现金红包是一种通过在Java码中调用微信支付接口实现的支付功能,用户可以使用现金红包来给其他用户发送一定金额的红包。以下是具体实现步骤: 首先,我们需要在微信公众平台上注册一个公众号,并进行相关设置和认证。然后,通过微信支付开发文档了解相关的API接口和参数,获取到自己的AppID、商户号和商户密钥等信息。 接下来,在Java项目中引入微信支付的SDK,可以使用第三方开源的SDK如weixin-java-pay等,或者通过HTTP请求自行实现。 然后,编写Java码调用微信支付接口实现现金红包的功能。首先需要构建请求参数,包括发送红包的接口URL、请求方式(一般为POST)、AppID、商户号、商户密钥、随机字符串、签名等信息。可以使用Java中的HttpURLConnection类发送HTTP请求,并添加请求头信息和请求体参数。其中,签名的生成需要根据微信支付的签名规则进行加密计算,确保数据的安全性。 最后,接收到微信支付接口返回的结果后,可以对返回的数据进行解析和处理,判断红包发送状态是否成功。根据业务需求,可以将红包发送结果进行持久化存储,以备后续查询和记录使用。 需要注意的是,微信支付的红包功能需要满足一定的条件和规则,例如红包的最低金额、发送频率等,开发者需要仔细阅读微信支付文档,并根据实际需求进行相应的调整。 总的来说,通过Java编写码调用微信支付接口实现现金红包功能需要按照微信支付的接口规范进行开发和调试,确保支付接口的安全性和稳定性,同时可以根据具体业务需求进行功能的扩展和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值