SpringBoot对接微信H5

SpringBoot对接微信支付H5

一:开发文档

  1. 场景介绍

H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务唤起微信客户端进行支付。

  1. 申请入口

登录商户平台–>产品中心–>我的产品–>支付产品–>H5支付 
注意:需要开通H5支付,并且做一些配置

微信官方体验链接:http://wxpay.wxutil.com/mch/pay/h5.v2.php,请在微信外浏览器打开。

  1. 业务流程描述

1、用户在商户侧完成下单,使用微信支付进行支付

2、由商户后台向微信支付发起下单请求(调用统一下单接口)注:交易类型trade_type=MWEB

3、统一下单接口返回支付相关参数给商户后台,如支付跳转url(参数名“mweb_url”),商户通过mweb_url调起微信支付中间页

4、中间页进行H5权限的校验,安全性检查(此处常见错误请见下文)

5、如支付成功,商户后台会接收到微信侧的异步通知

6、用户在微信支付收银台完成支付或取消支付,返回商户页面(默认为返回支付发起页面)

7、商户在展示页面,引导用户主动发起支付结果的查询

8、商户后台判断是否接到收微信侧的支付结果通知,如没有,后台调用我们的订单查询接口确认订单状态

9、展示最终的订单支付结果给用户

H5支付文档

二:集成步骤

  1. 引入依赖

<dependency>

<groupId>org.apache.httpcomponentsgroupId>

<artifactId>httpclientartifactId>

dependency>

<dependency>

<groupId>dom4jgroupId>

<artifactId>dom4jartifactId>

dependency>

  1. wechatConfig.properties

1、再resource/config下增加配置文件wechatConfig.properties

2、properties文件内容如下:

###############WeChatPay start#################

wechat.appid=wxd123456778902

wechat.merchantId=1234567890

wechat.merchantName=测试H5支付账号

wechat.merchantKey=12345678901234567890123456789012

wechat.notifyUrl=weChatPayResult

wechat.unifiedorder=https://api.mch.weixin.qq.com/pay/unifiedorder

wechat.orderquery=https://api.mch.weixin.qq.com/pay/orderquery

wechat.accessTocken=https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey

###############WeChatPay end#################

  1. 编写配置文件对应的类文件

package com.will.wang.wechatPay.utils;

 

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.context.annotation.PropertySource;

import org.springframework.stereotype.Component;

 

@Component

@PropertySource(value = "classpath:config/wechatConfig.properties")

@ConfigurationProperties(prefix = "wechat")

public class WeChatPropertyConfig {

         public String appid;

         public String merchantId;

         public String merchantName;

         public String merchantKey;

         public String notifyUrl;

         public String unifiedorder;

         public String orderquery;

         public String accessTocken;

        

         public String getAppid() {

                   return appid;

         }

         public void setAppid(String appid) {

                   this.appid = appid;

         }

         public String getMerchantId() {

                   return merchantId;

         }

         public void setMerchantId(String merchantId) {

                   this.merchantId = merchantId;

         }

         public String getMerchantName() {

                   return merchantName;

         }

         public void setMerchantName(String merchantName) {

                   this.merchantName = merchantName;

         }

         public String getMerchantKey() {

                   return merchantKey;

         }

         public void setMerchantKey(String merchantKey) {

                   this.merchantKey = merchantKey;

         }

         public String getNotifyUrl() {

                   return notifyUrl;

         }

         public void setNotifyUrl(String notifyUrl) {

                   this.notifyUrl = notifyUrl;

         }

         public String getUnifiedorder() {

                   return unifiedorder;

         }

         public void setUnifiedorder(String unifiedorder) {

                   this.unifiedorder = unifiedorder;

         }

         public String getOrderquery() {

                   return orderquery;

         }

         public void setOrderquery(String orderquery) {

                   this.orderquery = orderquery;

         }

         public String getAccessTocken() {

                   return accessTocken;

         }

