微信的文档写的是真的烂,特别是刚写完支付宝和苹果支付,有了对比就显得微信的文档是真的垃圾,想体验的可以去看下:
微信官方文档
为了下次做微信支付的时候能舒服点,记录下

主要坑点

  1. 统一下单接口调用的时候记得将编码格式转为iso8859-1,否则中文会乱码,微信官方文档里面的demo没有转换也没有提到这点
  2. 统一下单后还需要对参数进行加密签名,v3理论上应该要有支持加密的api但是我在文档里面没有找到,自己网上找代码实现的
  3. v3版本的回调返回不是xml格式的了,而是终于改成了json格式的数据放回
  4. 回调的数据不是直接给你的,需要对数据进行解密

主要代码

<dependency><groupId>com.github.wechatpay-apiv3</groupId><artifactId>wechatpay-apache-httpclient</artifactId><version>0.2.2</version>
</dependency>

import org.apache.http.HttpRequest;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Logger;@RestController
@RequestMapping("")
public class PayController {@Resourceprivate WxpayUtil wxpayUtil;@PostMapping("/wxpay/getOrder")public DataResult wxpayGetOrder(Integer orderType,Integer orderId,Integer orderNum) throws Exception {return wxpayUtil.getOrder(orderType,orderId,orderNum);}@PostMapping("/wxpay/callback")public String wxPayCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {String resXml = "";try {InputStream inputStream = request.getInputStream();//将InputStream转换成xmlStringBufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));StringBuilder sb = new StringBuilder();String line = null;try {while ((line = reader.readLine()) != null) {sb.append(line + "\n");}} catch (IOException e) {e.printStackTrace();} finally {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}resXml = sb.toString();String result =  wxpayUtil.callback(resXml,response);return result;} catch (Exception e) {System.out.println("微信手机支付失败:" + e.getMessage());e.printStackTrace();String result = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";return result;}}
}
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;public class WxAPIV3AesUtil {static final int KEY_LENGTH_BYTE = 32;static final int TAG_LENGTH_BIT = 128;private final byte[] aesKey;public WxAPIV3AesUtil(byte[] key) {if (key.length != KEY_LENGTH_BYTE) {throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");}this.aesKey = key;}public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext)throws GeneralSecurityException, IOException {try {Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");SecretKeySpec key = new SecretKeySpec(aesKey, "AES");GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);cipher.init(Cipher.DECRYPT_MODE, key, spec);cipher.updateAAD(associatedData);return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {throw new IllegalStateException(e);} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {throw new IllegalArgumentException(e);}}
}
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;import com.youyi.heidong.util.ResultUtil;
import com.youyi.heidong.util.StringUtils;
import com.youyi.heidong.web.mapper.*;
import com.youyi.heidong.web.pojo.response.DataResult;
import com.youyi.heidong.web.service.MoneyDictionariesService;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.security.*;
import java.util.*;@Service
public class WxpayUtil {String privateKey = "微信私钥";String mchId = "商户号";//String mchSerialNo = "商户证书序列号";// V3密钥String apiV3Key = "apiv3密钥";String appid = "appid";// 回调地址String NOTIFY_URL = "回调地址";String app_secret = "appSecret";/*** 获取订单号*/public DataResult getOrder(Integer orderType, Integer orderId, Integer orderNum) throws Exception {// 加载商户私钥(privateKey:私钥字符串)PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));// 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),apiV3Key.getBytes("utf-8"));// 初始化httpClientHttpClient httpClient = WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, merchantPrivateKey).withValidator(new WechatPay2Validator(verifier)).build();//请求URLHttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/app");// 请求body参数String reqdata = "{"+ "\"amount\": {"+ "\"total\":1,"+ "\"currency\":\"CNY\""+ "},"+ "\"mchid\":\""+mchId+"\","+ "\"description\":\"7878787878会员充值\","+ "\"notify_url\":\""+NOTIFY_URL+"\","+ "\"out_trade_no\":\""+new Date().getTime()+"\","+ "\"appid\":\""+appid+"\","+ "\"attach\":\"自定义数据说明\""+ "}";StringEntity entity = new StringEntity(new String(reqdata.getBytes("utf-8"), "iso8859-1"));entity.setContentType("application/json");httpPost.setEntity(entity);httpPost.setHeader("Accept", "application/json");//完成签名并执行请求CloseableHttpResponse response = (CloseableHttpResponse) httpClient.execute(httpPost);try {int statusCode = response.getStatusLine().getStatusCode();if (statusCode == 200) { //处理成功Map<String, String> param = new LinkedHashMap<>();param.put("appid", appid);param.put("partnerid",mchId);String prepay_id = EntityUtils.toString(response.getEntity());ObjectMapper objectMapper = new ObjectMapper();param.put("prepayid",objectMapper.readValue(prepay_id,Map.class).get("prepay_id").toString());param.put("package","Sign=WXPay");param.put("noncestr", StringUtils.randomString(32));param.put("timestamp",System.currentTimeMillis()/1000+"");param.put("sign",createSign(param));return ResultUtil.success(param);//return ResultUtil.success(EntityUtils.toString(response.getEntity()));} else if (statusCode == 204) { //处理成功,无返回BodySystem.out.println("success");return ResultUtil.success();} else {String flag = EntityUtils.toString(response.getEntity());System.out.println("failed,resp code = " + statusCode+ ",return body = " + flag);return ResultUtil.fail("failed,resp code = " + statusCode+ ",return body = " + flag);//throw new IOException("request failed");}} finally {response.close();}}/*** 微信支付签名算法sign* @param parameters* @return*/public String createSign(Map<String,String> parameters){StringBuffer sb = new StringBuffer();Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)Iterator it = es.iterator();while(it.hasNext()) {Map.Entry entry = (Map.Entry)it.next();String k = (String)entry.getKey();Object v = entry.getValue();if(null != v && !"".equals(v)&& !"sign".equals(k) && !"key".equals(k)) {sb.append(k + "=" + v + "&");}}sb.append("key=" + apiV3Key);System.out.println("签名字符串:"+sb.toString());
//        System.out.println("签名MD5未变大写:" + MD5Util.MD5Encode(sb.toString(), characterEncoding));String sign = md5Password(sb.toString()).toUpperCase();return sign;}/*** 生成32位md5码** @param key* @return*/public static String md5Password(String key) {char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};try {byte[] btInput = key.getBytes();// 获得MD5摘要算法的 MessageDigest 对象MessageDigest mdInst = MessageDigest.getInstance("MD5");// 使用指定的字节更新摘要mdInst.update(btInput);// 获得密文byte[] md = mdInst.digest();// 把密文转换成十六进制的字符串形式int j = md.length;char str[] = new char[j * 2];int k = 0;for (int i = 0; i < j; i++) {byte byte0 = md[i];str[k++] = hexDigits[byte0 >>> 4 & 0xf];str[k++] = hexDigits[byte0 & 0xf];}return new String(str);} catch (Exception e) {return null;}}public String callback(String param, HttpServletResponse response) throws IOException, GeneralSecurityException {System.out.println(param);// 新版本微信回调进行了修改使用json格式回调数据Map<String, Object> paramMap = new HashMap<String, Object>();ObjectMapper mapper = new ObjectMapper();paramMap = mapper.readValue(param,Map.class);// 判断是否为支付成功回调if("TRANSACTION.SUCCESS".equals(paramMap.get("event_type"))){Map<String,String> resourceMap = (Map)paramMap.get("resource");// 使用商户私钥解密byte[] key = apiV3Key.getBytes("UTF-8");WxAPIV3AesUtil aesUtil = new WxAPIV3AesUtil(key);String decryptToString = aesUtil.decryptToString(resourceMap.get("associated_data").getBytes("UTF-8"),resourceMap.get("nonce").getBytes("UTF-8"),resourceMap.get("ciphertext"));System.out.println(decryptToString);// 获取回调数据进行校验比对Map map = mapper.readValue(decryptToString, Map.class);if(mchId.equals(map.get("mchid"))&&appid.equals(map.get("appid"))&&"SUCCESS".equals(map.get("trade_state"))){// todo 基础信息校验通过开始处理业务逻辑String out_trade_no = map.get("out_trade_no").toString();}}// 回应微信调用return "{ \"code\": \"SUCCESS\",    \"message\": \"成功\"\n }";}}

java微信app支付服务端v3代码相关推荐

