您现在的位置是:首页 > 文章详情

微信扫码支付、网站接入微信支付-java

日期:2018-05-02点击:288

如果你的网站想接入微信支付,那么你的有个公众号(微信公众平台),然后开通支付功能,在微信商户平台操作。仔细看哦,这是两个平台,商家平台有详细的接入流程,这里只介绍程序方面。

1、准备

  • 准备商家帐户
  • 下载证书,重置密钥(密钥重置后请妥善保管)
  • 内网穿透软件(微信支付成功后会有回调)

2、代码

  • 加入依赖

微信支付比较麻烦,所以我们采用第三方封装的jar包

compile group: 'com.github.binarywang', name: 'weixin-java-pay', version: '3.0.0' 
  • 新建 pay.properties
#wxpay WX.APPID=wxdd088f0c1d70cbf9 WX.MCHID=你的商户id WX.MCHKEY=你的密钥 WX.SUBAPPID= WX.SUBMCHID= WX.KEYPATH= #下面这个是微信回调地址,要保证外网可以访问,内网测试就用内网穿透软件 WX.NOTIFYURL=http://tdcloud.trmap.cn/reward/getOrderNotifyResult WX.TRADETYPE=NATIVE 
  • 配置类

WxPayConfig 将配置文件里的值读取出来,微信支付需要的相关配置

 @Configuration @PropertySource(value="classpath:pay.properties", ignoreResourceNotFound=true) public class WxPayConfig { /** * http请求连接超时时间 */ private int httpConnectionTimeout = 5000; /** * http请求数据读取等待时间 */ private int httpTimeout = 10000; private String appId; private String subAppId; private String mchId; private String mchKey; private String subMchId; private String notifyUrl; private String tradeType; private String signType; private SSLContext sslContext; private String keyPath; private boolean useSandboxEnv = false; private String httpProxyHost; private Integer httpProxyPort; private String httpProxyUsername; private String httpProxyPassword; public String getKeyPath() { return keyPath; } /** * 设置证书 * * @param keyPath apiclient_cert.p12的文件的绝对路径 */ public void setKeyPath(String keyPath) { this.keyPath = keyPath; } /** * 商户号 */ public String getMchId() { return this.mchId; } public void setMchId(String mchId) { this.mchId = mchId; } /** * 商户密钥 */ public String getMchKey() { return this.mchKey; } public void setMchKey(String mchKey) { this.mchKey = mchKey; } /** * 公众号appid */ public String getAppId() { return this.appId; } public void setAppId(String appId) { this.appId = appId; } /** * 服务商模式下的子商户公众账号ID */ public String getSubAppId() { return this.subAppId; } public void setSubAppId(String subAppId) { this.subAppId = subAppId; } /** * 服务商模式下的子商户号 */ public String getSubMchId() { return this.subMchId; } public void setSubMchId(String subMchId) { this.subMchId = subMchId; } /** * 微信支付异步回掉地址,通知url必须为直接可访问的url,不能携带参数。 */ public String getNotifyUrl() { return this.notifyUrl; } public void setNotifyUrl(String notifyUrl) { this.notifyUrl = notifyUrl; } /** * 交易类型 * <pre> * JSAPI--公众号支付 * NATIVE--原生扫码支付 * APP--app支付 * </pre> */ public String getTradeType() { return this.tradeType; } public void setTradeType(String tradeType) { this.tradeType = tradeType; } /** * 签名方式 * 有两种HMAC_SHA256 和MD5 * @see com.github.binarywang.wxpay.constant.WxPayConstants.SignType */ public String getSignType() { return this.signType; } public void setSignType(String signType) { this.signType = signType; } public SSLContext getSslContext() { return this.sslContext; } public void setSslContext(SSLContext sslContext) { this.sslContext = sslContext; } /** * 微信支付是否使用仿真测试环境 * 默认不使用 */ public boolean useSandbox() { return this.useSandboxEnv; } /** * 设置是否使用沙箱仿真测试环境 */ public void setUseSandboxEnv(boolean useSandboxEnv) { this.useSandboxEnv = useSandboxEnv; } public SSLContext initSSLContext() throws WxPayException { if (StringUtils.isBlank(this.getMchId())) { throw new WxPayException("请确保商户号mchId已设置"); } if (StringUtils.isBlank(this.getKeyPath())) { throw new WxPayException("请确保证书文件地址keyPath已配置"); } InputStream inputStream; final String prefix = "classpath:"; String fileHasProblemMsg = "证书文件【" + this.getKeyPath() + "】有问题,请核实!"; String fileNotFoundMsg = "证书文件【" + this.getKeyPath() + "】不存在,请核实!"; if (this.getKeyPath().startsWith(prefix)) { String path = StringUtils.removeFirst(this.getKeyPath(), prefix); if (!path.startsWith("/")) { path = "/" + path; } inputStream = WxPayConfig.class.getResourceAsStream(path); if (inputStream == null) { throw new WxPayException(fileNotFoundMsg); } } else { try { File file = new File(this.getKeyPath()); if (!file.exists()) { throw new WxPayException(fileNotFoundMsg); } inputStream = new FileInputStream(file); } catch (IOException e) { throw new WxPayException(fileHasProblemMsg, e); } } try { KeyStore keystore = KeyStore.getInstance("PKCS12"); char[] partnerId2charArray = this.getMchId().toCharArray(); keystore.load(inputStream, partnerId2charArray); this.sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build(); return this.sslContext; } catch (Exception e) { throw new WxPayException(fileHasProblemMsg, e); } finally { IOUtils.closeQuietly(inputStream); } } /** * http请求连接超时时间 */ public int getHttpConnectionTimeout() { return this.httpConnectionTimeout; } public void setHttpConnectionTimeout(int httpConnectionTimeout) { this.httpConnectionTimeout = httpConnectionTimeout; } /** * http请求数据读取等待时间 */ public int getHttpTimeout() { return this.httpTimeout; } public void setHttpTimeout(int httpTimeout) { this.httpTimeout = httpTimeout; } public String getHttpProxyHost() { return httpProxyHost; } public void setHttpProxyHost(String httpProxyHost) { this.httpProxyHost = httpProxyHost; } public Integer getHttpProxyPort() { return httpProxyPort; } public void setHttpProxyPort(Integer httpProxyPort) { this.httpProxyPort = httpProxyPort; } public String getHttpProxyUsername() { return httpProxyUsername; } public void setHttpProxyUsername(String httpProxyUsername) { this.httpProxyUsername = httpProxyUsername; } public String getHttpProxyPassword() { return httpProxyPassword; } public void setHttpProxyPassword(String httpProxyPassword) { this.httpProxyPassword = httpProxyPassword; } } 
  • 发起支付,获取生成二维码的地址

