微信v3图片上传版本2,完整版代码

package com.dsx.wechat;

import com.alibaba.fastjson.JSONObject;
import com.dsx.HttpClientHelper;
import com.dsx.v3.SignatureUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

/**
 * @author : tianwenqing
 * @version : 1.0
 * @date : 2020-08-12 16:56
 * @description :
 **/
@Slf4j
@Service
public class WechatV3Api {


    @Autowired
    private SignatureUtil signatureUtil = new SignatureUtil() ;

    @Value("${wechat.channel.prikey}")
    private String privateKey = "服务商私钥";

    @Value("${wechat.channel.merchantId}")
    private String merchantId="服务上id";

    @Value("${wechat.channel.certificateSerialNumber}")
    private String certificateSerialNumber="商户API证书序列号serial_no";

    @Autowired
    private HttpClientHelper httpClientHelper ;

    public void updateImage(File file){
        try {
            // 换行符
            String LINE_END ="\r\n";
            String PREFIX ="--";
            // 定义数据分隔线
            String BOUNDARY ="boundary";
            String filename = file.getName();//文件名
            FileInputStream fileInputStream = new FileInputStream(file);
            String fileSha256 = DigestUtils.sha256Hex(fileInputStream);//文件sha256值
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("filename",filename);
            jsonObject.put("sha256",fileSha256);
            String url = "https://api.mch.weixin.qq.com/v3/merchant/media/upload";
            log.debug("request url:{}", url);
            HttpPost httpPost = new HttpPost(url);
            StringEntity json = new StringEntity(jsonObject.toString(), Charset.forName("UTF-8"));
            httpPost.setEntity(json);
            String authorization = signatureUtil.getAuthorization(httpPost, privateKey, merchantId, certificateSerialNumber);
            Map headerMap = new HashMap<>();
            headerMap.put("Charsert","UTF-8");
            headerMap.put("Accept","application/json");
            headerMap.put("Content-Type","multipart/form-data; boundary=" + BOUNDARY);
            headerMap.put("Authorization", authorization);
            String result = httpClientHelper.post(url, BOUNDARY, file,filename, fileSha256,headerMap);
            log.info("updateImage result ->{}", JSONObject.toJSONString(result));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        File file = new File("/Users/xxx/Downloads/你好.png");
        WechatV3Api d = new WechatV3Api();
        d.updateImage(file);
    }

}

SignatureUtil.java

package com.dsx.v3;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.URI;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

/**
 * @author : tianwenqing
 * @version : 1.0
 * @date : 2020-05-15 16:44
 * @description :
 **/
@Slf4j
@Component
public class SignatureUtil {

    private static final String SYMBOLS =
            "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final SecureRandom RANDOM = new SecureRandom();

    private static final String SCHEME = "WECHATPAY2-SHA256-RSA2048 ";

    protected String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }


    protected long generateTimestamp() {
        return System.currentTimeMillis() / 1000;
    }




    /**
     * 生成v3请求头信息
     * @param request 请求url
     * @param privateKey 私钥
     * @param merchantId 微信商户号
     * @param certificateSerialNumber 商户API证书序列号serial_no,用于声明所使用的证书
     * @return
     * @throws IOException
     */
    public String getAuthorization(HttpUriRequest request, PrivateKey privateKey, String merchantId, String certificateSerialNumber){
        try {
            String nonceStr = generateNonceStr();
            long timestamp = generateTimestamp();
            String message = buildMessage(nonceStr, timestamp, request);
            log.debug("authorization message=[{}]", message);
            String sign = sign(message.getBytes("utf-8"), privateKey);
            String token = "mchid=\"" + merchantId + "\","
                    + "nonce_str=\"" + nonceStr + "\","
                    + "timestamp=\"" + timestamp + "\","
                    + "serial_no=\"" + certificateSerialNumber + "\","
                    + "signature=\"" + sign + "\"";
            log.debug("authorization token=[{}]", token);
            String authorization = SCHEME + token;
            log.debug("authorization [{}]", authorization);
            return authorization;
        }  catch (Exception e) {
            log.error("Exception",e);
            throw new RuntimeException(e);
        }

    }

