收藏
评论

v3图片上传接口java代码(httpclient和httpmime实现)

之前用HttpURLConnection实现的,现在改成用httpclient和httpmime实现(我用的是4.5.9版本),感觉会简单一点。水平有限,如有错误请指正。

public class uploadFileTest2 {
 
    public static void main(String[] args) {
         
        try {
                   
            //商户号
            String mchid = "";
            //证书序列号
            String serial_no = "";
            //商户私钥(拷贝apiclient_key.pem文件里-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY-----之间的内容
            String rsaPrivateKey = "";
            //微信支付平台公钥
            String rsaPublicKeyFile = "";           
            //时间戳
            String timestamp = Long.toString(System.currentTimeMillis()/1000);
            //随机数
            String nonce_str = "";
             
            //图片文件
            String filePath = "";//文件路径
            File file = new File(filePath);
            String filename = file.getName();//文件名
            String fileSha256 = DigestUtils.sha256Hex(new FileInputStream(file));//文件sha256
              
            //拼签名串
            StringBuffer sb = new StringBuffer();
            sb.append("POST").append("\n");
            sb.append("/v3/merchant/media/upload").append("\n");
            sb.append(timestamp).append("\n");
            sb.append(nonce_str).append("\n");
            sb.append("{\"filename\":\""+filename+"\",\"sha256\":\""+fileSha256+"\"}").append("\n");
            System.out.println("签名原串:"+sb.toString());
             
            //计算签名
            String sign = new String(Base64.encodeBase64(signRSA(sb.toString(),rsaPrivateKey)));
            System.out.println("签名sign值:"+sign);
             
            //拼装http头的Authorization内容
            String authorization ="WECHATPAY2-SHA256-RSA2048 mchid=\""+mchid+"\",nonce_str=\""+nonce_str+"\",signature=\""+sign+"\",timestamp=\""+timestamp+"\",serial_no=\""+serial_no+"\"";
            System.out.println("authorization值:"+authorization);
             
            //接口URL
            String url = "https://api.mch.weixin.qq.com/v3/merchant/media/upload";           
            CloseableHttpClient httpclient = HttpClients.createDefault(); 
            HttpPost httpPost = new HttpPost(url);
             
            //设置头部
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-Type", "multipart/form-data");
            httpPost.addHeader("Authorization", authorization);
             
            //创建MultipartEntityBuilder
            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);
            //设置boundary
            multipartEntityBuilder.setBoundary("");
            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());         
             
            //获取返回内容
            CloseableHttpResponse response = httpclient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();           
            String rescontent = new String(InputStreamTOByte(httpEntity.getContent()));
            System.out.println("返回内容:" + rescontent);
            //获取返回的http header
            Header headers[] = response.getAllHeaders();             
            int i = 0;    
            while (i < headers.length) {     
                System.out.println(headers[i].getName() + ":  " + headers[i].getValue()); 
                i++;       
            
             
            //验证微信支付返回签名
            String Wtimestamp = response.getHeaders("Wechatpay-Timestamp")[0].getValue();
            String Wnonce = response.getHeaders("Wechatpay-Nonce")[0].getValue();
            String Wsign = response.getHeaders("Wechatpay-Signature")[0].getValue();
            //拼装待签名串
            StringBuffer ss = new StringBuffer();
            ss.append(Wtimestamp).append("\n");
            ss.append(Wnonce).append("\n");
            ss.append(rescontent).append("\n");
            //验证签名
            if(verifyRSA(ss.toString(), Base64.decodeBase64(Wsign.getBytes()), rsaPublicKeyFile)) {
                System.out.println("签名验证成功");
            } else {
                System.out.println("签名验证失败");
            }
             
            EntityUtils.consume(httpEntity);
            response.close();
  
        } catch (Exception e) {
            System.out.println("发送POST请求异常!" + e);
            e.printStackTrace();
        }
 
    }
     
    public static byte[] InputStreamTOByte(InputStream in) throws IOException{ 
         
        int BUFFER_SIZE = 4096
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] data = new byte[BUFFER_SIZE]; 
        int count = -1
         
        while((count = in.read(data,0,BUFFER_SIZE)) != -1
            outStream.write(data, 0, count); 
           
        data = null
        byte[] outByte = outStream.toByteArray();
        outStream.close();
         
        return outByte; 
    }
     
    

   public static byte[] signRSA(String data, String priKey) throws Exception {


//签名的类型

        Signature sign = Signature.getInstance("SHA256withRSA");

        //读取商户私钥,该方法传入商户私钥证书的内容即可

        byte[] keyBytes = Base64.decodeBase64(priKey);

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        sign.initSign(privateKey);

        sign.update(data.getBytes("UTF-8"));

        return sign.sign();

     }

    public static boolean verifyRSA(String data, byte[] sign, String pubKey) throws Exception{

if(data == null || sign == null || pubKey == null){

return false;

}


CertificateFactory cf = CertificateFactory.getInstance("X.509");

        FileInputStream in = new FileInputStream(pubKey);

        Certificate c = cf.generateCertificate(in);

        in.close();

        PublicKey publicKey = c.getPublicKey();

        Signature signature = Signature.getInstance("SHA256WithRSA");

        signature.initVerify(publicKey);

        signature.update(data.getBytes("UTF-8"));

        return signature.verify(sign);


}

 
     
}


