微信支付---H5支付(JAVA)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/grq15203514615/article/details/85789523

H5支付
已上传至github库 https://github.com/gaoruiqiang2017/weixinpay.git

1、用户在商户侧完成下单,使用微信支付进行支付
2、由商户后台向微信支付发起下单请求(调用统一下单接口)注:交易类型trade_type=MWEB
3、统一下单接口返回支付相关参数给商户后台,如支付跳转url(参数名“mweb_url”),商户通过mweb_url调起微信支付中间页
4、中间页进行H5权限的校验,安全性检查(此处常见错误请见下文)
5、如支付成功,商户后台会接收到微信侧的异步通知
6、用户在微信支付收银台完成支付或取消支付,返回商户页面(默认为返回支付发起页面)
7、商户在展示页面,引导用户主动发起支付结果的查询
8,9、商户后台判断是否接到收微信侧的支付结果通知,如没有,后台调用我们的订单查询接口确认订单状态
10、展示最终的订单支付结果给用户

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.weixinpay</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--微信支付SDK-->
        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.5</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>

        <finalName>demo</finalName>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/*.properties</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>false</filtering>
                <includes>
                    <include>**</include>
                </includes>
            </resource>
        </resources>
    </build>

</project>

util

/**
 * @Description
 * @Date:03
 */
public class HttpUtil {