    /**
     * 生成v3请求头信息
     * @param request 请求url
     * @param privateKey 私钥
     * @param merchantId 微信商户号
     * @param certificateSerialNumber 商户API证书序列号serial_no,用于声明所使用的证书
     * @return
     * @throws IOException
     */
    public String getAuthorization(HttpUriRequest request, String privateKey, String merchantId, String certificateSerialNumber){
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] decode = com.yunzong.parking.common.utils.rsa.Base64.decode(privateKey);
            PrivateKey key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decode));
            String nonceStr = generateNonceStr();
            long timestamp = generateTimestamp();
            String message = buildMessage(nonceStr, timestamp, request);
            log.debug("authorization message=[{}]", message);
            String sign = sign(message.getBytes("utf-8"), key);
            String token = "mchid=\"" + merchantId + "\","
                    + "nonce_str=\"" + nonceStr + "\","
                    + "timestamp=\"" + timestamp + "\","
                    + "serial_no=\"" + certificateSerialNumber + "\","
                    + "signature=\"" + sign + "\"";
            log.debug("authorization token=[{}]", token);
            String authorization = SCHEME + token;
            log.debug("authorization [{}]", authorization);
            return authorization;
        } catch (NoSuchAlgorithmException e) {
            log.error("NoSuchAlgorithmException",e);
            throw new RuntimeException(e);
        } catch (Exception e) {
            log.error("Exception",e);
            throw new RuntimeException(e);
        }

    }


    /**
     * 生成v3请求头信息
     * @param requestUrl 请求url
     * @param privateKey 私钥
     * @param merchantId 微信商户号
     * @param certificateSerialNumber 商户API证书序列号serial_no,用于声明所使用的证书
     * @param httpMethod  请求方式: GET/POST
     * @return
     * @throws IOException
     */
    public String getAuthorization(String requestUrl, String privateKey, String merchantId, String certificateSerialNumber,String httpMethod){
        HttpUriRequest request =null ;
        try {
            if(httpMethod.equalsIgnoreCase("GET")){
                request = new HttpGet(requestUrl);
            }else if(httpMethod.equalsIgnoreCase("POST")){
                request = new HttpPost(requestUrl);
            }
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] decode = com.yunzong.parking.common.utils.rsa.Base64.decode(privateKey);
            PrivateKey key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decode));
            String nonceStr = generateNonceStr();
            long timestamp = generateTimestamp();
            String message = buildMessage(nonceStr, timestamp, request);
            log.debug("authorization message=[{}]", message);
            String sign = sign(message.getBytes("utf-8"), key);
            String token = "mchid=\"" + merchantId + "\","
                    + "nonce_str=\"" + nonceStr + "\","
                    + "timestamp=\"" + timestamp + "\","
                    + "serial_no=\"" + certificateSerialNumber + "\","
                    + "signature=\"" + sign + "\"";
            log.debug("authorization token=[{}]", token);
            String authorization = SCHEME + token;
            log.debug("authorization [{}]", authorization);
            return authorization;
        } catch (NoSuchAlgorithmException e) {
            log.error("NoSuchAlgorithmException",e);
            throw new RuntimeException(e);
        } catch (Exception e) {
            log.error("Exception",e);
            throw new RuntimeException(e);
        }

    }


    /**
     * SHA256withRSA 签名
     *
     * @param message
     * @param privateKey
     * @return
     */
    private String sign(byte[] message, PrivateKey privateKey) {
        try {
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initSign(privateKey);
            sign.update(message);
            return Base64.getEncoder().encodeToString(sign.sign());
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
        } catch (InvalidKeyException e) {
            throw new RuntimeException("签名计算失败", e);
        } catch (SignatureException e) {
            throw new RuntimeException("无效的私钥", e);
        }


    }


    protected final String buildMessage(String nonce, long timestamp, HttpUriRequest request)
            throws IOException {
        URI uri = request.getURI();
        String canonicalUrl = uri.getRawPath();
        if (uri.getQuery() != null) {
            canonicalUrl += "?" + uri.getRawQuery();
        }

        String body = "";
        // PATCH,POST,PUT
        if (request instanceof HttpEntityEnclosingRequestBase) {
            body = EntityUtils.toString(((HttpEntityEnclosingRequestBase) request).getEntity());
        }

        return request.getRequestLine().getMethod() + "\n"
                + canonicalUrl + "\n"
                + timestamp + "\n"
                + nonce + "\n"
                + body + "\n";
    }


}