         public void setAccessTocken(String accessTocken) {

                   this.accessTocken = accessTocken;

         }

}

  1. WeChatUtils

package com.will.wang.wechatPay.utils;

 

import java.io.ByteArrayOutputStream;

import java.io.InputStream;

import java.net.URLEncoder;

import java.util.Map;

import java.util.TreeMap;

 

import javax.servlet.http.HttpServletRequest;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

 

import com.will.wang.utils.MD5Util;

import com.will.wang.utils.UUIDUtils;

import com.will.wang.utils.XMLUtils;

 

@Component

public class WeChatUtils {

        

         //支付状态

         public static final String SUCCESS= "SUCCESS";

         public static final String FAIL= "FAIL";

        

         @Autowired

         private WeChatPropertyConfig weChatPropertyConfig;

         @Autowired

         private XMLUtils XMLUtils;

        

        

         public String packageOrderQueryXml(Map map) {

                   TreeMap treeMap = new TreeMap();

                   treeMap.put("appid", String.valueOf(map.get("appid")));

                   treeMap.put("mch_id", String.valueOf(map.get("mch_id")));

          treeMap.put("transaction_id",String.valueOf(map.get("transaction_id")));

                   treeMap.put("nonce_str", UUIDUtils.createUUID());

//                treeMap.put("out_trade_no", this.out_trade_no);

                  

                   StringBuilder sb = new StringBuilder();

                   for (String key : treeMap.keySet()) {

         sb.append(key).append("=").append(treeMap.get(key)).append("&");

                   }

                   sb.append("key=" + weChatPropertyConfig.getMerchantKey());

                   String sign = MD5Util.MD5Encode(sb.toString(), "utf-8").toUpperCase();

                   treeMap.put("sign", sign);

 

                   String xmlStr = XMLUtils.doMapToXML(treeMap);

                   return xmlStr;

         }

        

         /**

          * 封装需要提交给微信的参数

          * 此处参数再实际使用中最好传入一个订单类,根据订单参数封装提交给微信的数据

          * @param bill_create_ip

          * @param amount

          * @return

          */

         public String packageParam(String bill_create_ip, Double amount) {

                   String prePayXml = null;

                   try {

                            //订单id

                            String out_trade_no  = UUIDUtils.createUUID();

                            //获取配置信息,appId,商户id,商户名称,商户key,回调地址

                            String appid = weChatPropertyConfig.getAppid();

                            String merchantId = weChatPropertyConfig.getMerchantId();

                            String merchantKey = weChatPropertyConfig.getMerchantKey();

                            String merchantName = weChatPropertyConfig.getMerchantName();

                            String notifyUrl = weChatPropertyConfig.getNotifyUrl();

                                              

                            TreeMap treeMap = new TreeMap();

                            treeMap.put("appid", appid);

                            treeMap.put("mch_id", merchantId);// 设置商户号

                            treeMap.put("nonce_str", UUIDUtils.createUUID());//随机数

                            treeMap.put("body", URLEncoder.encode("测试支付", "UTF-8"));//商品描述 

                            treeMap.put("out_trade_no", out_trade_no);//商户系统内部的订单号,32个字符内、可包含字母,确保在商户系统唯一,详细说明

//                         treeMap.put("total_fee", String.valueOf((int)Math.floor(amount*100)));// 商品总金额,以分为单位,古放大100倍向下取整、

                            treeMap.put("total_fee", String.valueOf(amount));

                            treeMap.put("spbill_create_ip", bill_create_ip);

                            treeMap.put("notify_url", notifyUrl);//通知回调地址

                            treeMap.put("trade_type", "MWEB");//H5支付

                            String sceneinfo = "{\"h5_info\":{\"type\":\"Wap\",\"wap_url\":\"http://test4.csservice.cn\",\"wap_name\":\"dangfeijiaona\"}}";

                            treeMap.put("scene_info",sceneinfo);

                            treeMap.put("openid", null);

                            treeMap.put("attach", URLEncoder.encode("测试微信支付", "UTF-8"));

                            StringBuilder sb = new StringBuilder();

                            for (String key : treeMap.keySet()) {

                                     sb.append(key).append("=").append(treeMap.get(key)).append("&");

                            }

                            sb.append("key=" + merchantKey);

                            String sign = MD5Util.MD5Encode(sb.toString(), "utf-8").toUpperCase();

                            treeMap.put("sign", sign);

                            StringBuilder xml = new StringBuilder();

                            xml.append("\n");

                            for (Map.Entry entry : treeMap.entrySet()) {

                                               xml.append("<" + entry.getKey() + ">").append(entry.getValue()).append(" + entry.getKey() + ">\n");

                            }

                            xml.append("");

                            System.out.println(xml.toString());

                           

                            prePayXml = new String(xml.toString().getBytes("UTF-8"), "ISO-8859-1");

                                     //调用微信接口

                   } catch (Exception e) {

                                     // TODO Auto-generated catch block

                                     e.printStackTrace();

                   }

                   return prePayXml;

         }

 

         /**

          * 获取微信回调数据

          * @param request

          * @return

          */

         public Map getWeChatReplay(HttpServletRequest request){

                   Map map = null;

                   try {

                            InputStream inStream = request.getInputStream();

                            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();

                            byte[] buffer = new byte[1024];

                            int len = 0;

                            while ((len = inStream.read(buffer)) != -1) {

                                     outSteam.write(buffer, 0, len);

                            }

                            outSteam.close();

                            inStream.close();

                            String result = new String(outSteam.toByteArray(), "utf-8");

                            map = XMLUtils.doXMLParse(result);

                   }catch(Exception e) {

                            e.printStackTrace();

                   }

                   return map;

         }

        

}