微信支付的单位是分,例如你支付金额是9.9元(保留两位小数),那你微信支付的时候支付金额是9.9元*100 = 990分,最后支付金额是整数。

封装请求参数,请求微信接口后会返回生成二维码的地址

 @Autowired private WxPayConfig payConfig; @Autowired private WxPayService wxService; //上边依赖第三方库提供的 @RequestMapping("wxpay") private ResponseEntity<Result> rewardWxpay(@RequestParam Double money, HttpServletRequest request,WxPayUnifiedOrderRequest wxreq){ try { @RequestMapping("wxpay") private ResponseEntity<Result> rewardWxpay(String userid,@RequestParam String produceid,@RequestParam Double money,String remark, HttpServletRequest request,WxPayUnifiedOrderRequest wxreq){ try { // TODO 生成你的订单信息,然后返回订单id,这里代码忽略,根据自己的业务调整 String ip = req.getHeader("x-forwarded-for"); if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = req.getHeader("Proxy-Client-IP"); } if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = req.getHeader("WL-Proxy-Client-IP"); } if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = req.getRemoteAddr(); } if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) { // 多次反向代理后会有多个ip值,第一个ip才是真实ip if( ip.indexOf(",")!=-1 ){ ip = ip.split(",")[0]; } } request.setBody("实景在线打赏-"); // 支付标题 request.setOutTradeNo(你自己的订单编号); // 金额一定要以分为单位,所以最后支付金额为整数 String string = String.valueOf((reward.getMoney()*100)); request.setTotalFee(Integer.parseInt(string.substring(0,string.indexOf(".")))); request.setAppid(payConfig.getAppId()); request.setMchId(payConfig.getMchId()); request.setNotifyUrl(payConfig.getNotifyUrl()); request.setSpbillCreateIp(ip); request.setTradeType(payConfig.getTradeType()); //this.wxService.unifiedOrder(request) 发起请求,获取地址,然后根据地址生成二维码 return SUCCESS(this.wxService.unifiedOrder(request);); } catch (WxPayException e) { e.printStackTrace(); } return ERROR("发起支付失败"); } } catch (WxPayException e) { e.printStackTrace(); } return ERROR("发起支付失败"); } 
  • 生成二维码

