Java服务端支付功能模块--(二)微信支付
来源:互联网 发布:淘宝天猫京东关系 编辑:程序博客网 时间:2024/06/05 01:58
上一篇写了关于支付宝支付的相关问题,本篇主要介绍微信支付的模块
微信支付可以大体分为5块:1.网页支付、2.App支付、3.H5外部浏览器支付、4.小程序支付、5.H5微信内部浏览器支付。这篇文章主要讲解 2、3、4、5这4种支付。
整体难度来说:H5微信内部浏览器支付>H5外部浏览器支付>小程序支付>App支付>网页支付。
编程语言为JAVA,采用的框架是SpringBoot+Mybatis.
控制层代码:
1.createPayOrder为三端统一调起的接口 只用appType和code区分出到底是调用哪个方法
2.因为H5外部浏览器支付需要获取用户的Ip地址所以主动去获取了请求的ip地址
3.isPayEarnest只是区分是否定金
@RestController@RequestMapping("/wechatpay")public class WeChatPayController { @Autowired private WeChatPayService weChatPayService; /** * 发起统一下单 * @param appType 0为H5端 1为小程序 2为app * @param billNo Code是微信通过授权后获取的 * @return Result */ @RequestMapping(value = "/createPayOrder", method = RequestMethod.POST) public @ResponseBody Result createAppWeChatPayOrder(HttpServletRequest request, int appType, String billNo, String code, int isPayEarnest) { if (appType == 0) { if (code != null) { return weChatPayService.h5CreateInnerPayOrder(billNo,code,isPayEarnest); } // h5 return weChatPayService.h5CreatePayOrder(billNo, getIpAddr(request), isPayEarnest); } else if (appType == 1) { // 小程序 return weChatPayService.wxAppCreatePayOrder(code, billNo, isPayEarnest); } else { // app return weChatPayService.appCreatePayOrder(appType, billNo, isPayEarnest); } } /** * 获取访问者IP * * 在一般情况下使用Request.getRemoteAddr()即可,但是经过nginx等反向代理软件后,这个方法会失效。 * * 本方法先从Header中获取X-Real-IP,如果不存在再从X-Forwarded-For获得第一个IP(用,分割), * 如果还不存在则调用Request .getRemoteAddr()。 * * @param request * @return */ public static String getIpAddr(HttpServletRequest request) { String ip = request.getHeader("X-Real-IP"); if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) { return ip; } ip = request.getHeader("X-Forwarded-For"); if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) { // 多次反向代理后会有多个IP值,第一个为真实IP。 int index = ip.indexOf(','); if (index != -1) { return ip.substring(0, index); } else { return ip; } } else { return request.getRemoteAddr(); } } /** * 查询订单 * @param appType String * @param wxBillNo String * @param erpBillNo String * @return */ @RequestMapping(value = "/orderquery") public @ResponseBody Result orderQuery(WeChatPayOrderQueryRequest request) { return weChatPayService.orderQuery(request); }}
业务层代码:
```@Servicepublic class WeChatPayServiceImpl implements WeChatPayService { private static Logger LOG = Logger.getLogger(WeChatPayServiceImpl.class); //微信支付配置参数 @Autowired private WeChatPayProperties weChatPayProperties; private String orderDetail = "XXXX业务:"; //支付业务 @Autowired private PayService payService; @Override public Result wxAppCreatePayOrder(String code, String billNo, int isPayEarnest) { // 向微信请求获取openId Map<String, Object> openIdMap = getOpenId(initWxAppOpenIdParmMap(code)); if (openIdMap == null) { return new Result(Constants.FAILURE_CODE, ErrorMsg.GET_WECHATPAY_OPENID); } String openId = (String) openIdMap.get("openid"); if (openId == null) { return new Result(Constants.FAILURE_CODE, ErrorMsg.GET_WECHATPAY_OPENID); } // String session_key = (String) openIdMap.get("session_key"); // 获取订单信息 CarRentOrderPerson dto = payService.findOrder(billNo); //为了能多次吊起支付,调起支付订单号要加上时间戳 String newbillNo = payService.createNewOrderNo(billNo); //保存吊起支付请求记录,方便维护(可有可无) payService.savePayRequest(newbillNo, dto, PayTypeEnums.WXAPP.getIndex(), SourceTypeEnums.WXAPP.getIndex()); // 初始化微信小程序统一下单参数 Map<String, String> params = initWxAppCreatePayBillParams(openId, orderDetail + dto.getModelname(), newbillNo,isPayEarnest == 1 ? dto.getPrepaydeposit().multiply((new BigDecimal(100))): dto.getReceivableamount().multiply((new BigDecimal(100)))); // 向微信平台请求 Result result = sendCreateOrderRequest(params); if (result.getCode() == Constants.FAILURE_CODE) { return result; } String prePayid = (String) result.getData(); // 封装prePayId到返回参数中,直接返回给前端,前端直接拿着这个就可以调起支付 return new Result(Constants.SUCCESS_CODE, "", initWxAppCreatePayBillReturnParams(prePayid)); } @Override public Result appCreatePayOrder(int appType, String billNo, int isPayEarnest) { // 判断app类型 获取相应appId String appId = weChatPayProperties.getAppAppid(); if (!(appType == 3 || appType == 2)) { return new Result(Constants.FAILURE_CODE, ErrorMsg.NO_SUCH_APP_TYPE); } // 获取预订单 CarRentOrderPerson dto = payService.findOrder(billNo); if (dto == null) { return new Result(Constants.FAILURE_CODE, ErrorMsg.BILLNO_CANOT_BE_NULL); } String newbillNo = payService.createNewOrderNo(billNo); //3为安卓 2为ios 记录请求 if (appType == 3) { payService.savePayRequest(newbillNo, dto, PayTypeEnums.WXAPP.getIndex(), SourceTypeEnums.ANDROID.getIndex()); } else { payService.savePayRequest(newbillNo, dto, PayTypeEnums.WXAPP.getIndex(), SourceTypeEnums.IOS.getIndex()); } //创建请求信息 Map<String, String> params = initAppCreateOrderParams(appId, orderDetail + dto.getModelname(), newbillNo, isPayEarnest == 1 ? dto.getPrepaydeposit().multiply((new BigDecimal(100))) : dto.getReceivableamount().multiply(new BigDecimal(100))); // 向微信请求 Result result = sendCreateOrderRequest(params); if (result.getCode() == Constants.FAILURE_CODE) { return result; } String prePayid = (String) result.getData(); return new Result(Constants.SUCCESS_CODE, "", initAppCreateOrderRetunParams(appId, prePayid)); } @Override //H5外部调起支付 public Result h5CreatePayOrder(String billNo, String ip, int isPayEarnest) { String sceenInfo = "{\"h5_info\": \"h5_info\" {\"type\": \"api\", \"wap_url\": \"\",\"wap_name\": \"\"}}"; // 获取预订单 CarRentOrderPerson dto = payService.findOrder(billNo); if (dto == null) { return new Result(Constants.FAILURE_CODE, ErrorMsg.BILLNO_CANOT_BE_NULL); } String newbillNo = payService.createNewOrderNo(billNo); // 保存请求参数 payService.savePayRequest(newbillNo, dto, PayTypeEnums.WXAPP.getIndex(), SourceTypeEnums.H5.getIndex()); Map<String, String> params = initH5CreateOrderParams(sceenInfo, orderDetail + dto.getModelname(), newbillNo, ip, isPayEarnest == 1 ? dto.getPrepaydeposit().multiply((new BigDecimal(100))) : dto.getReceivableamount().multiply(new BigDecimal(100))); Result result = sendRequestToWxApi(params, weChatPayProperties.CREATE_PAY_ORDER_URL); if (result.getCode() == Constants.FAILURE_CODE) { return result; } @SuppressWarnings("unchecked") HashMap<String, String> returnHashMap = (HashMap<String, String>) result.getData(); //prePayid为空请求失败 String prePayid = returnHashMap.get("prepay_id"); if (prePayid == null) { return new Result(Constants.FAILURE_CODE, ErrorMsg.WECHATPAY_WXAPP_CREATE_ORDER_FAIL); } String url = returnHashMap.get("mweb_url"); if (url == null) { return new Result(Constants.FAILURE_CODE, ErrorMsg.WECHATPAY_WXAPP_CREATE_ORDER_FAIL); } return new Result(Constants.SUCCESS_CODE, "", initH5CreatePayBillReturnParams(prePayid, url)); } @Override //H5微信内部浏览器调起 public Result h5CreateInnerPayOrder(String billNo, String code, int isPayEarnest) { // 获取openId Map<String, Object> openIdMap = getH5OpenId(initH5OpenIdParmMap(code)); if (openIdMap == null) { return new Result(Constants.FAILURE_CODE, ErrorMsg.GET_WECHATPAY_OPENID); } String openId = (String) openIdMap.get("openid"); if (openId == null) { return new Result(Constants.FAILURE_CODE, ErrorMsg.GET_WECHATPAY_OPENID); } // 获取预订单 CarRentOrderPerson dto = payService.findOrder(billNo); String newbillNo = payService.createNewOrderNo(billNo); payService.savePayRequest(newbillNo, dto, PayTypeEnums.WXAPP.getIndex(), SourceTypeEnums.H5.getIndex()); // 初始化微信统一下单参数 Map<String, String> params = initWxAppCreatePayBillParams(openId, orderDetail + dto.getModelname(), newbillNo, isPayEarnest == 1 ? dto.getPrepaydeposit().multiply((new BigDecimal(100))) : dto.getReceivableamount().multiply((new BigDecimal(100)))); // 向微信平台请求 Result result = sendCreateOrderRequest(params); if (result.getCode() == Constants.FAILURE_CODE) { return result; } String prePayid = (String) result.getData(); // 封装prePayId到返回参数中 return new Result(Constants.SUCCESS_CODE, "", initH5InnerCreatePayBillReturnParams(prePayid)); } @Override public Result orderQuery(WeChatPayOrderQueryRequest request) { String appid = ""; if (StringUtils.isBlank(request.getErpBillNo()) && StringUtils.isBlank(request.getWxBillNo())) { return new Result(Constants.FAILURE_CODE, ErrorMsg.BILLNO_CANOT_BE_NULL); } if (2 == request.getAppType() || 3 == request.getAppType()) { appid = weChatPayProperties.getAppAppid(); } else if (0 == request.getAppType()) { appid = weChatPayProperties.getH5Appid(); } else if (1 == request.getAppType()) { appid = weChatPayProperties.getWxAppAppid(); } else { return new Result(Constants.FAILURE_CODE, ErrorMsg.NO_SUCH_APP_TYPE); } Map<String, String> params = initOrderQueryParams(appid, request.getWxBillNo(), request.getErpBillNo()); // 向微信请求 Result result = sendRequestToWxApi(params, weChatPayProperties.ORDERQUERY_URL); if (result.getCode() == Constants.FAILURE_CODE) { return result; } @SuppressWarnings("unchecked") HashMap<String, String> returnHashMap = (HashMap<String, String>) result.getData(); return new Result(Constants.SUCCESS_CODE, "", WeChatPayOrderStatus.findNameById(returnHashMap.get("trade_state"))); } private HashMap<String, String> initH5CreatePayBillReturnParams(String prePayid, String url) { HashMap<String, String> signMap = new HashMap<String, String>(); signMap.put("appId", weChatPayProperties.getH5Appid()); signMap.put("nonceStr", RandomUtils.generateString(31)); signMap.put("package", "prepay_id=" + prePayid); signMap.put("signType", "MD5"); signMap.put("timeStamp", new Date().getTime() + ""); signMap.put("mweb_url", url); signMap.put("paySign", createSign(signMap)); return signMap; } private HashMap<String, String> initH5InnerCreatePayBillReturnParams(String prePayid) { HashMap<String, String> signMap = new HashMap<String, String>(); signMap.put("appId", weChatPayProperties.getH5Appid()); signMap.put("nonceStr", RandomUtils.generateString(31)); signMap.put("package", "prepay_id=" + prePayid); signMap.put("signType", "MD5"); signMap.put("timeStamp", new Date().getTime() + ""); signMap.put("paySign", createSign(signMap)); return signMap; } /** * 初始化微信小程序统一下单返回参数 * @param prePayid 预订单编号 * @return */ private HashMap<String, String> initWxAppCreatePayBillReturnParams(String prePayid) { HashMap<String, String> signMap = new HashMap<String, String>(); signMap.put("appId", weChatPayProperties.getWxAppAppid()); signMap.put("nonceStr", RandomUtils.generateString(31)); signMap.put("package", "prepay_id=" + prePayid); signMap.put("signType", "MD5"); signMap.put("timeStamp", new Date().getTime() + ""); signMap.put("paySign", createSign(signMap)); return signMap; } /** * 初始化微信小程序统一下单参数 * @param openId 商户openId * @param body 商品信息 * @param billNo 订单编号 * @param totalFee 总价(单位分) * @return */ private Map<String, String> initWxAppCreatePayBillParams(String openId, String body, String billNo, BigDecimal totalFee) { // 生成微信下单请求参数 HashMap<String, String> params = new HashMap<String, String>(); Instant now = Instant.now(); Date nowDate = Date.from(now); // 支付有限时间为10分钟 now = now.plusSeconds(600); Date endDate = Date.from(now); params.put("appid", weChatPayProperties.getWxAppAppid()); params.put("mch_id", weChatPayProperties.getWxAppMchId()); params.put("notify_url", weChatPayProperties.getNotifyUrl()); params.put("time_start", DateUtils.dateToString(nowDate, "yyyyMMddHHmmss")); params.put("time_expire", DateUtils.dateToString(endDate, "yyyyMMddHHmmss")); params.put("nonce_str", RandomUtils.generateString(31)); params.put("body", body); /* + DateUtils.dateToString(nowDate, "yyyyMMddHHmm") */ params.put("out_trade_no", billNo); params.put("total_fee", String.valueOf(totalFee.intValue())); // params.put("total_fee", String.valueOf(1)); // 测试金额 // params.put("total_fee", String.valueOf(new BigDecimal(100))); params.put("spbill_create_ip", "0.0.0.1"); params.put("trade_type", "JSAPI"); params.put("openid", openId); params.put("sign", createSign(params)); return params; } /** * 向微信后台发送统一下单请求 * * @param 统一下单请求参数 params * @return */ private Result sendCreateOrderRequest(Map<String, String> params) { Result result = sendRequestToWxApi(params, weChatPayProperties.CREATE_PAY_ORDER_URL); if (result.getCode() == Constants.FAILURE_CODE) { return result; } @SuppressWarnings("unchecked") HashMap<String, String> returnHashMap = (HashMap<String, String>) result.getData(); String prePayid = returnHashMap.get("prepay_id"); if (prePayid == null) { return new Result(Constants.FAILURE_CODE, ErrorMsg.WECHATPAY_WXAPP_CREATE_ORDER_FAIL); } return new Result(Constants.SUCCESS_CODE, "", prePayid); } /** * 向微信后台发送请求 * @param 参数 params * @param 地址 url * @return */ private Result sendRequestToWxApi(Map<String, String> params, String url) { String sendMsg = XMLUtils.mapToXml(params); if (sendMsg == null) { return new Result(Constants.FAILURE_CODE, ErrorMsg.WECHATPAY_REQUEST); } String retString = HttpUtils.postXML(url, sendMsg); if (retString == null) { return new Result(Constants.FAILURE_CODE, ErrorMsg.WECHATPAY_REQUEST); } Map<String, String> returnHashMap = XMLUtils.parseMap(retString); if (returnHashMap == null) { return new Result(Constants.FAILURE_CODE, ErrorMsg.WECHATPAY_REQUEST); } if (WeChatPayConstants.RETURN_CODE_FAIL.equals(returnHashMap.get("return_code"))) { return new Result(Constants.FAILURE_CODE, returnHashMap.get("return_msg")); } if (WeChatPayConstants.RETURN_CODE_FAIL.equals(returnHashMap.get("result_code"))) { return new Result(Constants.FAILURE_CODE, returnHashMap.get("err_code_des")); } return new Result(Constants.SUCCESS_CODE, "", returnHashMap); } /** * 初始化App统一下单请求参数 * @return */ private Map<String, String> initAppCreateOrderParams(String appid, String body, String billNo, BigDecimal totolFee) { HashMap<String, String> params = new HashMap<String, String>(); Instant now = Instant.now(); Date nowDate = Date.from(now); now = now.plusSeconds(600); Date endDate = Date.from(now); params.put("appid", appid); params.put("mch_id", weChatPayProperties.getMchId()); params.put("notify_url", weChatPayProperties.getNotifyUrl()); params.put("time_start", DateUtils.dateToString(nowDate, "yyyyMMddHHmmss")); params.put("time_expire", DateUtils.dateToString(endDate, "yyyyMMddHHmmss")); params.put("nonce_str", RandomUtils.generateString(31)); params.put("body", body); params.put("out_trade_no", billNo); params.put("total_fee", String.valueOf(totolFee.intValue())); params.put("spbill_create_ip", "117.28.154.84"); params.put("trade_type", "APP"); params.put("sign", createSign(params)); return params; } /** * 初始化App统一下单请求参数 * @return */ private Map<String, String> initH5CreateOrderParams(String sceneInfo, String body, String billNo, String ip, BigDecimal totolFee) { HashMap<String, String> params = new HashMap<String, String>(); Instant now = Instant.now(); Date nowDate = Date.from(now); now = now.plusSeconds(600); Date endDate = Date.from(now); params.put("appid", weChatPayProperties.getH5Appid()); params.put("mch_id", weChatPayProperties.getMchId()); params.put("notify_url", weChatPayProperties.getNotifyUrl()); params.put("time_start", DateUtils.dateToString(nowDate, "yyyyMMddHHmmss")); params.put("time_expire", DateUtils.dateToString(endDate, "yyyyMMddHHmmss")); params.put("nonce_str", RandomUtils.generateString(31)); params.put("body", body); params.put("out_trade_no", billNo); params.put("total_fee", String.valueOf(totolFee.intValue())); params.put("spbill_create_ip", ip); params.put("trade_type", "MWEB"); params.put("scene_info", sceneInfo); params.put("sign", createSign(params)); return params; } /** * 初始化App统一下单请求参数 * @return */ private Map<String, String> initAppCreateOrderRetunParams(String appId, String prepayid) { HashMap<String, String> signMap = new HashMap<String, String>(); signMap.put("appid", appId); signMap.put("partnerid", weChatPayProperties.getMchId()); signMap.put("prepayid", prepayid); signMap.put("package", "Sign=WXPay"); signMap.put("noncestr", RandomUtils.generateString(31)); String timestamp = String.valueOf(new Date().getTime()); signMap.put("timestamp", timestamp.substring(0, timestamp.length() - 3)); signMap.put("sign", createSign(signMap)); return signMap; } public Map<String, String> initWxAppOpenIdParmMap(String code) { HashMap<String, String> params = new HashMap<String, String>(); params.put("appid", weChatPayProperties.getWxAppAppid()); params.put("secret", weChatPayProperties.getWxAppAppsecret()); params.put("js_code", code); params.put("grant_type", "authorization_code"); return params; } public Map<String, String> initH5OpenIdParmMap(String code) { HashMap<String, String> params = new HashMap<String, String>(); params.put("appid", weChatPayProperties.getH5Appid()); params.put("secret", weChatPayProperties.getH5Appsecret()); params.put("code", code); params.put("grant_type", "authorization_code"); return params; } /** * 获取openID * @param params * @return */ public Map<String, Object> getOpenId(Map<String, String> params) { Map<String, Object> map = null; String retStr = HttpUtils.sendPost(weChatPayProperties.GET_OPEN_ID_URL, params); if (retStr == null) { return null; } map = stringToHashMap(retStr); if (map == null || map.get("openid") == null || map.get("session_key") == null) { return null; } return map; } /** * 获取H5openID * @param params * @return */ public Map<String, Object> getH5OpenId(Map<String, String> params) { Map<String, Object> map = null; String retStr = HttpUtils.sendPost(weChatPayProperties.GET_H5_OPEN_ID_URL, params); if (retStr == null) { return null; } map = stringToHashMap(retStr); if (map == null || map.get("openid") == null) { return null; } return map; } private boolean checkSign(Map<String, String> map) { String signFromAPIResponse = map.get("sign").toString(); if (signFromAPIResponse == "" || signFromAPIResponse == null) { return false; } // 清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名 map.remove("sign"); // 将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较 String signForAPIResponse = createSign(map); if (!signForAPIResponse.equals(signFromAPIResponse)) { return false; } return true; } @SuppressWarnings("unchecked") private Map<String, Object> stringToHashMap(String retStr) { ObjectMapper mapper = new ObjectMapper(); HashMap<String, Object> map = null; try { map = mapper.readValue(retStr, HashMap.class); } catch (JsonParseException e) { LOG.info(e.toString()); return null; } catch (JsonMappingException e) { LOG.info(e.toString()); return null; } catch (IOException e) { LOG.info(e.toString()); return null; } return map; } // 创建签名 private String createSign(Map<String, String> params) { if (params.isEmpty()) { return null; } StringBuilder sb = new StringBuilder(); params.entrySet().stream().sorted(Comparator.comparing(e -> e.getKey())).forEachOrdered(e -> { sb.append(e.getKey() + "=" + e.getValue() + "&"); }); String key = weChatPayProperties.getWxAppAppid().equals(params.get("appid")) || weChatPayProperties.getWxAppAppid().equals(params.get("appId")) ? weChatPayProperties.getWxAppKey() : weChatPayProperties.getKey(); sb.append("key=" + key); String md5 = MD5Helper.getMd5(sb.toString()); return md5.toUpperCase(); } private Map<String, String> initOrderQueryParams(String appid, String wxBillNo, String erpBillNo) { Map<String, String> params = new HashMap<String, String>(); params.put("appid", appid); params.put("mch_id", weChatPayProperties.getWxAppAppid().equals(appid) ? weChatPayProperties.getWxAppMchId() : weChatPayProperties.getMchId()); params.put("nonce_str", RandomUtils.generateString(31)); if (StringUtils.isNotEmpty(wxBillNo)) { params.put("transaction_id", wxBillNo); } else { // 根据旧单号查询 params.put("out_trade_no", payService.getNewOrderNoByOrderNo(erpBillNo)); } params.put("sign", createSign(params)); return params; } // 获取openID public Map<String, Object> getOpenId(String code) { Map<String, Object> map = null; Map<String, String> params = new HashMap<String, String>(); params.put("appid", weChatPayProperties.getWxAppAppid()); params.put("secret", weChatPayProperties.getWxAppAppsecret()); params.put("js_code", code); params.put("grant_type", "authorization_code"); String retStr = HttpUtils.sendPost(weChatPayProperties.GET_OPEN_ID_URL, params); if (retStr == null) { return null; } map = stringToHashMap(retStr); if (map == null || map.get("openid") == null || map.get("session_key") == null) { return null; } return map; }
@Configuration@PropertySource("classpath:pay.properties")public class WeChatPayProperties { @Value("${WeChatPay.wxapp.appid}") private String wxAppAppid; @Value("${WeChatPay.wxapp.appsecret}") private String wxAppAppsecret; @Value("${WeChatPay.app.appid}") private String appAppid; @Value("${WeChatPay.app.appsecret}") private String appAppsecret; @Value("${WeChatPay.h5.appid}") private String h5Appid; @Value("${WeChatPay.h5.appsecret}") private String h5Appsecret; @Value("${WeChatPay.mch_id}") private String mchId; @Value("${WeChatPay.key}") private String key; @Value("${WeChatPay.notify_url}") private String notifyUrl; @Value("${WeChatPay.wxappmch_id}") private String wxAppMchId; @Value("${WeChatPay.wxappkey}") private String wxAppKey; public final String CREATE_PAY_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder"; public final String ORDERQUERY_URL = "https://api.mch.weixin.qq.com/pay/orderquery"; public final String GET_OPEN_ID_URL = "https://api.weixin.qq.com/sns/jscode2session"; public final String GET_H5_OPEN_ID_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";}
总体来说,微信支付其实整体流程基本差不多,除了h5外部浏览器最后是跳转页面,基本都是服务端做好请求参数,客户端返回参数直接就吊起支付。虽然最后代码看起来简单,但这个微信支付捣鼓了我2个多月才断断续续做完,我总结了下主要是以下几个原因:
1. 微信公众平台,开放平台,商户平台3者的关系特别凌乱。首先像微信小程序的开发是需要在开放平台处理的;接下来H5的微信内部吊起支付是需要通过绑定公众号才能实现,需要通过公众平台来处理;最令人惊讶的是app支付是通过在开放平台开通权限,然后用申请到的商户号进入商户平台处理。跟支付宝只需要在一个开发者中心处理完所有的业务来说,这是腾讯很坑的一点,需要阅读很多文档,因为没有人有精力去研究这三个平台的关联。 2. 腾讯缺少在线客服。支付宝调试遇到问题可以在线向支付宝的技术客服询问,可以很高效地解决问题,相反像腾讯这种虽然文档齐全,但是只能发邮件来问问题我认为效率太低了。因为经常会遇到一些可能客服解决只需要·半分钟的事情,我们却花了3个小时去查看腾讯的文档,这是十分低效的。 3. 微信支付文档齐全但却缺少代码。微信支付几乎没有代码可以使用,都是开发者通过看他的流程图然后自己写代码。我认为微信支付既然都有那么多商户接入,为什么不做一些比较好的代码demo提高接入接口的效率呢?
在这个开发过程中也遇到一些坑:
- App支付必须要发布到正式环境才能调起。
- H5外部客户端调起支付同样也必须发布到正式环境才能调起。
- H5外部客户端支付是在商户平台申请开通的,开通后appid是和App支付的appid一致(我的商户号是通过申请App支付才能生成的),商户号也是和app支付一致
- 各个客户端调起支付的请求参数是不一样的,需要逐个确认。
- app支付的时间戳是10位的,但是其他支付的时间戳长度没有限制。
- 调起支付的金额一定记得要处理。
阅读全文
0 0
- Java服务端支付功能模块--(二)微信支付
- Java服务端支付功能模块--(一)支付宝支付
- 微信APP支付服务端(JAVA)
- java微信支付宝支付(二)
- 微信支付java 服务端实现
- java 服务端对接微信支付 Demo
- 微信支付Java开发服务端
- 微信APP支付Java服务端
- java支付宝和微信app支付(服务端处理)
- Java 微信支付之APP支付服务端 (一)
- java版+支付宝支付和微信支付(二)
- 微信支付 java 服务端demo (v3版本app支付 springMVC框架中)
- 微信支付 java 服务端demo (v3版本app支付 springMVC框架中)
- 微信支付 java 服务端demo (v3版本app支付 springMVC框架中)
- 微信支付 java 服务端demo (v3版本app支付 springMVC框架中)
- java--spring boot微信支付服务端实现含代码(app支付、扫码支付等)
- 微信支付(二)
- 微信支付,服务端代码
- HBASE-11425 直接从offheap读取数据
- 过某P之KdEnteredDebugger检测
- NOT EXISTS不等于NOT IN,IN等于EXISTS
- 数据结构之顺序表
- (学习笔记)spring框架入门之配置bean(处理属性中有集合的情况)
- Java服务端支付功能模块--(二)微信支付
- mybatis的作用域(Scope)和生命周期
- hdu--2056(矩形面积交)
- Nginx高级数据结构总结(一)
- 精简易用cocoaPods的安装与使用
- 使用Intent在启动活动时候来传递数据
- no-repeat 失效
- 对于卡券类兑换的,随机生成兑换码
- 关于成长和学习