  1. HttpClient

package com.will.wang.utils.http;

 

import java.io.IOException;

import java.io.UnsupportedEncodingException;

import java.util.ArrayList;

import java.util.List;

import java.util.Map;

 

import org.apache.http.HttpEntity;

import org.apache.http.NameValuePair;

import org.apache.http.ParseException;

import org.apache.http.client.entity.UrlEncodedFormEntity;

import org.apache.http.client.methods.CloseableHttpResponse;

import org.apache.http.client.methods.HttpGet;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.client.methods.HttpPut;

import org.apache.http.client.utils.URIBuilder;

import org.apache.http.entity.StringEntity;

import org.apache.http.impl.client.CloseableHttpClient;

import org.apache.http.impl.client.HttpClients;

import org.apache.http.message.BasicNameValuePair;

import org.apache.http.util.EntityUtils;

import org.springframework.stereotype.Component;

 

@Component

public class HttpClient {

        

         public static final int SUCCESS = 200;

        

         CloseableHttpClient httpClient = null;

         CloseableHttpResponse response = null;

        

         private static class HttpClientHolder{

        private static HttpClient instance=new HttpClient();

    }

    private HttpClient(){

    }

    public static HttpClient getInstance(){

        return HttpClientHolder.instance;

    }

        

         public String doGet(String uri){

                   HttpGet httpGet = new HttpGet(uri);

                   return sendHttpGet(httpGet);

         }

        

         /**

          * 发送Get请求

          * @param uri

          * @param map

          * @return

          */

         public String doGet(String uri, Map map){

                    List parameters = new ArrayList();

                    for(Map.Entry entry : map.entrySet()){

                             parameters.add(new BasicNameValuePair(entry.getKey(),String.valueOf(entry.getValue())));

                    }

                   HttpGet httpGet = new HttpGet(uri);

                   String param = null;

                   try{

                            param = EntityUtils.toString(new UrlEncodedFormEntity(parameters));

                            //build get uri with params

                            httpGet.setURI(new URIBuilder(httpGet.getURI().toString() + "?" + param).build());

                   }catch(Exception e){

                            e.printStackTrace();

                   }

                   return sendHttpGet(httpGet);

         }

        

         /**

          * 无参POST请求

          * @param uri

          * @return

          */