HttpClientHelper.java

package com.dsx.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author : tianwenqing
 * @version : 1.0
 * @date : 2020-05-07 21:19
 * @description : httpclient 辅助类
 **/
@Slf4j
@Component
public class HttpClientHelper {

    public static final String ACCEPT_TYPE_JSON = "application/json";
    public static final String ACCEPT_TYPE_HTML = "text/html";
    public static final String ACCEPT_TYPE_XML = "application/xml";
    public static final String ACCEPT_TYPE_X_WWW = "application/x-www-form-urlencoded";
    public static final int DEFAULT_SO_TIMEOUT = 30000;
    public static final int DEFAULT_CONN_TIMEOUT = 6000;
    public static final int DEFAULT_CONN_REQ_TIMEOUT = 5000;
    private static PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
    private RequestConfig requestConfig;

    @PostConstruct
    public void init() {
        this.requestConfig = RequestConfig.custom().setSocketTimeout(DEFAULT_SO_TIMEOUT).setConnectTimeout(DEFAULT_CONN_TIMEOUT).setConnectionRequestTimeout(DEFAULT_CONN_REQ_TIMEOUT).build();
    }

    @PreDestroy
    public void destory() {
        if (cm != null) {
            log.info("关闭HttpClient线程池");
            cm.shutdown();
        }

    }


    public static enum POST_MEDIA_TYPE {
        JSON,
        FORM,
        JSONSTR,
        XML;

        private POST_MEDIA_TYPE() {
        }
    }


    public String post(String url, Map<String, Object> params, POST_MEDIA_TYPE mediaType) {
        String result = null;
        HttpEntity resEntity = null;
        CloseableHttpResponse response = null;
        if (null == mediaType) {
            mediaType = POST_MEDIA_TYPE.JSON;
        }

        List<NameValuePair> list = new ArrayList();
        Iterator iterator = params.entrySet().iterator();

        while (iterator.hasNext()) {
            Map.Entry<String, String> elem = (Map.Entry) iterator.next();
            list.add(new BasicNameValuePair((String) elem.getKey(), (String) elem.getValue()));
        }

        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).setConnectionManagerShared(true).build();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(this.requestConfig);
        if (list.size() > 0) {
            UrlEncodedFormEntity entity = null;
            try {
                entity = new UrlEncodedFormEntity(list, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                log.error(e.getMessage(), e);
            }
            httpPost.setEntity(entity);
        }
        if (POST_MEDIA_TYPE.JSON == mediaType) {
            httpPost.setHeader("Accept", ACCEPT_TYPE_JSON);
            httpPost.setHeader("Content-type", ACCEPT_TYPE_JSON);
        } else if (POST_MEDIA_TYPE.FORM == mediaType) {
            httpPost.setHeader("Content-Type", ACCEPT_TYPE_X_WWW);
        }
        try {
            response = httpClient.execute(httpPost);
            if (response != null) {
                resEntity = response.getEntity();
                if (resEntity != null) {
                    result = EntityUtils.toString(resEntity, "UTF-8");
                }
            }
        } catch (IOException var10) {
            log.error(var10.getMessage(), var10);
        } finally {
            if (resEntity != null) {
                EntityUtils.consumeQuietly(resEntity);
            }

            if (response != null) {
                try {
                    response.close();
                } catch (IOException var20) {
                    log.error("关闭HttpResponse出错,错误信息:" + var20.getMessage(), var20);
                }
            }

//            if (httpClient != null) {
//                try {
//                    httpClient.close();
//                } catch (IOException var19) {
//                    log.error("关闭HttpClient出错,错误信息:" + var19.getMessage(), var19);
//                }
//            }

        }
        return result;
    }


