微信V3接口 图片上传API
准备一个V3接口Token生成工具
package com.youjia.datacenter.base.util.pay.wxPay;
import com.youjia.datacenter.util.RandomUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
public class WxV3TokenUtil {
private final static Logger logger = LoggerFactory.getLogger(WxV3TokenUtil.class);
public static String getToken(String method, String url, String body) throws Exception {
String nonceStr = RandomUtil.str_(32);
long timestamp = System.currentTimeMillis() / 1000;
String message = buildMessage(method, url, timestamp, nonceStr, body);
String signature = sign(message.getBytes("UTF-8"));
return "mchid=\"" + WxConfig.INSTANCE.getMchId() + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"" + WxConfig.INSTANCE.getApiCertSerialNumber() + "\","
+ "signature=\"" + signature + "\"";
}
private static String sign(byte[] message) throws Exception {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(getPrivateKey());
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
}
private static String buildMessage(String method, String url, long timestamp, String nonceStr, String body) throws Exception{
return method + "\n"
+ url + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ body + "\n";
}
private static PrivateKey getPrivateKey() throws IOException {
//privateKeyData 是微信支付证书中的 apiclient_key.pem
String content = new String(WxConfig.INSTANCE.getPrivateKeyData(), "UTF-8");
try {
String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
logger.info("privateKey:" + privateKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(
new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA", e);
} catch (InvalidKeySpecException e) {
logger.info("异常:" + e);
throw new RuntimeException("无效的密钥格式");
}
}
}
编写上传工具
package com.youjia.datacenter.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.youjia.datacenter.base.config.SysConfig.MpConstants;
import com.youjia.datacenter.base.util.pay.wxPay.WxConfig;
import com.youjia.datacenter.base.util.pay.wxPay.WxV3TokenUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.FormBodyPart;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.AbstractContentBody;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.StringBody;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class WxMediaUploadUtil {
private final static Logger logger = LoggerFactory.getLogger(WxMediaUploadUtil.class);
/**
* 上传图片文件至微信服务器
* @param fileName
* @Param filePath
* @return 微信mediaId
*/
public static String uploadMediaFile(String fileName,String filePath){
if(StringUtils.isBlank(filePath)){
return null;
}
File file = new File(filePath);
if(!file.exists()){
return null;
}
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
String sha256 = DigestUtils.sha256Hex(fileInputStream);
String url = MpConstants.WX_UPLOAD_FILE_URL;
String signUrl = url.replace("https://api.mch.weixin.qq.com","");
//根属性
JSONObject root = new JSONObject();
//mate
JSONObject meta = new JSONObject();
meta.put("filename",fileName);
meta.put("sha256",sha256);
String json = root.toJSONString();
//获取签名字符串
String sign = WxV3TokenUtil.getToken("POST",signUrl,meta.toJSONString());
Map<String,String> headers = new HashMap<>();
String authorization = "WECHATPAY2-SHA256-RSA2048 "+sign;
headers.put("Authorization",authorization);
headers.put("Content-Type","multipart/form-data");
headers.put("Accept", "application/json");
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create().addBinaryBody("file",file).addPart("meta",new StringBody(meta.toJSONString(),ContentType.APPLICATION_JSON)).setContentType(ContentType.MULTIPART_FORM_DATA);
String res = HttpUtils.httpsPostFile(url,multipartEntityBuilder,headers);
logger.info(">>>>>提交微信图片 res={"+res+"}");
JSONObject result = JSON.parseObject(res);
if(result.containsKey("media_id")){
return result.getString("media_id");
}
logger.error(">>>>>上传文件到微信未成功,res={"+res+"}");
return null;
} catch (Exception e) {
logger.error(">>>>>上传图片到微信出现错误",e);
}finally {
try {
fileInputStream.close();
} catch (IOException e) {
logger.error(">>>>>>");
}
}
return null;
}
}
代码中使用的HttpUtils
此工具类在此博客 HttpUtils
将此方法添加至HttpUtils中
public static String httpsPostFile(String url, MultipartEntityBuilder multipartEntityBuilder,Map<String,String> headers) throws Exception {
CloseableHttpClient hp = createSSLClientDefault();
HttpPost httpPost = new HttpPost(url);
Iterator<Map.Entry<String, String>> iterator = headers.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
httpPost.setHeader(entry.getKey(), entry.getValue());
}
//httpPost.setHeader("Content-Type","application/json");
multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
HttpEntity httpEntity = multipartEntityBuilder.build();
httpPost.setEntity(httpEntity);
CloseableHttpResponse response = hp.execute(httpPost);
HttpEntity entity = response.getEntity();
String content = EntityUtils.toString(entity, "UTF-8");
hp.close();
return content;
}
测试
打印出微信返回的media_id