         public CloseableHttpResponse doPost(String uri){

                   HttpPost httpPost = new HttpPost(uri);

                   return sendHttpPost(httpPost);

         }

        

         /**

          * 发送post请求,参数用map接收

          * @param url 地址

          * @param map 参数

          * @return 返回值

          */

         public CloseableHttpResponse doPost(String url,Map map) {

                   HttpPost post = new HttpPost(url);

                   List pairs = new ArrayList();

                   for(Map.Entry entry : map.entrySet()){

                            pairs.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));

                   }

                   try {

                            post.setEntity(new UrlEncodedFormEntity(pairs,"UTF-8"));

                   } catch (UnsupportedEncodingException e) {

                            e.printStackTrace();

                   }

                   return sendHttpPost(post);

         }

        

         /**

          * POST发送xml文件

          * @param uri

          * @param reqXml

          * @return

          */

         public CloseableHttpResponse doPost(String uri, String reqXml){

                   HttpPost httpPost = new HttpPost(uri);

                   httpPost.addHeader("Content-Type", "application/xml");

                   StringEntity entity = null;

                   try{

                            entity = new StringEntity(reqXml, "UTF-8");

                   }catch(Exception e){

                            e.printStackTrace();

                   }

                   //http post with xml data

                   httpPost.setEntity(entity);

                   return sendHttpPost(httpPost);

         }

        

         /**

          *

          * @param uri

          * @param map

          * @return

          */

         public String doPut(String uri, Map map){

                  List parameters = new ArrayList();

                  for(Map.Entry entry : map.entrySet()){

                             parameters.add(new BasicNameValuePair(entry.getKey(),String.valueOf(entry.getValue())));

                   }

                  

                   HttpPut httpPut = new HttpPut(uri);

                   String param = null;

                   try{

                            param = EntityUtils.toString(new UrlEncodedFormEntity(parameters));

                            httpPut.setURI(new URIBuilder(httpPut.getURI().toString() + "?" + param).build());

                   }catch(Exception e){

                            e.printStackTrace();

                   }

                   return sendHttpPut(httpPut);

         }

        

         private CloseableHttpResponse sendHttpPost(HttpPost httpPost){

                  

//                HttpEntity entity = null;

//                String responseContent = null;

                   try{

                            httpClient = HttpClients.createDefault();

//                         httpPost.setConfig(config);

                            response = httpClient.execute(httpPost);

//                         int status = response.getStatusLine().getStatusCode();

//                         if(status == 200) {//支付成功

//                                   entity = response.getEntity();

//                                   responseContent = EntityUtils.toString(entity, "UTF-8");

//                         }

                           

                   }catch (Exception e) {

                            e.printStackTrace();

                   }

                  

                   return response;

         }

        

         private String sendHttpGet(HttpGet httpGet){

//                CloseableHttpClient httpClient = null;

//                CloseableHttpResponse response = null;

                   HttpEntity entity = null;

                   String responseContent = null;

                   try{

                            httpClient = HttpClients.createDefault();

//                         httpGet.setConfig(config);

                            response = httpClient.execute(httpGet);

                            entity = response.getEntity();

                            responseContent = EntityUtils.toString(entity, "UTF-8");

                   }catch(Exception e){

                            e.printStackTrace();

                   }finally{

//                         try{

//                                   if(response != null)

//                                            response.close();

//                                   if(httpClient != null)

//                                            httpClient.close();

//                         }catch(IOException e){

//                                   e.printStackTrace();

//                         }

                   }

                   return responseContent;

         }

        

        

         private String sendHttpPut(HttpPut httpPut){

//                CloseableHttpClient httpClient = null;

//                CloseableHttpResponse response = null;

                   HttpEntity entity = null;

                   String responseContent = null;

                   try{

                            httpClient = HttpClients.createDefault();

//                         httpPut.setConfig(config);

                            response = httpClient.execute(httpPut);

                            entity = response.getEntity();

                            responseContent = EntityUtils.toString(entity, "UTF-8");

                   }catch(Exception e){

                            e.printStackTrace();

                   }

                   return responseContent;

         }

        

         public String getRequestResult(CloseableHttpResponse response) {

                   HttpEntity entity = null;

                   String responseContent = null;

                   int status = response.getStatusLine().getStatusCode();

                   if(status == HttpClient.SUCCESS) {//支付成功

                            entity = response.getEntity();

                            try {

                                     responseContent = EntityUtils.toString(entity, "UTF-8");

                            } catch (ParseException | IOException e) {

                                     e.printStackTrace();

                            }finally {

                                     try{

                                               if(response != null)

                                                        response.close();

                                               if(httpClient !=null)

                                                        httpClient.close();

                                     }catch(IOException e){

                                               e.printStackTrace();

                                     }

                            }

                   }

                   return responseContent;

         }

 

}

  1. XMLUtils