  1. 微信app支付服务端开发记录

    微信APP支付服务端 调用接口需要注意事项: 1.签名:需要全部参数参加签名,空值去掉.(实际传递了什么参数需要,就根据实际参数进行签名) 2.签名参数:appid是申请支付功能的app对于的ID,k ...

  2. 微信APP支付服务端PHP完整代码

    <?php//微信APP支付 一定要先仔细阅读微信的官方文档,统一下单接口 // 调取微信APP支付必须先开通商户后台的微信APP支付 // 注意:开通微信APP支付会发邮件到你们邮箱,下面的商 ...

  3. 微信app服务端php,微信APP支付服务端PHP完整代码

    //微信APP支付 一定要先仔细阅读微信的官方文档,统一下单接口 // 调取微信APP支付必须先开通商户后台的微信APP支付 // 注意:开通微信APP支付会发邮件到你们邮箱,下面的商户号和appid ...

  4. 微信APP支付服务端和Android 端详解及其demo

    最近在开发APP微信支付和支付宝支付,Android 端和后端都是我自己开发的,发现两家公司的文档都不是很友好,特别是微信,接触过或者开发过的人都应该有所体会.因此我特意把开发的过程梳理了,做下记录, ...

  5. 微信APP支付服务端demo

    1.创建应用(获取appid) 要开发APP微信支付,需要在微信开放平台(http://open.weixin.qq.com)上创建应用以获得应用id.微信有几个平台,一定要搞清楚,否则开发过程会觉得 ...

  6. java支付宝和微信app支付(服务端处理)

    最近在接入支付宝和微信的app支付 , 之前因为大部分做的都是网页版的支付,没接触过app,这次把遇到的坑都记录下来. 首先 支付宝支付 https://openhome.alipay.com/pla ...

  7. php微信生成签名_微信APP支付服务端PHP生成签名

    官网支付说明 商户系统和微信支付系统主要交互说明: 步骤1:用户在商户APP中选择商品,提交订单,选择微信支付. 步骤2:商户后台收到用户支付单,调用微信支付统一下单接口.参见[统一下单API]. 步 ...

  8. 解决微信App支付服务端,App上提示“商户支付下单id非法”

    折腾了半天,请大家一定要注意 统一下单接口,返回的字段名是"prepay_id" 调起支付接口,传入的字段名是"prepayid" 坑爹的微信支付!! 同时呼吁 ...

  9. java app支付_Java 微信支付之APP支付服务端 (一)

    Java 微信支付之APP支付服务端 (一) 如图所示,这是服务端要集成的所有微信接口.至于在开放平台申请就不做赘述了.主要流程,1.下单,2.异步通知,3.查询. 一.微信统一下单请求交易 /** ...

最新文章

  1. Android开发之异步任务加载网络图片并存储在sdcard中(源代码分享)
  2. ajax的学多久,ajax第二天学习
  3. WCF入门(五)---创建WCF服务
  4. 解决:安装Widget插件提醒已安装却不见界面
  5. python卸载_手把手教Python环境安装
  6. 《网页设计心理学》一1.6 你最近是否有过灵光一现?
  7. 数组累加兼eval性能测试
  8. POJ-1004-Financial Management
  9. php 判断 小米 手机浏览器,javascript - uc、qq、搜狗 以上三个手机浏览器判断移动端的js代码不执行...
  10. OpenSSL之自签名证书认证
  11. 小程序上传图片前将图片剪切成固定尺寸
  12. oracle pdb与cdb区别,浅谈oracle 12C的新特性-CDB和PDB
  13. 华为的人力资源管理揭秘
  14. ListView适配器
  15. iOS之Category和Extention的区别
  16. CMOS图像传感器——深入ISO
  17. Word中跨页表格都显示表头
  18. VC++实现交换网络的QQ号嗅探
  19. 新版飞信取消手机号捆绑 分析称移动意在圈地
  20. c++中将字符串转换为无符号整数函数:std::stoul and std::stoull

热门文章

  1. 2010经典爱情语句收集(转载)
  2. 原生JS实现一个简单的打字小游戏
  3. python面试(python语法篇)
  4. 【数学建模之Python】12.追赶法求解三对角方程组
  5. 雅虎董事会给了微软首席执行官鲍尔默一个响亮的回答
  6. php坏处,电子产品的好处和坏处是什么
  7. 用httpclient开发的在线自动抢订火车票系统(铁老大不给力,哥给力)
  8. Markdown 扩展语法-特殊字符
  9. 已知前序中序输出后序(java)返回值是数组
  10. python写个围棋程序_经典python实战项目blog源码学习