微信公众号一物一码二维码包解码 Java
1. 公众号内找到密钥
申请一物一码成功后,打开公众号,点击右上角通知,找到关于一物一码的消息,里面包含解密用的密钥
微信公众号一物一码地址: https://developers.weixin.qq.com/doc/offiaccount/Unique_Item_Code/Unique_Item_Code_Op_Guide.html
2.下载二维码代码(文章末尾包含所有相关接口)
下载二维码工具
public static HashMap applycodedownload(String ACCESSTOKEN, String application_id, String code_start, String code_end, String key) {
// 拼接请求地址
String requestUrl = "https://api.weixin.qq.com/intp/marketcode/applycodedownload?access_token=ACCESSTOKEN";
requestUrl = requestUrl.replace("ACCESSTOKEN", ACCESSTOKEN);
Map<String, Object> param = new HashMap<>();
if (StringUtils.isNotBlank(application_id)) {
param.put("application_id", application_id);
}
if (StringUtils.isNotBlank(code_start)) {
param.put("code_start", code_start);
}
if (StringUtils.isNotBlank(code_end)) {
param.put("code_end", code_end);
}
String result = HttpClientUtil.sendPost(requestUrl, JSONObject.toJSONString(param));
JSONObject jsonObject = JSONObject.parseObject(result);
// 返回信息,如errcode不为0,则errmsg为错误信息
if (jsonObject.containsKey("errcode") && jsonObject.getString("errcode").equals("0")) {
String buffer = jsonObject.getString("buffer");
//解密时,先进行base64解码,然后使用密钥及AES/CBC/PKCS7Padding进行解密。
//密钥在申请实名接口权限时,会提供到申请方。
String qrDecrypt = WeChatDecryptUtils.qrDecrypt(buffer, key);
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put("buffer", buffer);
objectObjectHashMap.put("newbuffer", qrDecrypt);
return objectObjectHashMap;
} else {
log.error(jsonObject.toJSONString());
return null;
}
}
代码用到的导包
import com.alibaba.fastjson.JSONObject;
代码用到的http发送方法
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
OutputStreamWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setReadTimeout(20000);
conn.setConnectTimeout(20000);
// 获取URLConnection对象对应的输出流
conn.setRequestProperty("Content-type", "application/json");
conn.setRequestProperty("Content-Length", param.replace("\n", ""));
OutputStream outputStream = conn.getOutputStream();
outputStream.write(param.toString().getBytes());
out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
// 发送请求参数
out.write(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
3.编写解密工具类
/**
* description: 初始化密钥
*
* @return void
* @throws Exception
*/
public static void init() throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyGenerator.getInstance(AES).init(128);
}
/**
* description: 生成iv
*
* @param iv
* @return AlgorithmParameters
* @throws Exception
*/
public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
// iv 为一个 16 字节的数组,这里采用和 iOS 端一样的构造方法,数据全为0
// Arrays.fill(iv, (byte) 0x00);
AlgorithmParameters params = AlgorithmParameters.getInstance(AES);
params.init(new IvParameterSpec(iv));
return params;
}
/**
* description: 执行解密操作
*
* @param encryptedData 加密后的字符串
* @param keyBytes 密钥key
* @param iv 便宜向量iv
* @return byte[]
* @throws Exception
*/
public static byte[] decrypt(byte[] encryptedData, byte[] keyBytes, AlgorithmParameters iv) throws Exception {
Key key = new SecretKeySpec(keyBytes, AES);
Cipher cipher = Cipher.getInstance(AES_CBC_PADDING);
// 设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, key, iv);
return cipher.doFinal(encryptedData);
}
/**
* description: 微信一物一码, 二维码解密
*
* @param encrypted
* @return String
* @throws Exception
* https://developers.weixin.qq.com/doc/offiaccount/Unique_Item_Code/Unique_Item_Code_API_Documentation.html#10
*/
public static String qrDecrypt(String encrypted, String key) {
// 实名数据,先进行base64解码
byte[] encryptedData = Base64.decodeBase64(encrypted);
// key 没有进行编码,直接转换即可
byte[] keyBytes = key.getBytes();
// iv使用加解密钥 --- iv 根据密钥生成的
String result = null;
try {
init();
AlgorithmParameters iv = generateIV(keyBytes);
result = new String(decrypt(encryptedData, keyBytes, iv));
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
这段代码是参考其他博客(原文地址找不到了,找到补上!!!),感谢原博主
附录:所有相关一物一码接口工具
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* 微信一物一码
*/
@Slf4j
public class WeChatMarketcodeUtils {
/**
* 2.1接口规则
* <p>
* <p>
* 提交方式:采用POST方法提交。API调用凭证 accesstoken,参照说明:获取access_token。
* <p>
* 数据格式:提交和返回数据JSON格式,数据格式如:
* <p>
* {
* "field1":"data1",
* "field2":"data2",
* "int_field":123
* }
* 字符编码:统一采用UTF-8字符编码。
*
* @param
* @return
*/
public static String getAccessToken(String appid, String secret) {
String access_token = null;
//获取缓存token
access_token = LocalCache.get(appid + "_access_token");
log.info("缓存的access_token= " + access_token);
if (StringUtils.isBlank(access_token)) {
// 拼接请求地址
String requestUrl = "https://api.weixin.qq.com/cgi-bin/token";
String param = "grant_type=client_credential&appid=APPID&secret=APPSECRET";
String replace = param.replace("APPID", appid).replace("APPSECRET", secret);
String result = HttpClientUtil.sendGet(requestUrl, replace);
JSONObject jsonObject = JSONObject.parseObject(result);
Map map = new HashMap<String, String>();
if (!jsonObject.containsKey("errcode")) {
map.put("access_token", jsonObject.getString("access_token"));
map.put("expires_in", jsonObject.getString("expires_in"));
access_token = jsonObject.getString("access_token");
log.info("重新获取的access_token=" + access_token);
//放入缓存
LocalCache.put(appid + "_access_token", jsonObject.getString("access_token"), 7200);
map = JSON.parseObject(JSON.toJSONString(jsonObject), Map.class);
} else {
log.info("响应的错误信息" + result);
return null;
}
}
return access_token;
}
/**
* 2.2申请二维码接口
* <p>
* <p>
* API:https://api.weixin.qq.com/intp/marketcode/applycode?access_token=ACCESSTOKEN
* <p>
* ACCESSTOKEN参见接口规则说明。
* <p>
* 请求参数:
* <p>
* 字段名 中文解释 类型 是否必填 备注
* code_count 申请码的数量 Uint64 Y ≥10000,≤200000000,10000的整数倍
* isv_application_id 外部单号 String128 Y 相同isv_application_id视为同一申请单
* 返回参数:
* <p>
* 字段名 中文解释 类型 是否必填 备注
* errcode 返回状态码 Int32 Y 0
* errmsg 错误提示 String128 N 返回信息,如errcode不为0,则errmsg为错误信息
* application_id 申请单号 Uint64 Y 无
* 入参示例:
* <p>
* {
* "code_count":100000,
* "isv_application_id":"testid124"
* }
* 返回示例:
* <p>
* {
* "errcode":0,
* "errmsg":"ok",
* "application_id":581865877
* }
*
* @param ACCESSTOKEN
* @param code_count 申请码的数量 ≥10000,≤200000000,10000的整数倍
* @param isv_application_id 外部单号 相同isv_application_id视为同一申请单
* @return
*/
public static JSONObject applycode(String ACCESSTOKEN, String code_count, String isv_application_id) {
// 拼接请求地址
String requestUrl = "https://api.weixin.qq.com/intp/marketcode/applycode?access_token=ACCESSTOKEN";
requestUrl = requestUrl.replace("ACCESSTOKEN", ACCESSTOKEN);
Map<String, Object> param = new HashMap<>();
param.put("code_count", code_count);
if (StringUtils.isNotBlank(isv_application_id)) {
param.put("isv_application_id", isv_application_id);
}
String s = JSONObject.toJSONString(param);
String result = HttpClientUtil.sendPost(requestUrl, JSONObject.toJSONString(param));
JSONObject jsonObject = JSONObject.parseObject(result);
// // 返回信息,如errcode不为0,则errmsg为错误信息
// if (jsonObject.containsKey("errcode") && jsonObject.getString("errcode").equals("0")) {
//
// String application_id = jsonObject.getString("application_id");
//
// Map map = JSON.parseObject(JSON.toJSONString(jsonObject), Map.class);
//
// return map;
// } else {
//
// Map map = JSON.parseObject(JSON.toJSONString(jsonObject), Map.class);
// log.error(jsonObject.toJSONString());
// return null;
// // 返回信息,如errcode不为0,则errmsg为错误信息
// }
return jsonObject;
}
/**
* 2.3 查询二维码申请单接口
* <p>
* <p>
* API:https://api.weixin.qq.com/intp/marketcode/applycodequery?access_token=ACCESSTOKEN
* ACCESSTOKEN参见接口规则说明。
* <p>
* 请求参数:
* <p>
* 字段名 中文解释 类型 是否必填 备注
* application_id 申请单号 Uint64 Y 无
* isv_application_id 外部单号 String128 Y 相同isv_application_id视为同一申请单
* 返回参数:
* <p>
* 字段名 中文解释 类型 是否必填 备注
* errcode 返回状态码 Int32 Y 0
* errmsg 错误提示 String128 N 返回信息,如errcode不为0,则errmsg为错误信息
* status 申请单状态 String128 Y INIT PROCESSING FINISH为可下载
* isv_application_id 外部单号 String128 Y 无
* application_id 申请单号 Uint64 Y 无
* create_time 创建时间 Uint32 Y 无
* update_time 更新时间 Uint32 Y 无
* code_start 开始位置 Uint64 Y 包含,如0
* code_end 结束位置 Uint64 Y 包含,如49999,上述0-49999为一个号码段
* 入参示例:
* <p>
* {
* "application_id":"581865877"
* }
* 返回示例:
* <p>
* {
* "errcode": 0,
* "errmsg": "ok",
* "status": "FINISH",
* "code_generate_list": [{
* "code_start": 0,
* "code_end": 49999
* },{
* "code_start": 50000,
* "code_end": 99999
* }]
* }
*
* @param ACCESSTOKEN
* @param application_id 申请单号 Uint64 Y 无
* @param isv_application_id 外部单号 String128 Y 相同isv_application_id视为同一申请单
* @return
*/
public static Map applycodequery(String ACCESSTOKEN, String application_id, String isv_application_id) {
// 拼接请求地址
String requestUrl = "https://api.weixin.qq.com/intp/marketcode/applycodequery?access_token=ACCESSTOKEN";
requestUrl = requestUrl.replace("ACCESSTOKEN", ACCESSTOKEN);
Map<String, Object> param = new HashMap<>();
if (StringUtils.isNotBlank(application_id)) {
param.put("application_id", application_id);
}
if (StringUtils.isNotBlank(isv_application_id)) {
param.put("isv_application_id", isv_application_id);
}
String result = HttpClientUtil.sendPost(requestUrl, JSONObject.toJSONString(param));
JSONObject jsonObject = JSONObject.parseObject(result);
// 返回信息,如errcode不为0,则errmsg为错误信息
if (jsonObject.containsKey("errcode") && jsonObject.getString("errcode").equals("0")) {
//INIT PROCESSING FINISH为可下载
String status = jsonObject.getString("status");
if (StringUtils.isNotBlank(isv_application_id)) {
//外部单号 String128 Y 无
String isv_application_ids = jsonObject.getString("isv_application_id");
//申请单号 Uint64 Y 无
String application_ids = jsonObject.getString("application_id");
//创建时间 Uint32 Y 无
String create_time = jsonObject.getString("create_time");
//更新时间 Uint32 Y 无
String update_time = jsonObject.getString("update_time");
String code_generate_list = String.valueOf(jsonObject.get("code_generate_list"));
JSONArray objects = JSONArray.parseArray(code_generate_list);
for (int i = 0; i < objects.size(); i++) {
JSONObject jsonObject1 = objects.getJSONObject(i);
//开始位置 Uint64 Y 包含,如0
String code_start = jsonObject1.getString("code_start");
//结束位置 Uint64 Y 包含,如49999,上述0-49999为一个号码段
String code_end = jsonObject1.getString("code_end");
}
} else {
String code_generate_list = jsonObject.getString("code_generate_list");
JSONArray objects = JSONArray.parseArray(code_generate_list);
for (Object object : objects) {
JSONObject jsonObject1 = JSONArray.parseObject((String) object);
String code_start = jsonObject1.getString("code_start");
String code_end = jsonObject1.getString("code_end");
}
}
Map map = JSON.parseObject(JSON.toJSONString(jsonObject), Map.class);
return map;
} else {
Map map = JSON.parseObject(JSON.toJSONString(jsonObject), Map.class);
log.error(jsonObject.toJSONString());
return null;
}
}
/**
* 2.4 下载二维码包接口
* <p>
* API:https://api.weixin.qq.com/intp/marketcode/applycodedownload?access_token=ACCESSTOKE
* ACCESSTOKEN参见接口规则说明。
* <p>
* 请求参数:
* <p>
* 字段名 中文解释 类型 是否必填 备注
* application_id 申请单号 Uint64 Y 无
* code_start 开始位置 Uint64 Y 来自查询二维码申请接口
* code_end 结束位置 Uint64 Y 来自查询二维码申请接口
* 返回参数:
* <p>
* 字段名 中文解释 类型 是否必填 备注
* errcode 返回状态码 Int32 Y 0
* errmsg 错误提示 String128 N 返回信息,如errcode不为0,则errmsg为错误信息
* buffer 文件buffer String128 Y 需要先base64 decode,再做解密操作(解密参见3.1)
* 解密后的数据格式为:
* <p>
* a1 b1 c1 d1
* a2 b2 c2 d2
* <p>
* 即以 /n 换行,每行四个元素以 /t 分隔。
* <p>
* a为361字节的01点阵,用于支持生成19*19的微型码,0为白,1为黑,
* <p>
* b为原始码数据,最长9位,
* <p>
* c为该码在此次申请的索引位置,
* <p>
* d为28位字符,用于支持转为普通二维码。可生成码制2,纠错等级Q的二维码。
* <p>
* 入参示例:
* <p>
* 如下表示获取该申请单的0-49999这一段的码。
* <p>
* {
* "application_id":581865877,
* "code_start": 0,
* "code_end": 49999
* }
* 返回示例:
* <p>
* {
* "errcode":0,
* "errmsg":"ok",
* "buffer": "ajfiwejfoiawjfijweofi"
* }
*
* @param application_id 申请单号 Uint64 Y 无
* @param code_start 开始位置 Uint64 Y 来自查询二维码申请接口
* @param code_end 结束位置 Uint64 Y 来自查询二维码申请接口
* @return
*/
public static HashMap applycodedownload(String ACCESSTOKEN, String application_id, String code_start, String code_end, String key) {
// 拼接请求地址
String requestUrl = "https://api.weixin.qq.com/intp/marketcode/applycodedownload?access_token=ACCESSTOKEN";
requestUrl = requestUrl.replace("ACCESSTOKEN", ACCESSTOKEN);
Map<String, Object> param = new HashMap<>();
if (StringUtils.isNotBlank(application_id)) {
param.put("application_id", application_id);
}
if (StringUtils.isNotBlank(code_start)) {
param.put("code_start", code_start);
}
if (StringUtils.isNotBlank(code_end)) {
param.put("code_end", code_end);
}
String result = HttpClientUtil.sendPost(requestUrl, JSONObject.toJSONString(param));
JSONObject jsonObject = JSONObject.parseObject(result);
// 返回信息,如errcode不为0,则errmsg为错误信息
if (jsonObject.containsKey("errcode") && jsonObject.getString("errcode").equals("0")) {
String buffer = jsonObject.getString("buffer");
//解密时,先进行base64解码,然后使用密钥及AES/CBC/PKCS7Padding进行解密。
//密钥在申请实名接口权限时,会提供到申请方。
String qrDecrypt = WeChatDecryptUtils.qrDecrypt(buffer, key);
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put("buffer", buffer);
objectObjectHashMap.put("newbuffer", qrDecrypt);
return objectObjectHashMap;
} else {
log.error(jsonObject.toJSONString());
return null;
}
}
/**
* 2.5 激活二维码接口
*
* @param application_id 申请单号 Uint64 Y 无
* activity_name 活动名称 String128 Y 数据分析活动区分依据,请规范命名
* product_brand 商品品牌 String128 Y 数据分析品牌区分依据,请规范命名
* product_title 商品标题 String128 Y 数据分析商品区分依据,请规范命名
* product_code 商品条码 String128 Y EAN商品条码,请规范填写
* wxa_appid 小程序的appid String128 Y 扫码跳转小程序的appid
* wxa_path 小程序的path String128 Y 扫码跳转小程序的path
* wxa_type 小程序版本 Int32 N 默认为0正式版,开发版为1,体验版为2
* code_start 激活码段的起始位 Uint64 Y 如0(包含该值)
* code_end 激活码段的结束位 Uint64 Y 如9999(包含该值)
* @return access_token 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
* expires_in access_token接口调用凭证超时时间,单位(秒)
* refresh_token 用户刷新access_token
* openid 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
* scope 用户授权的作用域,使用逗号(,)分隔
*/
public static JSONObject codeactive(String ACCESSTOKEN, String application_id, String activity_name, String product_brand,
String product_title, String product_code, String wxa_appid, String wxa_path, Integer wxa_type, String code_start, String code_end) {
// 拼接请求地址
String requestUrl = "https://api.weixin.qq.com/intp/marketcode/codeactive?access_token=ACCESSTOKEN";
requestUrl = requestUrl.replace("ACCESSTOKEN", ACCESSTOKEN);
Map<String, Object> param = new HashMap<>();
if (StringUtils.isNotBlank(application_id)) {
param.put("application_id", application_id);
}
if (StringUtils.isNotBlank(activity_name)) {
param.put("activity_name", activity_name);
}
if (StringUtils.isNotBlank(product_brand)) {
param.put("product_brand", product_brand);
}
if (StringUtils.isNotBlank(product_title)) {
param.put("product_title", product_title);
}
if (StringUtils.isNotBlank(product_code)) {
param.put("product_code", product_code);
}
if (StringUtils.isNotBlank(wxa_appid)) {
param.put("wxa_appid", wxa_appid);
}
if (StringUtils.isNotBlank(wxa_path)) {
param.put("wxa_path", wxa_path);
}
if (!Objects.isNull(wxa_type)) {
param.put("wxa_type", wxa_type);
}
if (StringUtils.isNotBlank(code_start)) {
param.put("code_start", code_start);
}
if (StringUtils.isNotBlank(code_end)) {
param.put("code_end", code_end);
}
String result = HttpClientUtil.sendPost(requestUrl, JSONObject.toJSONString(param));
JSONObject jsonObject = JSONObject.parseObject(result);
// 返回信息,如errcode不为0,则errmsg为错误信息
// if (jsonObject.containsKey("errcode") && jsonObject.getString("errcode").equals("0")) {
//
// String errmsg = jsonObject.getString("errmsg");
// }
// Map map = JSON.parseObject(JSON.toJSONString(jsonObject), Map.class);
return jsonObject;
}
/**
* 2.6 查询二维码激活状态接口
* <p>
* application_id 申请单号 Uint64 Y 无
* code 九位的字符串原始码 String N code与code_index二选一
* code_index 该码在批次中的偏移量 Uint64 N code与code_index二选一
*/
public static Map codeactivequery(String ACCESSTOKEN, String application_id, String code, String code_index) {
// 拼接请求地址
String requestUrl = "https://api.weixin.qq.com/intp/marketcode/codeactivequery?access_token=ACCESSTOKEN";
requestUrl = requestUrl.replace("ACCESSTOKEN", ACCESSTOKEN);
Map<String, Object> param = new HashMap<>();
param.put("application_id", application_id);
param.put("code", code);
param.put("code_index", code_index);
String result = HttpClientUtil.sendPost(requestUrl, JSONObject.toJSONString(param));
JSONObject jsonObject = JSONObject.parseObject(result);
// 返回信息,如errcode不为0,则errmsg为错误信息
if (jsonObject.containsKey("errcode") && jsonObject.getString("errcode").equals("0")) {
/* 返回示例:
{
"errcode": 0,
"errmsg": "ok",
"code_start": 0,
"code_end": 200,
"activity_name": "test_name",
"product_brand": "test_brand",
"product_title": "test_title",
"product_code": "test_code",
"wxa_appid": "test_appid",
"wxa_path": "test_path"
}*/
//活动名称
String activity_name = jsonObject.getString("activity_name");
//商品品牌
String product_brand = jsonObject.getString("product_brand");
//商品标题
String product_title = jsonObject.getString("product_title");
//小程序的appid
String wxa_appid = jsonObject.getString("wxa_appid");
//小程序的path
String wxa_path = jsonObject.getString("wxa_path");
//小程序版本
String wxa_type = jsonObject.getString("wxa_type");
//激活码段的起始位
String code_start = jsonObject.getString("code_start");
//激活码段的结束位
String code_end = jsonObject.getString("code_end");
}
Map map = JSON.parseObject(JSON.toJSONString(jsonObject), Map.class);
return map;
}
/**
* 2.7 code_ticket换code接口
* <p>
* 请求参数:
* openid 用户的openid String Y 无
* code_ticket 跳转时带上的code_ticket参数 String256 Y 无
* <p>
* 返回参数:
* <p>
* 字段名 中文解释 类型 是否必填 备注
* errcode 返回状态码 Int32 Y 0
* errmsg 错误提示 String128 N 返回信息,如errcode不为0,则errmsg为错误信息
* code 原始码 String16 Y 返回原始码数据,并返回对应的激活信息
* application_id 申请单号 Uint64 Y 无
* isv_application_id 外部单号 String128 Y 无
* activity_name 活动名称 String128 Y 无
* product_brand 商品品牌 String128 Y 无
* product_title 商品标题 String128 Y 无
* wxa_appid 小程序的appid String128 Y 无
* wxa_path 小程序的path String128 Y 无
* code_start 激活码段的起始位 Uint64 Y 如0(包含该值)
* code_end 激活码段的结束位 Uint64 Y 如9999(包含该值)
*/
public static JSONObject codeactivequery(String ACCESSTOKEN, String openid, String code_ticket) {
// 拼接请求地址
String requestUrl = "https://api.weixin.qq.com/intp/marketcode/tickettocode?access_token=ACCESSTOKEN";
requestUrl = requestUrl.replace("ACCESSTOKEN", ACCESSTOKEN);
Map<String, Object> param = new HashMap<>();
param.put("openid", openid);
param.put("code_ticket", code_ticket);
String result = HttpClientUtil.sendPost(requestUrl, JSONObject.toJSONString(param));
JSONObject jsonObject = JSONObject.parseObject(result);
/**
* 处理结果如下 复制就行
// 返回信息,如errcode不为0,则errmsg为错误信息
// if (jsonObject.containsKey("errcode") && jsonObject.getString("errcode").equals("0")) {
// /* 返回示例:
// {
// "errcode": 0,
// "errmsg": "ok",
// "code": "8",
// "code_start": 0,
// "code_end": 200,
// "activity_name": "test_name",
// "product_brand": "test_brand",
// "product_title": "test_title",
// "product_code": "test_code",
// "wxa_appid":"wx3sxjifjwojfsffef",
// "wxa_path":"pages/index/index"
// }*/
// //原始码 String16 Y 返回原始码数据,并返回对应的激活信息
// String code = jsonObject.getString("code");
// //申请单号
// String application_id = jsonObject.getString("application_id");
// //外部单号
// String isv_application_id = jsonObject.getString("isv_application_id");
// //活动名称
// String activity_name = jsonObject.getString("activity_name");
// //商品品牌
// String product_brand = jsonObject.getString("product_brand");
// //商品标题
// String product_title = jsonObject.getString("product_title");
// //小程序的appid
// String wxa_appid = jsonObject.getString("wxa_appid");
// //小程序的path
// String wxa_path = jsonObject.getString("wxa_path");
// //激活码段的起始位
// String code_start = jsonObject.getString("code_start");
// //激活码段的结束位
// String code_end = jsonObject.getString("code_end");
// }
// Map map = JSON.parseObject(JSON.toJSONString(jsonObject), Map.class);
return jsonObject;
}
}
上文中用的ACCESSTOKEN 保存工具类
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* create by Nathan on 2020/11/18
*/
/**
* 本地缓存服务
* key = 字符串 | value = 字符串 | expire = 秒(有效时间)
*
* put 添加缓存
* get 读取缓存值
*
* 失效策略:
* 1. 定期删除策略:启动1个线程,每2分钟扫描一次,超时数据移除
* 2. 懒惰淘汰策略:每次访问时校验有效性,如果失效移除
*/
public class LocalCache {
private final static Logger logger = LoggerFactory.getLogger(LocalCache.class);
/**
* 启动开始后延迟5000秒执行时效策略
*/
private static final int INITIAL_DELAY_TIME = 5000;
/**
* 执行时效策略间隔时间
*/
private static final int PERIOD_TIME = 5000;
/**
* 本地缓存map
*/
private static ConcurrentHashMap<String, Cache> store;
/**
* 执行时效策略线程池
*/
private final static ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
/*
* 静态代码块
*
* 初始化缓存map
* 添加时效策略定时线程任务
*/
static {
store = new ConcurrentHashMap<>();
executor.scheduleAtFixedRate(new Task(), INITIAL_DELAY_TIME, PERIOD_TIME, TimeUnit.SECONDS);
}
public static void put(String key, String value) {
put(key, value, 0);
}
/**
* 设置缓存
* @param key 唯一key
* @param value 值
* @param expire 超时时间-单位(s/秒)
*/
public static void put(String key, String value, long expire) {
logger.info("添加缓存,key={}, value={}, expire={}秒", key, value, expire);
if (expire > 0) {
store.put(key, new Cache(value, expire));
} else {
store.put(key, new Cache(value));
}
}
public static String get(String key) {
Cache cache = store.get(key);
if (cache == null) {
return null;
}
if (cache.getExpire() > 0 && cache.getExpire() < System.currentTimeMillis()) {
remove(key);
return null;
}
return store.get(key).getValue();
}
private static void remove(String key) {
Cache cache = store.remove(key);
logger.info("懒惰淘汰策略: 移除超时失效数据, cache={}", cache);
}
private static void removeAll() {
logger.info("定期删除策略: 开始执行, store={}", store);
for (String key : store.keySet()) {
Cache cache = store.get(key);
if (cache.getExpire() > 0 && cache.getExpire() < System.currentTimeMillis()) {
store.remove(key);
logger.info("定期删除策略: 移除超时失效数据, key={}, value={}, time={}", key, cache.getValue(), cache.getExpire());
}
}
}
/**
* 定时移除时效数据任务
*/
private static class Task implements Runnable {
@Override
public void run() {
try {
LocalCache.removeAll();
} catch (Exception e) {
logger.info("定期删除策略异常", e);
}
}
}
/**
* 本地缓存对象
*/
@Data
private static class Cache {
private String value;
private long expire = 0;
Cache(String value, long expire) {
this.value = value;
this.expire = System.currentTimeMillis() + expire * 1000;
}
Cache(String value) {
this.value = value;
}
}
public static void main(String[] args) {
LocalCache.put("a", "10a", 7);
String a = LocalCache.get("a");
System.out.println(a);
}
}
对于下载后的buffer二维码和解密后的二维码,我采用的方式都是保存到数据库,然后再把解密后的二维码以txt格式保存到了oss中,用户下载和查看都是返回oss的路径!
–保存oss 请移步 oss工具
如有不足,请各位留言评论!!!