package com.will.wang.utils;

 

import java.io.ByteArrayInputStream;

import java.io.IOException;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

 

import org.dom4j.Document;

import org.dom4j.Element;

import org.dom4j.io.SAXReader;

import org.springframework.stereotype.Component;

 

@Component

public class XMLUtils {

 

         /**

          * Mapxml字符串

          * @param params

          * @return

          */

         public String doMapToXML(Map params) {

                   StringBuilder xml = new StringBuilder();

                   xml.append("\n");

                   for (Map.Entry entry : params.entrySet()) {

                                     xml.append("<" + entry.getKey() + ">").append(entry.getValue()).append(" + entry.getKey() + ">\n");

                   }

                   xml.append("");

                   return null;

         }

        

         /**

          * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。

          * @param strxml

          * @return

          * @throws JDOMException

          * @throws IOException

          */

         public Map doXMLParse(String strxml) throws IOException{

                   if(null == strxml || "".equals(strxml)) {

                            return null;

                   }

                   Map m = new HashMap();

                   try {

// 创建saxReader对象 

                      SAXReader reader = new SAXReader(); 

                      // 通过read方法读取一个文件 转换成Document对象 

                      Document document = reader.read(new ByteArrayInputStream(strxml.getBytes("UTF-8"))); 

                        //获取根节点元素对象 

                            Element node = document.getRootElement();

m = parse(node, m);

                   } catch (Exception e) {

                            e.printStackTrace();

                   }

                   return m;

         }

        

        

         private Map parse(Element node, Map m) { 

                  m.put(node.getName(), node.getTextTrim());

               // 当前节点下面子节点迭代器 

     Iterator it = node.elementIterator()

               // 遍历 

while (it.hasNext()) { 

            // 获取某个子节点对象 

            Element e = it.next(); 

            // 对子节点进行遍历 

            parse(e,m); 

        } 

        return m;

    } 

}

  1. WeChatPayController

package com.will.wang.wechatPay.controller;

 

import java.util.HashMap;

import java.util.Map;

 

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.util.StringUtils;

import org.springframework.web.bind.annotation.RequestMapping;

 

import com.will.wang.utils.XMLUtils;

import com.will.wang.wechatPay.service.WeChatPayService;

import com.will.wang.wechatPay.utils.WeChatUtils;

 

 

@Controller

@RequestMapping("/weChatPay")

public class WeChatPayController {

        

         @Autowired

         private WeChatPayService weChatPayService;

         @Autowired

         private WeChatUtils weChatUtils;

         @Autowired

         private XMLUtils XMLUtils;

        

        

         @RequestMapping("/testWeChatPay")

         public String testWeChatPay(HttpServletRequest request) {

                   Double realAmount = 0.00;

                   //订单来源ip

                   String bill_create_ip = request.getRemoteAddr();

                   String realAmountStr = request.getParameter("realAmount");

                   if(StringUtils.isEmpty(realAmountStr)) {

                            realAmount = 0.01;//此处应该返回页面错误信息

                   }

                  

                   String mweb_url = weChatPayService.testWeChatPay(bill_create_ip, realAmount);

                  

                   return mweb_url;

         }

        

