最近做项目用到需要在服务端返回微信签名的。记录一下。
首先贴上使用http发送get、post请求的方法。在后面调微信获取access_token会用到。也可以自己封装。
package com.duolun.school.ddjd.utils.httpClient;
import com.alibaba.fastjson.JSONObject;
import com.duolun.school.ddjd.utils.Sha1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.security.DigestException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @title: HttpUtil
* @Author jishanfeng
* @Date: 2022/3/1 11:23
* @Version 1.0
*/
public class HttpUtil {
/**
* 向指定URL发送GET方法的请求
*
* @param url 发送请求的URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return URL 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
String result = "";
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
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) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(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;
}
public static void main(String[] args) throws DigestException {
// System.out.println(sendGet("https://api.weixin.qq.com/cgi-bin/token","grant_type=client_credential&appid=wxdc9dcffd583062c3&secret=edc9d247e0fb93c1b105339f56d9a8ad"));
String str1 = "{\"access_token\":\"54_4-qizbKbvhYzOdbYIpt1wN9MciGzyL6t-vDfL0w9EbvroAzQDEIxIHlLA9rLuEV7WrOhUTw8Zl7TxpBnw3X6vMZIZHqsrZCcIBsAhh-nkYXzgsOwmVeCzFHrmvY9X6Pkd68VArDd2Y8OgdgsFTLeAAAOCU\",\"expires_in\":7200}";
JSONObject jsonObject1 = JSONObject.parseObject(str1);
System.out.println(jsonObject1.getString("access_token"));
String assessToken = jsonObject1.getString("access_token");
String params = "access_token=" + assessToken + "&type=jsapi";
// System.out.println(sendGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket", params));
String str2 = "{\"errcode\":0,\"errmsg\":\"ok\",\"ticket\":\"LIKLckvwlJT9cWIhEQTwfPG7whEZnybotA8syZzenkfM2TmCFAuIQhsaAFVvNJx8yw1fePxPD5w0cL4LYivZcQ\",\"expires_in\":7200}";
JSONObject jsonObject2 = JSONObject.parseObject(str2);
System.out.println(jsonObject2.getString("ticket"));
String ticket = jsonObject2.getString("ticket");
HashMap map = new HashMap();
map.put("noncestr=", "Wm3WZYTPz0wzccnW");
map.put("jsapi_ticket=", ticket);
map.put("timestamp=", "1414587457");
map.put("url=", "http://mp.weixin.qq.com?params=value");
System.out.println(Sha1.SHA1(map));
}
}
这里会得到所有参数信息。后面就是调用工具类生成签名。如下:
package com.duolun.school.ddjd.utils;
import java.security.DigestException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
/**
* @title: Sha1
* @Author jishanfeng
* @Date: 2022/3/1 9:41
* @Version 1.0
*/
public class Sha1 {
public static void main(String[] args) throws DigestException {
Map m = new HashMap();
m.put("noncestr=", "Wm3WZYTPz0wzccnW");
m.put("jsapi_ticket=", "sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg");
m.put("timestamp=", "1414587457");
m.put("url=", "http://mp.weixin.qq.com?params=value");
System.out.println(SHA1(m));
}
/**
* SHA1 安全加密算法
*
* @param maps 参数key-value map集合
* @return
* @throws DigestException
*/
public static String SHA1(Map<String, Object> maps) throws DigestException {
//获取信息摘要 - 参数字典排序后字符串
String decrypt = getOrderByLexicographic(maps);
try {
//指定sha1算法
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(decrypt.getBytes());
//获取字节数组
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString().toLowerCase();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new DigestException("签名错误!");
}
}
/**
* 获取参数的字典排序
*
* @param maps 参数key-value map集合
* @return String 排序后的字符串
*/
private static String getOrderByLexicographic(Map<String, Object> maps) {
return splitParams(lexicographicOrder(getParamsName(maps)), maps);
}
/**
* 获取参数名称 key
*
* @param maps 参数key-value map集合
* @return
*/
private static List<String> getParamsName(Map<String, Object> maps) {
List<String> paramNames = new ArrayList<String>();
for (Map.Entry<String, Object> entry : maps.entrySet()) {
paramNames.add(entry.getKey());
}
return paramNames;
}
/**
* 参数名称按字典排序
*
* @param paramNames 参数名称List集合
* @return 排序后的参数名称List集合
*/
private static List<String> lexicographicOrder(List<String> paramNames) {
Collections.sort(paramNames);
return paramNames;
}
/**
* 拼接排序好的参数名称和参数值
*
* @param paramNames 排序后的参数名称集合
* @param maps 参数key-value map集合
* @return String 拼接后的字符串
*/
private static String splitParams(List<String> paramNames, Map<String, Object> maps) {
StringBuilder paramStr = new StringBuilder();
for (String paramName : paramNames) {
if (paramStr.length() > 20) {
paramStr.append("&" + paramName);
} else {
paramStr.append(paramName);
}
for (Map.Entry<String, Object> entry : maps.entrySet()) {
if (paramName.equals(entry.getKey())) {
paramStr.append(String.valueOf(entry.getValue()));
}
}
}
return paramStr.toString();
}
}
**
这样就可以返回最后所需得签名了
**
public R<WechatSignatureRsp> getWechatSign(String url) {
try {
if (RedisUtil.hasKey("ACCESS_TOKEN_TICKET_SIGNATURE")) {
WechatSignatureRsp data = RedisUtil.get("ACCESS_TOKEN_TICKET_SIGNATURE");
return R.success(data);
}
String noncestr = create_nonce_str(); // 随机字符串
String timestamp = create_timestamp(); // 随机时间戳
// 获取微信access_token
String accessTokenParams = "grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;
String str1 = HttpUtil.sendGet("https://api.weixin.qq.com/cgi-bin/token", accessTokenParams);
if (StringUtils.isEmpty(str1)) {
return R.fail("生成access_token失败");
}
JSONObject jsonObject1 = JSONObject.parseObject(str1);
String assessToken = jsonObject1.getString("access_token");
log.info(">>>>>>>>>>>>>>>>>" + "access_token:" + assessToken + "<<<<<<<<<<<<<<<<<<<<");
// 根据access_token获取微信ticket
String params = "access_token=" + assessToken + "&type=jsapi";
String str2 = HttpUtil.sendGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket", params);
if (StringUtils.isEmpty(str2)) {
return R.fail("生成ticket失败");
}
JSONObject jsonObject2 = JSONObject.parseObject(str2);
String ticket = jsonObject2.getString("ticket");
log.info(">>>>>>>>>>>>>>>>>" + "ticket:" + ticket + "<<<<<<<<<<<<<<<<<<<<");
HashMap map = new HashMap();
map.put("noncestr=", noncestr);
map.put("jsapi_ticket=", ticket);
map.put("timestamp=", timestamp);
map.put("url=", url);
String signature = Sha1.SHA1(map);
if (StringUtils.isEmpty(signature)) {
return R.fail("生成签名失败");
}
log.info(">>>>>>>>>>>>>>>>>" + "signature:" + signature + "<<<<<<<<<<<<<<<<<<<<");
WechatSignatureRsp data = WechatSignatureRsp.builder().appid(appId).nonceStr(noncestr).signature(signature).timestamp(timestamp).build();
RedisUtil.set("ACCESS_TOKEN_TICKET_SIGNATURE", data, RedisConstant.CacheExpireTime.HOUR2_EXPIRE_TIME);
return R.success(data);
} catch (DigestException e) {
e.printStackTrace();
}
return R.success();
}
这是实际使用的代码。加了redis缓存,避免大量调用获取access_token的接口。