根据上一步请求返回的地址生成二维码,生成的二维码是base64格式的字节码,前台用img标签直接显示即可,这时候用户就可以扫描生成的二维码进行支付了

/** * <pre> * 扫码支付模式二生成二维码的方法 * 对应链接格式:weixin://wxpay/bizpayurl?sr=XXXXX。请商户调用第三方库将code_url生成二维码图片。 * 该模式链接较短,生成的二维码打印到结账小票上的识别率较高。 * 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5 * </pre> * * @param codeUrl * 微信返回的交易会话的二维码链接 * @param logoFile * 商户logo图片的文件对象,可以为空 * @param sideLength * 要生成的二维码的边长,如果为空,则取默认值400 * @return 生成的二维码的字节数组 */ @PostMapping(value = "/createScanPayQrcode") public ResponseEntity<Result> createQrcode(String codeUrl,File logoFile, Integer sideLength) { byte[] by = this.wxService.createScanPayQrcodeMode2(codeUrl, logoFile, sideLength); return SUCCESS(by); } 
  • 回调接口

用户扫描支付后,微信会异步通知,请求地址为配置文件中的接口地址,所以要保证公网可以访问。微信共会请求8次回调接口,如果处理成功后,将不在请求回调接口

 /** * 读取支付结果通知 * * @param xmlData * @throws WxPayException */ @RequestMapping(value = "/getOrderNotifyResult", method = RequestMethod.POST) public String getOrderNotifyResult(@RequestBody String xmlData,HttpServletRequest request, HttpServletResponse response) throws WxErrorException, WxPayException { WxPayOrderNotifyResult orderNotifyResult = this.wxService.parseOrderNotifyResult(xmlData); String noticeStr = null; try { BufferedOutputStream outputStream = new BufferedOutputStream(response.getOutputStream()); // 支付成功,商户处理后同步返回给微信参数 if (!orderNotifyResult.getResultCode().equals("SUCCESS")) { // 支付失败, 记录流水失败 System.out.println("===============支付失败=============="); noticeStr = setXML("FAIL", "支付失败"); outputStream.write(noticeStr.getBytes()); outputStream.flush(); outputStream.close(); } else { // TODO 处理你的业务,修改订单状态等 // 通知微信已经收到消息,不要再给我发消息了,否则微信会8连击调用本接口 noticeStr = setXML("SUCCESS", "支付成功"); outputStream.write(noticeStr.getBytes()); outputStream.flush(); outputStream.close(); } } catch (Exception e) { e.printStackTrace(); } return noticeStr; } public String setXML(String return_code, String return_msg) { return "<xml><return_code><![CDATA[" + return_code + "]]></return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>"; } 

到这里,网站接入微信扫码支付,代码部分就全部完成了,最后效果图请看下方图片。


img_bd9eb9ebe0945d9c732b8f19395f76f2.png
这里写图片描述

img_2cdd4ac1e398ae70047d007142b3e65e.png
这里写图片描述

关注

如果有问题,请在下方评论,或者加群讨论 200909980

关注下方微信公众号,可以及时获取到各种技术的干货哦,如果你有想推荐的帖子,也可以联系我们的。

img_cb380af3d7a871d3f66df87a6eae835e.png
码农笔录二维码
原文链接:https://yq.aliyun.com/articles/635825
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章