         @RequestMapping("/weChatPayResult")

         public void weChatPayResult(HttpServletRequest request,HttpServletResponse response) {

                   try {

                            //将微信的返回参数封装成map

                            Map reqData = weChatUtils.getWeChatReplay(request);

                           

                            String returnCode = String.valueOf(reqData.get("return_code"));

String resultCode = String.valueOf(reqData.get("result_code"));

                        if (WeChatUtils.SUCCESS.equals(returnCode) && WeChatUtils.SUCCESS.equals(resultCode)) {

                     boolean signatureValid = weChatPayService.orderQuery(reqData);

                     if (signatureValid) {

                         // TODO 业务处理

        

                         Map responseMap = new HashMap<>(2);

                         responseMap.put("return_code", "SUCCESS");

                         responseMap.put("return_msg", "OK");

                         String responseXml = XMLUtils.doMapToXML(responseMap);

        

                         response.setContentType("text/xml");

                         response.getWriter().write(responseXml);

                         response.flushBuffer();

                     }

                 }

                   }catch(Exception e) {

                            e.printStackTrace();

                   }

         }

}

  1. WeChatPayServiceImpl

package com.will.wang.wechatPay.service.impl;

 

import java.util.Map;

 

import org.apache.http.client.methods.CloseableHttpResponse;

import org.apache.juli.logging.Log;

import org.apache.juli.logging.LogFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

 

import com.will.wang.utils.XMLUtils;

import com.will.wang.utils.http.HttpClient;

import com.will.wang.wechatPay.service.WeChatPayService;

import com.will.wang.wechatPay.utils.WeChatPropertyConfig;

import com.will.wang.wechatPay.utils.WeChatUtils;

 

@Service

public class WeChatPayServiceImpl implements WeChatPayService {

        

         Log log = LogFactory.getLog(WeChatPayServiceImpl.class);

 

         @Autowired

         private WeChatPropertyConfig weChatPropertyConfig;

         @Autowired

         private HttpClient httpRequest;

         @Autowired

         private XMLUtils XMLUtils;

         @Autowired

         private WeChatUtils weChatUtils;

        

         public boolean orderQuery(Map reqData) {

                   String xmlBody = weChatUtils.packageOrderQueryXml(reqData);

                   //查询订单

                   CloseableHttpResponse response = httpRequest.doPost(weChatPropertyConfig.getOrderquery(), xmlBody);

                   int status = response.getStatusLine().getStatusCode();

                   try {

                            if(status == HttpClient.SUCCESS) {

                                     //开始解析这个返回结果,取到需要的东西

                                     String httpResult = httpRequest.getRequestResult(response);

                                      // 过滤

                                     httpResult = httpResult.replaceAll("", "");

                     Map map = XMLUtils.doXMLParse(httpResult);

                     String return_code = String.valueOf(map.get("return_code"));

                     if("SUCCESS".equals(return_code)) {

                                      //此处添加支付成功后,支付金额和实际订单金额是否等价,防止钓鱼

                             if (map.get("openid") != null && map.get("trade_type") !=null) {

                                 String total_fee = String.valueOf(map.get("total_fee"));

                                 String order_total_fee = String.valueOf(map.get("total_fee"));

                                 if (Integer.parseInt(order_total_fee) >= Integer.parseInt(total_fee)) {

                                     return true;

                                 }

                             }

                     }

                            }

                   }catch(Exception e) {

                            e.printStackTrace();

                            log.error(e.getMessage());

                   }

                  

                   return false;

         }

        

         @Override

