关于微信支付和支付宝支付java实现
目前支付宝支付和微信支付是算是目前app的标配了 支付宝支付在更新过后有了官方专门的sdk和demo,所以相对而言比较简单,而微信支付稍微复杂一点,下面的文章会附实例代码,微信支付也是参考的github上的某位大神级人物的代码。 首先是微信支付 先准备各种数据,我一般都是放到配置类中,当然也可以放到数据库或者配置文件中 `public final class WxpayConfig { /** *商家可以考虑读取配置文件 */ //微信开发平台应用id public static final String APP_ID = "wx8888888888888888"; //财付通商户号 public static final String PARTNER = "1900000109";//app请求的商户号 public static final String MCHID = "1900000109";//预支付请求的商户号 //商户号对应的密钥 public static final String PARTNER_KEY = ""; //预支付接口 public static final String PREPAY_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //查询订单接口 public static final String QUERY_ORDER_URL = "https://api.mch.weixin.qq.com/pay/orderquery"; //签名算法常量值 public static final String SIGN_METHOD = "sha1"; //异步通知地址 public static final String NOTIFY_URL = “”; //交易类型 public static final String TRADE_TYPE = "APP"; //暂定包值 public static final String PACKAGE = "Sign=WXPay"; //返回状态成功 public static final String SUCCESS = "SUCCESS"; //返回状态失败 public static final String FAIL = "FAIL"; }` 这是关于微信支付的封装的工具类,其中httpclient和md5加密的需要自己去封装工具类 `public class WxpayUtil { /** *随机串 * @return */ public static String getNonceStr() { Random random = new Random(); return MD5Util.getMD5String(String.valueOf(random.nextInt(10000))); } /** *时间戳 * @return */ public static String getTimeStamp() { return String.valueOf(System.currentTimeMillis() / 1000); } /** *解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 * @param strxml * @return * @throws JDOMException * @throws IOException */ @SuppressWarnings("unchecked") public static Map parseToMap(String strXml) throws JDOMException, IOException { strXml = strXml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\""); if(null == strXml || "".equals(strXml)) { return null; } Map m = new HashMap<>(); InputStream in = new ByteArrayInputStream(strXml.getBytes("UTF-8")); SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(in); Element root = doc.getRootElement(); List list = root.getChildren(); Iterator it = list.iterator(); while(it.hasNext()) { Element e = it.next(); String k = e.getName(); String v = ""; List children = e.getChildren(); if(children.isEmpty()) { v = e.getTextNormalize(); } else { v = getChildrenText(children); } m.put(k, v); } //关闭流 in.close(); return m; } /** *获取子结点的xml * @param children * @return String */ @SuppressWarnings("unchecked") private static String getChildrenText(List children) { StringBuffer sb = new StringBuffer(); if(!children.isEmpty()) { Iterator it = children.iterator(); while(it.hasNext()) { Element e = it.next(); String name = e.getName(); String value = e.getTextNormalize(); List list = e.getChildren(); sb.append("<" + name + ">"); if(!list.isEmpty()) { sb.append(getChildrenText(list)); } sb.append(value); sb.append(""); } } return sb.toString(); } /** *只支持String,并且value非空 * @param map * @return */ public static String parseToXml(Map map){ StringBuffer sb = new StringBuffer(""); for(Map.Entry entry : map.entrySet()){ sb.append("<"+entry.getKey()+">"); sb.append(""); sb.append(""); } sb.append(""); return sb.toString(); } /** * POST提交XML对象 * @param document */ public static String postXmlClient(String url,String xmlParams) throws Exception { // return HttpUtils.postXmlEntity(url, xmlParams).getContent(); return HttpClient.postRequest(url, xmlParams); } } 这是关于微信支付一些参数处理的方法 public class WxpayHelper { /** *除去数组中的空值和签名参数 * @param sArray签名参数组 * @return去掉空值与签名参数后的新签名参数组 */ public static Map paraFilter(Map sArray) { Map result = new HashMap(); if (sArray == null || sArray.size() <= 0) { return result; } for (String key : sArray.keySet()) { String value = sArray.get(key); if (value == null || value.equals("") || key.equalsIgnoreCase("sign") || key.equalsIgnoreCase("key")) { continue; } result.put(key, value); } return result; } /** *把数组所有元素,并按照“参数=参数值”的模式用“&”字符拼接成字符串 * @param params需要参与字符拼接的参数组 * @param sorts 是否需要排序 true 或者false * @return拼接后字符串 */ public static String createLinkString(Map params) { List keys = new ArrayList(params.keySet()); Collections.sort(keys); String prestr = ""; for (int i = 0; i < keys.size(); i++) { String key = keys.get(i); String value = params.get(key); if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符 prestr = prestr + key + "=" + value; } else { prestr = prestr + key + "=" + value + "&"; } } return prestr; } /** *验签响应签名 * @param paras * @return */ public static boolean verify(Map paras){ String sign = paras.get("sign"); if(StringUtils.isBlank(sign)) return false; return sign.equals(WxpayBuilder.buildRequestMysign(paraFilter(paras))); } /** *响应成功 * @param loggerAgent -日志代理 * @return String */ /*public static String yes(ILoggerAgent loggerAgent){ Map return_wx = new HashMap<>(); return_wx.put("return_code", WxpayConfig.SUCCESS); loggerAgent.payParamsLogger(null , "WX-NOTIFY", false, return_wx); return WxpayUtil.parseToXml(return_wx); }*/ } public class WxpayBuilder { /** *生成签名结果 * @param sPara要签名的数组 * @return签名结果字符串 */ public static String buildRequestMysign(Map sPara) { String prestr = WxpayHelper.createLinkString(sPara)+"&key="+WxpayConfig.PARTNER_KEY; LogFactory.getInstance().getLogger().debug("微信支付签名的字符串:"+prestr); return MD5Util.getMD5String(prestr).toUpperCase(); } public static Map buildRequestPara(Map sParaTemp) { //除去数组中的空值和签名参数 Map sPara = WxpayHelper.paraFilter(sParaTemp); //生成签名结果 String mysign = buildRequestMysign(sPara); LogFactory.getInstance().getLogger().debug("微信支付签名数据:"+mysign); //签名结果与签名方式加入请求提交参数组中 sPara.put("sign", mysign); return sPara; } }` 使用例程 其中业务接口信息,参考https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_7&index=3 ` /** *微信订单逻辑 * * @throws Exception */ public Map wxPayLogic() throws Exception { //微信业务代码 Map xmlData = new HashMap(); xmlData.put("appid", WxpayConfig.APP_ID); xmlData.put("mch_id", WxpayConfig.MCHID); xmlData.put("nonce_str", WxpayUtil.getNonceStr()); xmlData.put("out_trade_no",); xmlData.put("total_fee",); xmlData.put("spbill_create_ip",“”); //从数据字典里面去主机地址 DataDictionary dataDictionary = dataDictionaryService.getDicByKey("PAY_CALLBACK"); xmlData.put("notify_url", dataDictionary.getValue() + WxpayConfig.NOTIFY_URL); xmlData.put("trade_type", WxpayConfig.TRADE_TYPE); xmlData.put("body", ""); //少写签名 Map result = WxpayBuilder.buildRequestPara(xmlData); // Map result = WxpayHelper.paraFilter(xmlData); String xmlParams = WxpayUtil.parseToXml(result); LogFactory.getInstance().getLogger().debug("微信支付请求报文:" + xmlParams); String xmlResult = WxpayUtil.postXmlClient(WxpayConfig.PREPAY_URL, xmlParams); Map map = WxpayUtil.parseToMap(xmlResult); LogFactory.getInstance().getLogger().debug("微信支付返回报文:" + JsonHelper.toJson(map)); //返回时SUCCESS if (WxpayConfig.SUCCESS.equals(map.get("return_code"))) { //验证返回是否成功 if (WxpayConfig.SUCCESS.equals(map.get("result_code"))) { //除去签名和空值 Map paraFilter = WxpayHelper.paraFilter(map); //获得签名 String mysign = WxpayBuilder.buildRequestMysign(paraFilter); //验证签名 if (mysign.equals(map.get("sign"))) { String prepay_id = map.get("prepay_id"); //验证签名成功 //进行操作 } else { //签名验证失败 LogFactory.getInstance().getLogger().debug("微信支付验证签名失败"); } } else { // result_code返回失败 String err_code = map.get("err_code"); String err_code_des = map.get("err_code_des"); chargeRecord.setCauses(err_code+err_code_des); LogFactory.getInstance().getLogger().debug("微信支付结果失败:失败码为"+err_code+",失败原因是"+err_code_des); chargeRecord.setState(2); } } else { // return_code返回失败 String return_msg = map.get("return_msg"); LogFactory.getInstance().getLogger().debug("微信支付返回失败:返回消息为:" + return_msg); return null; } //微信支付 Map mapBack = new HashMap<>(); mapBack.put("appid", WxpayConfig.APP_ID); mapBack.put("partnerid", WxpayConfig.PARTNER); mapBack.put("prepayid", chargeRecord.getOpenId()); mapBack.put("package", WxpayConfig.PACKAGE); mapBack.put("noncestr", WxpayUtil.getNonceStr()); mapBack.put("timestamp", WxpayUtil.getTimeStamp()); return WxpayBuilder.buildRequestPara(mapBack); }` 支付异步回传 接收到异步通知之后,才算是付款成功 `@Controller @RequestMapping(value = "/api") public class WxPayCallbackController extends BaseController { @Autowired OrderLogic orderLogic; @Autowired RedisFactory redisFactory; @Autowired ApplicationContext applicationContext; @RequestMapping(value = "/wxPayCallback", method = RequestMethod.POST) @ResponseBody public String wxPayCallback(@RequestBody String body) { MDC.put("seqID", SeqIdGenerator.generate());//日志序列 LogFactory.getInstance().getPayCallbackLogger().info("接收到微信的异步支付结果通知信息data=" + body); Map resultMap = new HashMap<>(); if (StringUtils.isNotBlank(body)) { try { Map map = WxpayUtil.parseToMap(body); //返回代码 if (WxpayConfig.SUCCESS.equals(map.get("return_code"))) { //验证签名 if (WxpayHelper.verify(map)) { //验证业务结果是否成功 String outTradeNo = map.get("out_trade_no"); if (WxpayConfig.SUCCESS.equals(map.get("result_code"))) { //设置支付类型,1为支付宝,2为微信 map.put("payType","2"); //通过所有验证,启动事件,通过spring的监听器进行监听,并执行付款成功后的业务 applicationContext.publishEvent(new OrderFinishEvent(map)); } else { //业务结果失败 LogFactory.getInstance().getPayCallbackLogger().info("接收到微信的异步支付业务结果失败"); orderLogic.updateState(outTradeNo,2); resultMap.put("return_code", WxpayConfig.SUCCESS); } } else { //签名失败 LogFactory.getInstance().getPayCallbackLogger().info("接收到微信的异步支付签名失败"); resultMap.put("return_code", WxpayConfig.FAIL); resultMap.put("return_msg", "签名失败"); } } else { //返回结果失败 LogFactory.getInstance().getPayCallbackLogger().info("接收到微信的异步支付返回结果失败"); resultMap.put("return_code", WxpayConfig.FAIL); resultMap.put("return_msg", "参数格式校验错误"); } } catch (Exception e) { e.printStackTrace(); } } else { //返回结果为空 LogFactory.getInstance().getPayCallbackLogger().info("参数格式校验错误"); resultMap.put("return_code", WxpayConfig.FAIL); resultMap.put("return_msg", "参数格式校验错误"); } return WxpayUtil.parseToXml(resultMap); } }` 付款成功统一处理事件监听 `@Component public class OrderFinishLister { @EventListener public void onApplicationEvent(OrderFinishEvent event){//这里不能抛出异常,外层无法处理,会造成中断 try { Map params = (HashMap) event.getSource(); String payType = params.get("payType"); String outTradeNo = params.get("out_trade_no"); String trade_no = null; String buyerLogonId = null; String buyerId = null; String transactionId = null; UserOrder order = null; if("1".equals(payType)){ //支付宝 trade_no = params.get("trade_no"); buyerLogonId = params.get("buyer_logon_id"); buyerId = params.get("buyer_id"); //执行付款成功后的业务逻辑 LogFactory.getInstance().getLogger().debug("支付宝获取支付更新状态:" + outTradeNo); }else if("2".equals(payType)){ //微信 transactionId = params.get("transaction_id"); //执行微信付款成功后的业务逻辑 LogFactory.getInstance().getLogger().debug("微信获取支付更新状态:" + outTradeNo); } }catch (Exception e){ e.printStackTrace(); } } }` 这就是单独的微信支付业务流程