Files
jsowell-charger-web/jsowell-admin/src/main/java/com/jsowell/service/AgentDevService.java

372 lines
16 KiB
Java
Raw Normal View History

package com.jsowell.service;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.jsowell.common.constant.CacheConstants;
import com.jsowell.common.core.redis.RedisCache;
import com.jsowell.common.util.StringUtils;
import com.jsowell.common.util.http.HttpUtils;
import com.jsowell.common.util.wxplatform.AesException;
import com.jsowell.common.util.wxplatform.WXBizMsgCrypt;
import com.jsowell.common.util.wxplatform.WXXmlToMapUtil;
import com.jsowell.pile.domain.agentDev.AuditItem;
import com.jsowell.pile.domain.agentDev.CategoryInfo;
import com.jsowell.pile.dto.agentDev.CommitCodeDTO;
import com.jsowell.pile.dto.agentDev.GetComponentTokenDTO;
import com.jsowell.pile.dto.agentDev.SubmitAuditDTO;
import com.jsowell.pile.vo.agentDev.AuthInfoVO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
2023-07-29 14:45:41 +08:00
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 代开发小程序Service
*
* @author Lemon
* @Date 2023/7/27 15:58
*/
@Service
public class AgentDevService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private RedisCache redisCache;
/**
* 第三方平台 appid
*/
private static final String PLATFORM_APP_ID = "wxac3b282a58b9a4a8";
/**
* 第三方平台 secret
*/
private static final String PLATFORM_APP_SECRET = "eb8adc2689b4f27be7ae75a4b646dbe6";
/**
* 第三方平台 消息加解密Key
*/
private static final String PLATFORM_AES_KEY = "9TDTYLBLYGG1IOU9VOLXHNIKKJ65NU40S0ITJ0BFQOU";
/**
* 第三方平台 消息校验Token
*/
private static final String PLATFORM_COMPONENT_TOKEN = "XD83ZUJWTVRB4OSN";
/**
* 解析请求
*
* @param timeStamp
* @param nonce
* @param msgSignature
* @param postData
* @return
*/
public String parseRequest(String timeStamp, String nonce, String msgSignature, String postData) {
logger.info("==============================开始授权事件接收URL=================================");
try {
//这个类是微信官网提供的解密类,需要用到消息校验Token 消息加密Key和服务平台appid
WXBizMsgCrypt pc = new WXBizMsgCrypt(PLATFORM_COMPONENT_TOKEN, PLATFORM_AES_KEY, PLATFORM_APP_ID);
String xml = pc.decryptMsg(msgSignature, timeStamp, nonce, postData);
Map<String, String> result = WXXmlToMapUtil.xmlToMap(xml);// 将xml转为map
logger.info("微信第三方平台推送消息解析后 result:{}", result);
// 获取 infoType 确认是哪个事件
String infoType = MapUtils.getString(result, "InfoType");
if (StringUtils.equals("component_verify_ticket", infoType)) {
// 授权票据事件
verifyTicket(result);
} else if (StringUtils.equals("authorized", infoType)
|| StringUtils.equals("updateauthorized", infoType)
|| StringUtils.equals("unauthorized", infoType)) {
// 授权成功通知 authorized、授权更新通知 updateauthorized、 取消授权通知 unauthorized
// 小程序/公众号授权事件
authorizedInform(result);
}
} catch (AesException e) {
e.printStackTrace();
}
logger.info("==============================结束授权事件接收URL=================================");
return "success";
}
/**
* 验证票据事件
*
* @param map 微信第三方平台推送消息解析后的 map
* @return
*/
private String verifyTicket(Map<String, String> map) {
// 获取验证票据
String componentVerifyTicket = MapUtils.getString(map, "ComponentVerifyTicket");
if (StringUtils.isEmpty(componentVerifyTicket)) {
throw new RuntimeException("微信开放平台,第三方平台获取【验证票据】为空");
}
String redisKey = CacheConstants.COMPONENT_VERIFY_TICKET + PLATFORM_APP_ID;
// 查缓存,看是否已经过期
String verifyTicket = redisCache.getCacheObject(redisKey);
if (verifyTicket != null) {
// 先删除旧缓存
redisCache.deleteObject(redisKey);
}
// 存入Redis 过期时间: 官方12小时但十分钟推送一次, 因此可设置 20 分钟过期
redisCache.setCacheObject(redisKey, componentVerifyTicket, 60 * 20, TimeUnit.SECONDS);
verifyTicket = redisCache.getCacheObject(redisKey);
// 存储平台授权票据,保存ticket
// redisTemplate.opsForValue().set("component_verify_ticket", componentVerifyTicket, 60 * 12, TimeUnit.SECONDS);
// String verifyTicket = redisTemplate.opsForValue().get("component_verify_ticket").toString();
logger.info("====================授权票据【ComponentVerifyTicket】" + verifyTicket + "】====================");
return verifyTicket;
}
/**
* 小程序/公众号授权事件
*
* @param map
*/
private void authorizedInform(Map<String, String> map) {
// 获取通知类型
String infoType = MapUtils.getString(map, "InfoType");
// 小程序appid
String authorizerAppid = MapUtils.getString(map, "AuthorizerAppid");
if (StringUtils.equals("unauthorized", infoType)) {
logger.info("微信开放平台,第三方平台,用户:{} 取消授权", authorizerAppid);
return;
}
logger.info("微信开放平台,第三方平台小程序/公众号授权事件 params:{}", map);
// 用户授权码 redisKey
String authCodeRedisKey = CacheConstants.COMPONENT_AUTHORIZATION_CODE + authorizerAppid;
// 用户预授权码 redisKey 过期时间 1800 秒
String preAuthCodeRedisKey = CacheConstants.COMPONENT_PRE_AUTHORIZATION_CODE + authorizerAppid;
// 如果此用户之前有缓存,需把原来的删除
if (StringUtils.isNotBlank(authCodeRedisKey)) {
redisCache.deleteObject(authCodeRedisKey);
}
if (StringUtils.isNotBlank(preAuthCodeRedisKey)) {
redisCache.deleteObject(preAuthCodeRedisKey);
}
// 获取授权码
String authorizationCode = MapUtils.getString(map, "AuthorizationCode");
// 预授权码
String preAuthCode = MapUtils.getString(map, "PreAuthCode");
// 过期时间 (授权码用)
int expiredTime = (Integer) MapUtils.getObject(map, "AuthorizationCodeExpiredTime");
if (StringUtils.isBlank(authorizationCode)
|| StringUtils.isBlank(authorizerAppid)) {
throw new RuntimeException("微信开放平台,第三方平台获取【授权码】为空");
}
redisCache.setCacheObject(authCodeRedisKey, authorizationCode, expiredTime, TimeUnit.SECONDS);
redisCache.setCacheObject(preAuthCodeRedisKey, preAuthCode, 60 * 30, TimeUnit.SECONDS);
logger.info("微信开放平台,第三方平台小程序/公众号授权事件 success");
}
/**
* 获取第三方平台 token
*
* @param dto
* @return
*/
public String getComponentToken(GetComponentTokenDTO dto) {
String verifyTicket = dto.getVerifyTicket();
String redisKey = CacheConstants.COMPONENT_ACCESS_TOKEN + dto.getAppId();
// 先判断缓存中是否有 token
String token = redisCache.getCacheObject(redisKey);
if (StringUtils.isNotBlank(token)) {
// 不为空直接返回
return token;
}
// 为空再去请求获取新令牌
String url = "https://api.weixin.qq.com/cgi-bin/component/api_component_token";
if (StringUtils.isBlank(verifyTicket)) {
// 获取缓存中的票据
verifyTicket = redisCache.getCacheObject(CacheConstants.COMPONENT_VERIFY_TICKET + dto.getAppId());
logger.info("获取第三方平台缓存中票据:{}", verifyTicket);
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("component_appid", dto.getAppId());
jsonObject.put("component_appsecret", dto.getAppSecret());
jsonObject.put("component_verify_ticket", verifyTicket);
String result = HttpUtils.sendPost(url, jsonObject.toString());
JSONObject jsonResult = JSONObject.parseObject(result);
logger.info("获取第三方平台 token 请求结果:{}", JSONObject.toJSONString(jsonResult));
// 获取返回值中的 token
token = jsonResult.getString("component_access_token");
if (token == null) {
throw new RuntimeException("获取第三方平台 token 异常!");
}
logger.info("获取第三方平台 token component_access_token:{}", token);
// 存入redis, 有效期 1小时50分, 官方 2 小时
redisCache.setCacheObject(redisKey, token, 60 * 110, TimeUnit.SECONDS);
return token;
}
/**
* 使用授权码获取授权信息
* 并将授权信息中的 接口调用令牌刷新令牌存入缓存
*
* @param authorizationCode
*/
public AuthInfoVO getAuthInfoByAuthCode(String authorizationCode) {
// 获取 component_access_token
GetComponentTokenDTO dto = GetComponentTokenDTO.builder()
.appId(PLATFORM_APP_ID)
.appSecret(PLATFORM_APP_SECRET)
.verifyTicket(null)
.build();
String componentToken = getComponentToken(dto);
// 使用授权码获取授权信息 url
String url = "https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=" + componentToken;
JSONObject jsonObject = new JSONObject();
jsonObject.put("component_appid", PLATFORM_APP_ID);
jsonObject.put("authorization_code", authorizationCode);
String result = HttpUtils.sendPost(url, JSONObject.toJSONString(jsonObject));
logger.info("获取第三方平台 使用授权码获取授权信息 请求参数:{}, 请求结果:{}", JSONObject.toJSONString(jsonObject), result);
AuthInfoVO authInfoVO = JSONObject.parseObject(result, AuthInfoVO.class);
if (authInfoVO == null) {
throw new RuntimeException("获取第三方平台 使用授权码获取授权信息 error");
}
String authorizerAccessToken = authInfoVO.getAuthorizerAccessToken(); // 接口调用令牌, 默认有效期 7200 秒
String authorizerRefreshToken = authInfoVO.getAuthorizerRefreshToken(); // 刷新令牌 永久保存
String authorizerAppid = authInfoVO.getAuthorizerAppid(); // 授权方 appid
String authAccessTokenKey = CacheConstants.AUTHORIZER_ACCESS_TOKEN + authorizerAppid;
redisCache.setCacheObject(authAccessTokenKey, authorizerAccessToken, authInfoVO.getExpiredTime(), TimeUnit.SECONDS);
String authRefreshTokenKey = CacheConstants.AUTHORIZER_REFRESH_TOKEN + authorizerAppid;
redisCache.setCacheObject(authRefreshTokenKey, authorizerRefreshToken);
return authInfoVO;
}
/**
* 提交代码并生成体验版小程序
*
* @param dto
* @return
*/
public String commitCode(CommitCodeDTO dto) {
String redisKey = CacheConstants.AUTHORIZER_ACCESS_TOKEN + dto.getAuthorizerAppid();
String authAccessToken = redisCache.getCacheObject(redisKey);
if (StringUtils.isBlank(authAccessToken)) {
throw new RuntimeException("微信第三方平台 提交代码 error: authAccessToken为空");
}
// 提交代码 url
String url = "https://api.weixin.qq.com/wxa/commit?access_token=" + authAccessToken;
JSONObject jsonObject = new JSONObject();
jsonObject.put("template_id", dto.getTemplateId());
jsonObject.put("ext_json", dto.getExtJson());
jsonObject.put("user_version", dto.getUserVersion());
jsonObject.put("user_desc", dto.getUserDesc());
String result = HttpUtils.sendPost(url, JSONObject.toJSONString(jsonObject));
logger.info("获取第三方平台 使用授权码获取授权信息 请求参数:{}, 请求结果:{}", JSONObject.toJSONString(jsonObject), result);
// 将返回结果转为json对象
JSONObject resultJson = JSONObject.parseObject(result);
return resultJson.getString("errmsg");
}
/**
* 获取类目列表
*
* @param authorizerAppid 用户appid
* @return
*/
2023-07-29 14:45:41 +08:00
public List<CategoryInfo> getAllCategoryName(String authorizerAppid) {
String redisKey = CacheConstants.AUTHORIZER_ACCESS_TOKEN + authorizerAppid;
String authAccessToken = redisCache.getCacheObject(redisKey);
if (StringUtils.isBlank(authAccessToken)) {
throw new RuntimeException("微信第三方平台 获取类目名称信息 error: authAccessToken为空");
}
String url = "https://api.weixin.qq.com/wxa/get_category?access_token=" + authAccessToken;
String result = HttpUtils.sendGet(url);
logger.info("获取第三方平台 获取类目名称信息 请求结果:{}", result);
// 将返回结果转为json对象
JSONObject resultJson = JSONObject.parseObject(result);
int errCode = (int) resultJson.get("errcode");
if (errCode != 0) {
// 不为 0 则说明有错误
logger.error("获取第三方平台 获取类目名称信息 error:{}", resultJson.getString("errmsg"));
return new ArrayList<>();
}
// 将 jsonArray 转成 List
JSONArray categoryList = resultJson.getJSONArray("category_list");
List<CategoryInfo> categoryInfos = categoryList.toList(CategoryInfo.class);
if (CollectionUtils.isEmpty(categoryInfos)) {
logger.info("获取第三方平台 获取类目名称信息 error");
return new ArrayList<>();
}
return categoryInfos;
2023-07-29 14:45:41 +08:00
}
/**
* 提交代码审核
*
* @param dto
* @return
*/
public String submitAudit(SubmitAuditDTO dto) {
String redisKey = CacheConstants.AUTHORIZER_ACCESS_TOKEN + dto.getAuthorizerAppid();
String authAccessToken = redisCache.getCacheObject(redisKey);
if (StringUtils.isBlank(authAccessToken)) {
throw new RuntimeException("微信第三方平台 提交代码审核 error: authAccessToken为空");
}
List<AuditItem> itemList = dto.getAuditItems();
String url = "https://api.weixin.qq.com/wxa/submit_audit?access_token=" + authAccessToken;
// List --> JsonArray
JSONArray itemArray = JSONArray.parseArray(JSONObject.toJSONString(itemList));
// 发送请求
JSONObject jsonObject = new JSONObject();
jsonObject.put("item_list", itemArray);
String result = HttpUtils.sendPost(url, JSONObject.toJSONString(jsonObject));
logger.info("微信第三方平台 提交代码审核 请求参数:{}, 请求结果:{}", JSONObject.toJSONString(jsonObject), result);
// 将返回结果转为json对象
JSONObject resultJson = JSONObject.parseObject(result);
int errCode = (int) resultJson.get("errcode");
if (errCode != 0) {
String errMsg = resultJson.getString("errmsg");
logger.info("微信第三方平台 提交代码审核 error, {}", errMsg);
return errMsg;
}
// 获取审核编码并返回
long auditId = (long) resultJson.get("auditid");
return String.valueOf(auditId);
}
public static void main(String[] args) {
JSONArray array = new JSONArray();
array.set(0, "1");
array.set(1, "2");
array.set(2, "3");
List<String> list = array.toList(String.class);
System.out.println(list);
}
}