         public String testWeChatPay(String bill_create_ip, Double realAmount) {

                   String mweb_url = null;

                   try {

                            //TODO 产生订单,插入数据库状态为支付中

                           

                            // 将订单参数封装之后给微信

                            String prePayXml = weChatUtils.packageParam(bill_create_ip, realAmount);

                           

                            CloseableHttpResponse response = httpRequest.doPost(weChatPropertyConfig.getUnifiedorder(), prePayXml);

                            int status = response.getStatusLine().getStatusCode();

                            if(status == HttpClient.SUCCESS) {

                                     //开始解析这个返回结果,取到需要的东西

                                     String httpResult = httpRequest.getRequestResult(response);

                                      // 过滤

                                     httpResult = httpResult.replaceAll("", "");

                     Map map = XMLUtils.doXMLParse(httpResult);

                     String return_code = String.valueOf(map.get("return_code"));

                     if("SUCCESS".equals(return_code)) {

                             //解析mweb_url

                             mweb_url = String.valueOf(map.get("mweb_url"));

                               mweb_url = mweb_url.replaceAll("&", "&");

                               System.out.println(httpResult);

                     }else {

                             log.error(map.get("return_msg"));

                     }

                            }

                           

                   } catch (Exception e) {

                            e.printStackTrace();

                            log.error(e.getMessage());

                   }

                  

                   return mweb_url;

                  

         }

}

三:编写页面

  1. 引入jquery

在resource/static下新建js文件夹增加jquery-3.3.1.js

  1. 编写html页面

在resource/templates下新增支付页面和回调页面

  1. H5Pay.html

DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>

    <meta http-equiv="Content-Type" content="text/html; charset= UTF-8"/>

    <title>Titletitle>

head>

<body style="font-size: 30px">

 

<h3><span th:text="${message}">购买商品:生活费span>h3>

<h3><span th:text="${price}">价格:0.01span>h3>

<h3><span th:text="${num}">数量:10个span>h3>

 

<button style="width: 100%; height: 60px; alignment: center; background: #b49e8f" onclick="commitOrder()">提交订单button>

 

<script src="../static/js/jquery-3.3.1.js">script>

<script>

    function commitOrder() {

        $.ajax({

            type: "POST",

            url: "http://localhost:8080/weChatPay/testWeChatPay",

            data: null,

            success: function(data) {

                console.log(data);

                var redirectUrl = "http://localhost:8080/weChatPay/weChatPayResult";

                var mwebUrl = data.mweb_url+"&redirect_url="+encodeURIComponent(redirectUrl);

                window.location.href=mwebUrl;

            }

 

        })

    }

script>

 

body>

htm>

  1. H5PaySuccess.html

DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>

    <meta  http-equiv="Content-Type" content="text/html;  charset=UTF-8"/>

    <title>Titletitle>

head>

<body>

<h1><span th:text="${message}">微信支付-H5支付成功span>h1>

body>

html>

附录

  1. Thymeleaf资料

https://www.codercto.com/a/9497.html

  1. 微信支付失败,返回invalid total_fee,原来是金额不能出现小数点

微信支付出现提示:get brand_wcpay_request:fail

支付结果返回:invalid total_fee

微信支付提交的金额是不能带小数点的,且是以分为单位,所以我们系统如果是以元为单位要处理下金额,即先乘以100,再去小数点

String.valueOf((int)Math.floor(amount*100))

  1. 回调页面

注意:

  1. 注意MWEB_URL是普通的链接,不是微信那种短链接(我在使用测试账号时就返回了短链接,没找到什么原因,估计使用真实账号,申请开通H5支付,然后做一些开发配置估计就正常了)
  2. 需对redirect_url进行urlencode处理
  3. 由于设置redirect_url,回跳指定页面的操作可能发生在:
    1. 微信支付中间页调起微信收银台后超过5
    2. 用户点击取消支付或支付完成后点完成按钮。因此无法保证页面回跳时,支付流程已结束,所以商户设置的redirect_url地址不能自动执行查单操作,应让用户去点击按钮触发查单操作。
  1. GitHub完整代码

https://github.com/wangweiye/willWangServer

  1. csdn代码包地址

https://download.csdn.net/download/wwy1219787539/10571210

你可能感兴趣的:(支付对接)