不废话直接上代码。
需要配置商户号、商户秘钥、商户证书
需要使用的pom
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.8</version>
</dependency>
代码
import io.swagger.annotations.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
import java.util.UUID;
/**
* @program: Controller
* @description:
* @author: 云晓得峰
* @create: 2022/9/28 10:46
*/
@Api(description = "上传")
@RestController
@RequestMapping("/api/")
public class Controller {
@ApiOperation(value = "图片上传")
@ApiResponses(value = {
@ApiResponse(code = 0000, message = "请求已完成"),
@ApiResponse(code = 0001, message = "操作失败"),
})
@ApiImplicitParams({
@ApiImplicitParam(value = "(必传)token", name = "token", dataType = "String", required = true, paramType = "header"),
})
@PostMapping(value = "/addimg" , produces = "application/json;charset=UTF-8")
@ResponseBody
public String addimg(@RequestParam("file") MultipartFile file ) throws Exception {
String mediaid=null;
String uuid = UUID.randomUUID().toString().replaceAll("-","");
String filename = file.getOriginalFilename();
String suffix = filename.substring(filename.lastIndexOf(".") + 1);
filename = uuid + "."+suffix ;
if (file!=null) {
if (!"".equals(filename.trim())) {
//商户号
String mch_id="";
//商户key
String appKey="";
Map<String, String> stringStringMap = UploadServiceImpl.wxImageUpload(file, mch_id, appKey);
if(stringStringMap!=null && stringStringMap.get("return_msg").equals("OK")
&& stringStringMap.get("result_code").equals("SUCCESS") && stringStringMap.get("return_code").equals("SUCCESS")){
mediaid = stringStringMap.get("media_id").toString();
}else {
return "";
}
}
}
return mediaid;
}
}
import org.apache.commons.codec.binary.Hex;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* @program: UploadServiceImpl
* @description:
* @author: 云晓得峰
* @create: 2022/9/28 10:49
*/
public class UploadServiceImpl {
private static final Logger logger = LoggerFactory.getLogger(UploadServiceImpl.class);
/**
* 【需要设置】
登录微信商户平台
账户中心-》API安全-》申请API证书-》API证书管理
*/
private final static String wechatKeyFile = "C:/cert/apiclient_cert.p12";
/**
* 上传时调用此方法
* @param file 文件流
* @param mch_id 商户号
* @param appKey 商户key
*/
public static Map<String, String> wxImageUpload(MultipartFile file, String mch_id, String appKey) {
try {
byte [] byteArr=file.getBytes();
InputStream inputStream = new ByteArrayInputStream(byteArr);
String media_hash = md5HashCode(file.getInputStream());
Map paramMap = new HashMap<>();//用来参与计算sign的参数
paramMap.put("mch_id", mch_id);
paramMap.put("media_hash", media_hash);
paramMap.put("sign_type", "HMAC-SHA256");
String sign = sha256Sign(paramMap, appKey);
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();//用来实际请求接口的参数
multipartEntityBuilder.addTextBody("mch_id", mch_id, ContentType.MULTIPART_FORM_DATA);
multipartEntityBuilder.addBinaryBody("media", inputStream, ContentType.create("image/jpg"), file.getOriginalFilename());
multipartEntityBuilder.addTextBody("media_hash", media_hash, ContentType.MULTIPART_FORM_DATA);
multipartEntityBuilder.addTextBody("sign_type", "HMAC-SHA256", ContentType.MULTIPART_FORM_DATA);
multipartEntityBuilder.addTextBody("sign", sign, ContentType.MULTIPART_FORM_DATA);
FileInputStream instream = null;
SSLContext sslcontext = null;
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
instream = new FileInputStream(new File(wechatKeyFile));
keyStore.load(instream, mch_id.toCharArray());// 这里写密码..默认是你的MCHID
sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
} catch (Exception e) {
logger.error("证书加载失败!{}", e);
} finally {
try {
if (instream != null) {
instream.close();
}
} catch (IOException e) {
logger.error("证书加载失败!{}", e);
}
}
@SuppressWarnings("deprecation")
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
try {
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/secapi/mch/uploadmedia");
RequestConfig config = RequestConfig.custom().setConnectTimeout(10000).setConnectionRequestTimeout(10000).setSocketTimeout(10000).build();
httpPost.setConfig(config);
httpPost.addHeader("Content-Type", "multipart/form-data; charset=UTF-8");
httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36");
httpPost.setEntity(multipartEntityBuilder.build());
CloseableHttpResponse response = httpclient.execute(httpPost);
String result = EntityUtils.toString(response.getEntity(), "UTF-8");
Map<String, String> resMap = xmlStrToMap(result);
return resMap;
} catch (Exception e) {
logger.error("请求失败!{}", e);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Xml字符串转换为Map
*
* @return
*/
public static Map<String,String> xmlStrToMap(String strXML) throws IOException, SAXException, ParserConfigurationException {
try {
Map<String, String> data = new HashMap<String, String>();
DocumentBuilder documentBuilder = newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int idx = 0; idx < nodeList.getLength(); ++idx) {
Node node = nodeList.item(idx);
if (node.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.put(element.getNodeName(), element.getTextContent());
}
}
try {
stream.close();
} catch (Exception ex) {
// do nothing
}
return data;
} catch (Exception ex) {
logger.error("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
throw ex;
}
}
public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
documentBuilderFactory.setXIncludeAware(false);
documentBuilderFactory.setExpandEntityReferences(false);
return documentBuilderFactory.newDocumentBuilder();
}
/**
* 对上次文件进行MD5获取其Hash值
*
* @param fis
* @return
*/
public static String md5HashCode(InputStream fis) {
try {
MessageDigest MD5 = MessageDigest.getInstance("MD5");
byte[] buffer = new byte[8192];
int length;
while ((length = fis.read(buffer)) != -1) {
MD5.update(buffer, 0, length);
}
return new String(Hex.encodeHex(MD5.digest()));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取HMAC-SHA256签名
*
* @param paramMap 签名参数(sign不参与签名)
* @param key 签名密钥
* @return HMAC-SHA256签名结果
*/
public final static String sha256Sign(Map paramMap, String key) {
try {
String payParam = getSignTemp(paramMap, key);
logger.info("签名原文:{}", payParam);
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] array = sha256_HMAC.doFinal(payParam.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
String sign = sb.toString().toUpperCase();
logger.info("签名结果:{}", sign);
return sign;
} catch (Exception e) {
return null;
}
}
/**
* 获取签名参数字符串
*
* @param paramMap 签名参数(sign字段不参与签名)
* @param payKey 签名密钥
* @return 待签名字符串
*/
private final static String getSignTemp(Map paramMap, String payKey) {
ArrayList keyList = new ArrayList<>(paramMap.keySet());
Collections.sort(keyList);
StringBuilder signParam = new StringBuilder();
for (Object key : keyList) {
if (!"sign".equals(key) && paramMap.get(key) != null) {
signParam.append(key).append("=").append(paramMap.get(key)).append("&");
}
}
signParam.delete(signParam.length() - 1, signParam.length());
signParam.append("&key=").append(payKey);
return signParam.toString();
}
}