最后一次编辑于  2019-09-17
收藏

9 个评论

  • 你
    2019-11-13

    博主 用你的方法为什么获取sha256值报这个错呢


    2019-11-13
    赞同 1
    回复 3
    • 循序健进ꦿོ
      循序健进ꦿོ
      2019-11-20
      我也是
      2019-11-20
      回复
    • 循序健进ꦿོ
      循序健进ꦿོ
      2019-11-20
      兄弟,加上这个就可以了~
                   //设置boundary
                  multipartEntityBuilder.setBoundary("boundary");
      2019-11-20
      1
      回复
    • 苏
      2020-02-25
      我第一次也是报了这个错误,因为copy代码的时候忘记加multipartEntityBuilder.setBoundary("内容")了
      2020-02-25
      1
      回复
  • 明天会更好(林美荣13356547709
    明天会更好(林美荣13356547709
    发表于移动端
    2022-05-11
    good I was The way I n Mmrwne Theik
    2022-05-11
    赞同
    回复
  • SMVC
    SMVC
    2021-08-09

    请问下这个公钥怎么获取的?

    2021-08-09
    赞同
    回复
  • 苏
    2020-05-14

    我贴一个使用OKhttp完成V3图片上传的代码片段,理解起来更简单一些。

    2020-05-14
    赞同
    回复 2
    • 苏
      2020-05-14
      其中MediaType MEDIA_TYPE_IMAGE = MediaType.parse("image/jpg")
      2020-05-14
      回复
    • 李刚
      李刚
      2020-05-26
      能贴个代码吗?
      2020-05-26
      回复
  • wu@big 🐶
    wu@big 🐶
    2020-04-23

    证书序列号难道不是 微信商户平台-API安全里面的“当前生效证书号”么?

    2020-04-23
    赞同
    回复
  • wu@big 🐶
    wu@big 🐶
    2020-04-23

    好奇怪……我用这个提交过去后,提示我说:{"code":"SIGN_ERROR","message":"商户未申请过证书。请到商户平台上申请证书授权机构颁发的证书。详情可参考:http://kf.qq.com/faq/180824JvUZ3i180824YvMNJj.html。"}

    但是我证书是有申请下载过的,而且现在正常的订单支付那块也都没啥问题,求解。

    2020-04-23
    赞同
    回复
  • 苏
    2020-02-25

    非常非常感谢!

    2020-02-25
    赞同
    回复
  •     眾口難調
        眾口難調
    2019-09-08

    楼主 jar包能发下吗 httpclient和httpmime实现(我用的是4.5.9版本) 有问题呀


    2019-09-08
    赞同
    回复
  • 百合
    百合
    2019-09-06
    可以聊天
    2019-09-06
    赞同
    回复 1
登录 后发表内容