微信APP支付(基于Java实现微信APP支付)
Posted ljing21
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信APP支付(基于Java实现微信APP支付)相关的知识,希望对你有一定的参考价值。
步骤:
- 导入maven依赖
<!--微信支付--> <dependency> <groupId>com.github.wxpay</groupId> <artifactId>wxpay-sdk</artifactId> <version>0.0.3</version> </dependency>
- 微信支付参数配置
import com.github.wxpay.sdk.WXPayConfig; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; /** * 微信支付配置(单例) */ public class WXConfigUtil implements WXPayConfig private byte[] certData; private static WXConfigUtil INSTANCE; public static final String APP_ID = "*****";//应用AppID public static final String KEY = "******";//商户密钥 public static final String MCH_ID = "******";//商户号 public WXConfigUtil() throws Exception String certPath = WXConfigUtil.class.getClassLoader().getResource("").getPath();//从微信商户平台下载的安全证书存放的路径 File file = new File(certPath+ "apiclient_cert.p12"); InputStream certStream = new FileInputStream(file); this.certData = new byte[(int) file.length()]; certStream.read(this.certData); certStream.close(); //双重检查加锁 public static WXConfigUtil getInstance() throws Exception if (INSTANCE == null) synchronized (WXConfigUtil.class) if (INSTANCE == null) INSTANCE = new WXConfigUtil(); return INSTANCE; @Override public String getAppID() return APP_ID; //parnerid,商户号 @Override public String getMchID() return MCH_ID; @Override public String getKey() return KEY; @Override public InputStream getCertStream() ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData); return certBis; @Override public int getHttpConnectTimeoutMs() return 8000; @Override public int getHttpReadTimeoutMs() return 10000;
- 业务层统一下单以及异步通知后的XML数据处理
import com.aone.app.common.wx.WXConfigUtil; import com.aone.app.common.wx.WxCfg; import com.aone.app.service.PayService; import com.aone.app.service.WXAppPayService; import com.github.wxpay.sdk.WXPay; import com.github.wxpay.sdk.WXPayUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import java.util.HashMap; import java.util.Map; @Service public class WXAppPayServiceImpl implements WXAppPayService private static final Logger logger = LoggerFactory.getLogger("WXAppPayServiceImpl"); @Autowired private WxCfg wxCfg; /** * 调用官方SDK 获取预支付订单等参数 * @param type * @param out_trade_no * @param money * @return * @throws Exception */ @Override public Map<String, String> dounifiedOrder(String type,String out_trade_no,String money) throws Exception Map<String, String> returnMap = new HashMap<>(); //支付参数 WXConfigUtil config = new WXConfigUtil(); WXPay wxpay = new WXPay(config); //请求参数封装 Map<String, String> data = new HashMap<>(); data.put("appid", config.getAppID()); data.put("mch_id", config.getMchID()); data.put("nonce_str", WXPayUtil.generateNonceStr()); data.put("body", "订单支付"); data.put("out_trade_no", out_trade_no); data.put("total_fee", "1"); data.put("spbill_create_ip", wxCfg.getIp()); //自己的服务器IP地址 data.put("notify_url", wxCfg.getAppNotifyUrl());//异步通知地址(请注意必须是外网) data.put("trade_type", wxCfg.getAppType());//交易类型 data.put("attach", type);//附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 String s = WXPayUtil.generateSignature(data, config.getKey()); //签名 data.put("sign", s);//签名 try //使用官方API请求预付订单 Map<String, String> response = wxpay.unifiedOrder(data); System.out.println(response); String returnCode = response.get("return_code"); //获取返回码 //若返回码为SUCCESS,则会返回一个result_code,再对该result_code进行判断 if (returnCode.equals("SUCCESS")) //主要返回以下5个参数(必须按照顺序,否则APP报错:-1) String resultCode = response.get("result_code"); returnMap.put("appid", response.get("appid")); returnMap.put("noncestr", response.get("nonce_str")); if ("SUCCESS".equals(resultCode)) //resultCode 为SUCCESS,才会返回prepay_id和trade_type returnMap.put("package","Sign=WXPay"); returnMap.put("partnerid", response.get("mch_id")); returnMap.put("prepayid", response.get("prepay_id")); returnMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));//单位为秒 String sign = WXPayUtil.generateSignature(returnMap, config.getKey());// 二次签名 returnMap.put("sign",sign); //签名 returnMap.put("trade_type", response.get("trade_type"));//获取预支付交易回话标志 return returnMap; else //此时返回没有预付订单的数据 return returnMap; else return returnMap; catch (Exception e) System.out.println(e); //系统等其他错误的时候 return returnMap; /** * * @param notifyData 异步通知后的XML数据 * @return */ @Override public String payBack(String notifyData) WXConfigUtil config = null; try config = new WXConfigUtil(); catch (Exception e) e.printStackTrace(); WXPay wxpay = new WXPay(config); String xmlBack = ""; Map<String, String> notifyMap = null; try notifyMap = WXPayUtil.xmlToMap(notifyData); // 调用官方SDK转换成map类型数据 if (wxpay.isPayResultNotifySignatureValid(notifyMap)) //验证签名是否有效,有效则进一步处理 String return_code = notifyMap.get("return_code");//状态 String out_trade_no = notifyMap.get("out_trade_no");//商户订单号 if (return_code.equals("SUCCESS")) if (out_trade_no != null) // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户的订单状态从退款改成支付成功 // 注意特殊情况:微信服务端同样的通知可能会多次发送给商户系统,所以数据持久化之前需要检查是否已经处理过了,处理了直接返回成功标志 //业务数据持久化 System.err.println("支付成功"+"\n"); String attach = notifyMap.get("attach");//附加数据,用于区分是那张表订单 System.out.print("附加数据类型为:"+attach+"\n"); if(StringUtils.isEmpty(attach)) logger.info("附加数据类型为:", attach); else //@TODO 预支付下单后回调的逻辑 logger.info("微信手机支付回调成功订单号:", out_trade_no); xmlBack = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; else logger.info("微信手机支付回调失败订单号:", out_trade_no); xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; return xmlBack; else // 签名错误,如果数据里没有sign字段,也认为是签名错误 //失败的数据要不要存储? logger.error("手机支付回调通知签名错误"); xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; return xmlBack; catch (Exception e) logger.error("手机支付回调通知失败", e); xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; return xmlBack;
- WXCfg中配置的是微信支付的回调地址以及交易类型
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * 微信参数配置中心 */ @Component public class WxCfg @Value("$wx.appType") private String appType;//App支付交易类型 @Value("$wx.appNotifyUrl") private String appNotifyUrl;//App回调地址 @Value("$wx.h5Type") private String h5Type;//H5支付交易类型 @Value("$wx.h5NotifyUrl") private String h5NotifyUrl;//H5回调地址 @Value("$wx.ip") private String ip;//服务器ip @Value("$wx.redirect_url") private String redirect_url;//跳转地址 public String getAppNotifyUrl() return appNotifyUrl; public void setAppNotifyUrl(String appNotifyUrl) this.appNotifyUrl = appNotifyUrl; public String getH5NotifyUrl() return h5NotifyUrl; public void setH5NotifyUrl(String h5NotifyUrl) this.h5NotifyUrl = h5NotifyUrl; public String getAppType() return appType; public void setAppType(String appType) this.appType = appType; public String getH5Type() return h5Type; public void setH5Type(String h5Type) this.h5Type = h5Type; public String getIp() return ip; public void setIp(String ip) this.ip = ip; public String getRedirect_url() return redirect_url; public void setRedirect_url(String redirect_url) this.redirect_url = redirect_url;
- 控制层下单接口以及回调接口
import com.aone.app.service.WXAppPayService; import io.swagger.annotations.Api; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @RestController @RequestMapping("pay") @Api("App支付") public class PayAppController @Autowired private WXAppPayService wxAppPayService; /** * * App支付统一下单 * @param out_trade_no 订单号 * @param total_fee 支付金额 * @param type 0:预约订单1:专家保证金2:即时咨询订单 * @return * @throws Exception */ @PostMapping("order") public Map<String, String> order(@RequestParam(value = "type") String type,@RequestParam(value = "out_trade_no") String out_trade_no,@RequestParam(value = "total_fee") String total_fee)throws Exception return wxAppPayService.dounifiedOrder(type,out_trade_no,total_fee); /** * 微信支付异步结果通知 */ @RequestMapping(value = "wxPayNotify", method = RequestMethod.GET, RequestMethod.POST) public String wxPayNotify(HttpServletRequest request, HttpServletResponse response) System.out.print("微信回调开始"+"\n"); String resXml = ""; try InputStream inputStream = request.getInputStream(); //将InputStream转换成xmlString BufferedReader 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) System.out.println(e.getMessage()); finally try inputStream.close(); catch (IOException e) e.printStackTrace(); resXml = sb.toString(); String result = wxAppPayService.payBack(resXml); System.out.print("微信回调结束"+"\n"); return result; catch (Exception e) System.out.println("微信手机支付失败:" + e.getMessage()); String result = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; return result;
- 下单封装的Map中封装参数服务器IP写死可能会报错,提供获取服务器IP工具类
import javax.servlet.http.HttpServletRequest; /** * 获取服务器IP工具类 */ public class IpAddr public static String getIpAddr(HttpServletRequest request) String ip = request.getHeader("x-forwarded-for"); if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) ip = request.getHeader("PRoxy-Client-IP"); if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) ip = request.getHeader("WL-Proxy-Client-IP"); if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) ip = request.getRemoteAddr(); return ip;
主要用于安卓APP微信支付,ios微信支付可能是需要交钱,太贵了,所以IOS的微信支付提供外链接使用H5进行支付。
以上是关于微信APP支付(基于Java实现微信APP支付)的主要内容,如果未能解决你的问题,请参考以下文章