    public String post(String url, String boundary, File file , String filename, String fileSha256, Map<String, String> headers) {
        String result = null;
        HttpEntity resEntity = null;
        CloseableHttpResponse response = null;

        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).setConnectionManagerShared(true).build();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setConfig(this.requestConfig);
        if (headers != null && headers.size() > 0) {
            for (String key : headers.keySet()) {
                httpPost.setHeader(key, headers.get(key));
            }
        }
        //创建MultipartEntityBuilder
        MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);
        //设置boundary
        multipartEntityBuilder.setBoundary(boundary);
        multipartEntityBuilder.setCharset(Charset.forName("UTF-8"));
        //设置meta内容
        multipartEntityBuilder.addTextBody("meta","{\"filename\":\""+filename+"\",\"sha256\":\""+fileSha256+"\"}", ContentType.APPLICATION_JSON);
        //设置图片内容
        multipartEntityBuilder.addBinaryBody("file", file, ContentType.create("image/jpg"), filename);
        //放入内容
        httpPost.setEntity(multipartEntityBuilder.build());
        try {
            response = httpClient.execute(httpPost);
            if (response != null) {
                resEntity = response.getEntity();
                if (resEntity != null) {
                    result = EntityUtils.toString(resEntity, "UTF-8");
                }
            }
        } catch (IOException var10) {
            log.error(var10.getMessage(), var10);
        } finally {
            if (resEntity != null) {
                EntityUtils.consumeQuietly(resEntity);
            }

            if (response != null) {
                try {
                    response.close();
                } catch (IOException var20) {
                    log.error("关闭HttpResponse出错,错误信息:" + var20.getMessage(), var20);
                }
            }
        }
        return result;
    }


    public String get(String url, Map<String, Object> params, POST_MEDIA_TYPE mediaType, Map<String, String> headers) {
        String result = null;
        HttpEntity resEntity = null;
        CloseableHttpResponse response = null;
        if (null == mediaType) {
            mediaType = POST_MEDIA_TYPE.JSON;
        }

        StringBuilder paramSB = new StringBuilder();
        if (params != null) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                paramSB.append("&").append(entry.getKey()).append("=").append(entry.getValue());
            }
        }
        if (paramSB.length() > 0) {
            url = url + "?" + paramSB.substring(1);
        }

        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).setConnectionManagerShared(true).build();
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(this.requestConfig);

        if (POST_MEDIA_TYPE.JSON == mediaType) {
            httpGet.setHeader("Accept", ACCEPT_TYPE_JSON);
            httpGet.setHeader("Content-type", ACCEPT_TYPE_JSON);
        } else if (POST_MEDIA_TYPE.FORM == mediaType) {
            httpGet.setHeader("Content-Type", ACCEPT_TYPE_X_WWW);
        }
        if (headers != null && headers.size() > 0) {
            for (String key : headers.keySet()) {
                httpGet.setHeader(key, headers.get(key));
            }
        }
        try {
            response = httpClient.execute(httpGet);
            if (response != null) {
                resEntity = response.getEntity();
                if (resEntity != null) {
                    result = EntityUtils.toString(resEntity, "UTF-8");
                }
            }
        } catch (IOException var10) {
            log.error(var10.getMessage(), var10);
        } finally {
            if (resEntity != null) {
                EntityUtils.consumeQuietly(resEntity);
            }

            if (response != null) {
                try {
                    response.close();
                } catch (IOException var20) {
                    log.error("关闭HttpResponse出错,错误信息:" + var20.getMessage(), var20);
                }
            }

//            if (httpClient != null) {
//                try {
//                    httpClient.close();
//                } catch (IOException var19) {
//                    log.error("关闭HttpClient出错,错误信息:" + var19.getMessage(), var19);
//                }
//            }

        }
        return result;
    }

}

 

上述代码不算是完成代码,上传图片的流程是完整的,由于公司要求,自定义的包名稍有改动。再微信分类中有两个版本均可以上传成功

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值