    public static String doPost(String url, String requestXml) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse httpResponse = null;
        //创建httpClient连接对象
        httpClient = HttpClients.createDefault();
        //创建post请求连接对象
        HttpPost httpPost = new HttpPost(url);
        //创建连接请求对象,并设置连接参数
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(15000)   //连接服务区主机超时时间
                .setConnectionRequestTimeout(60000) //连接请求超时时间
                .setSocketTimeout(60000).build(); //设置读取响应数据超时时间
        //为httppost请求设置参数
        httpPost.setConfig(requestConfig);
        //将上传参数放到entity属性中
        httpPost.setEntity(new StringEntity(requestXml, "UTF-8"));
        //添加头信息
        httpPost.addHeader("Content-type", "text/xml");
        String result = "";
        try {
            //发送请求
            httpResponse = httpClient.execute(httpPost);
            //从相应对象中获取返回内容
            HttpEntity entity = httpResponse.getEntity();
            result = EntityUtils.toString(entity, "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;

    }

    /**
     * 获取IP地址
     *
     * @param request
     * @return
     */
    public static String getIpAddress(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.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

properties

appid=wx12822223?22sss
mchId=149232323312333sss
weixinKey=34234234er2werwerwer
unifiedorderUrl=https://api.mch.weixin.qq.com/pay/unifiedorder

接口

/**
 * @Description
 * @Date:03
 */
@RestController
@RequestMapping("/weixinH5pay")
public class WeixinH5pay {

    @Value("${appid}")
    private String appid;  //公众账号id

    @Value("${mchid}")
    private String mchId;  //商户号

    @Value("${weixinKey}")
    private String weixinKey;  //密匙

    @Value("${unifiedorderUrl}")
    private String unifiedorderUrl; //统一下单接口

    /**
     * @param httpServletRequest
     * @param httpServletResponse
     * @param orderNo             订单号(统一下单接口前自己要又订单)
     * @param money               金额
     * @param body                商品内容
     */
    @RequestMapping("/h5pay")
    public void h5pay(HttpServletRequest httpServletRequest, HttpServletResponse
            httpServletResponse, String orderNo, String money, String body, Writer writer)
            throws Exception {
        String mapStr = "";
        try {
            HashMap<String, String> dataMap = new HashMap<>();
            dataMap.put("appid", appid); //公众账号ID
            dataMap.put("mch_id", mchId); //商户号
            dataMap.put("nonce_str", WXPayUtil.generateNonceStr()); //随机字符串,长度要求在32位以内。
            dataMap.put("body", body); //商品描述
            dataMap.put("out_trade_no", orderNo); //商品订单号
            dataMap.put("total_fee", money); //商品金
            dataMap.put("spbill_create_ip", HttpUtil.getIpAddress(httpServletRequest)); //客户端ip
            dataMap.put("notify_url", "www.baidu.com"); //通知地址(假设是百度)
            dataMap.put("trade_type", "MWEB"); //交易类型
         //   dataMap.put("scene_info", "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\":
            // \"http://www" +
           //         ".baidu.com\",\"wap_name\": \"学易资源分享平台\"}}"); //场景信息(其实不写能用)
            //生成签名
            String signature = WXPayUtil.generateSignature(dataMap, weixinKey);
            dataMap.put("sign", signature);//签名
            //将类型为map的参数转换为xml
            String requestXml = WXPayUtil.mapToXml(dataMap);
            //发送参数,调用微信统一下单接口,返回xml
            String responseXml = HttpUtil.doPost(unifiedorderUrl, requestXml);
            System.out.print(responseXml);
            Map<String, String> map = WXPayUtil.xmlToMap(responseXml);
            if ("FAIL".equals(map.get("return_code"))) {
                mapStr = map.get("return_msg");
                writer.write(mapStr);
                return;
            }
            if ("FAIL".equals(map.get("result_code"))) {
                mapStr = map.get("err_code_des");
                writer.write(mapStr);
                return;
            }
            if (map.get("mweb_url") == null || "".equals(map.get("mweb_url"))) {
                mapStr = "mweb_url为null";
                writer.write(mapStr);
                return;
            }
            //成功返回了mweb_url,拼接支付成功后微信跳转自定义页面
            //确认支付过后跳的地址redirectUrl,需要经过urlencode处理(可以不写,会跳转默认原吊起微信的页面
            // 写了之后前端接收订单id后再传给后端,处理订单状态)

            //String redirectUrl = "http://www.xxxx.com/xxxxx/my_waRecord.html?orderNo=" + orderNo;
            //redirectUrl = URLEncoder.encode(redirectUrl, "utf-8");
            String url = map.get("mweb_url");//+ "&redirect_url=" + redirectUrl;
            //自动跳转微信
            StringBuilder urlHtml = new StringBuilder();
            urlHtml.append("<form id=\"weixinPay\" name=\"weixinPay\" action=\"" + url + "\" " +
                    "method=\"" + "post" + "\">");
            urlHtml.append("<input type=\"submit\" value=\"" + "payButton" + "\" " +
                    "style=\"display:none;\"></form>");
            urlHtml.append("<script>document.forms['weixinPay'].submit();</script>");
            httpServletResponse.setContentType("text/html;charset=utf-8");
            httpServletResponse.getWriter().write(urlHtml.toString());
            httpServletResponse.getWriter().flush();
        } catch (Exception e) {
            mapStr = "异常";
        }
        writer.write(mapStr);
    }
    
    /**
     * 异步回调(必须有,得发布到外网)
     *
     * @param unifiedorderUrl
     * @param requestXml
     * @return
     */
    @RequestMapping("/notifyUrl")
    public String notifyUrl(String unifiedorderUrl, String requestXml) {
        System.out.print("进入支付h5回调=====================");
        //如果没有加redirectUrl,就这这个接口处理订单信息
        //判断接受到的result_code是不是SUCCESS,如果是,则返回成功,具体业务具体分析
        return "success";
    }
}

常见问题
一、回调页面

正常流程用户支付完成后会返回至发起支付的页面,如需返回至指定页面,则可以在MWEB_URL后拼接上redirect_url参数,来指定回调页面。

如,您希望用户支付完成后跳转至https://www.wechatpay.com.cn,则可以做如下处理:

假设您通过统一下单接口获到的MWEB_URL= https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096

则拼接后的地址为MWEB_URL= https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096&redirect_url=https%3A%2F%2Fwww.wechatpay.com.cn

注意:
1.需对redirect_url进行urlencode处理

2.由于设置redirect_url后,回跳指定页面的操作可能发生在:1,微信支付中间页调起微信收银台后超过5秒 2,用户点击“取消支付“或支付完成后点“完成”按钮。因此无法保证页面回跳时,支付流程已结束,所以商户设置的redirect_url地址不能自动执行查单操作,应让用户去点击按钮触发查单操作。

分享个别人的连接

h5支付

猜你喜欢

转载自blog.csdn.net/grq15203514615/article/details/85789523