之前用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); }
} |
博主 用你的方法为什么获取sha256值报这个错呢
//设置boundary
multipartEntityBuilder.setBoundary("boundary");
我贴一个使用OKhttp完成V3图片上传的代码片段,理解起来更简单一些。
证书序列号难道不是 微信商户平台-API安全里面的“当前生效证书号”么?
好奇怪……我用这个提交过去后,提示我说:{"code":"SIGN_ERROR","message":"商户未申请过证书。请到商户平台上申请证书授权机构颁发的证书。详情可参考:http://kf.qq.com/faq/180824JvUZ3i180824YvMNJj.html。"}
但是我证书是有申请下载过的,而且现在正常的订单支付那块也都没啥问题,求解。
非常非常感谢!
楼主 jar包能发下吗 httpclient和httpmime实现(我用的是4.5.9版本) 有问题呀