前言:

本文基于PC网站需要,所开发的微信Native网页支付,技术栈,后端包含JAVA、SpringBoot、Maven、Mybatis、Mysql,前端包含HTML5、JS、JQUERY、AJAX等

开发前准备:

1、申请APPID

申请方式:
第一种:微信小程序,请前往小程序平台申请
第二种:微信公众号,请前往公众平台申请
第三种:如果商户已拥有以上两种的其一,则可以前往开放平台申请

2、申请mchId

步骤:
1、首先前往商户号申请平台申请
2、其次申请成功后,微信官方会向申请时所填写的联系邮箱下发通知邮件,内容包含申请成功的mchid及其登录账号密码,亦可以,登录商户平台,在【账户中心】的商户信息哪里也可以看到
3、最后,请妥善保存2的信息
注意:一个mchid只能对应一个结算币种,若需要使用多个币种收款,需要申请对应数量的mchid。

3、绑定APPID及mchid

步骤:
1、登录微信商户平台,点击【产品中心】,在左侧点击【AppID账号管理】,然后再点击【我关联的AppID账号】,出现列表,然后点击【+关联AppID】,然后输入商户号,提交就完成第一步了。
2、登录微信公众平台(公众号,只有服务号才有微信支付,订阅号没有,望注意!),点击左侧“广告与服务->微信支付->商户号管理->待关联商户号”,然后在列表中找到确认信息,点击确认,即可完成绑定。

注意:只有服务号才有微信支付,订阅号没有,望注意!

提供流程图:
1、
image.png
2、
image.png
3、
image.png

4、去商户平台配置APIV3密钥

步骤:
1、登录微信商户平台,进入【账户中心 > API安全 】目录,设置APIV3密钥。

image.png
2、在弹出窗口中点击“已沟通”。

image.png
3、输入API密钥,内容为32位字符,包括数字及大小写字母。点击获取短信验证码。
MD5加密免费获取32位字符
image.png
4、输入短信验证码,点击“确认”即设置成功。

image.png
5、完成

5、下载并配置商户证书

步骤:
1、【商户平台】商户可登录微信商户平台,在【账户中心】->【API安全】->【申请证书】

image.png
2、【商户平台】在弹出窗口中点击“确定”。

image.png
3、【商户平台】在弹出窗口内点击“下载证书工具”按钮下载证书工具。

image.png
4、【证书工具】安装证书工具并打开,选择证书需要存储的路径后点击“申请证书”。

image.png
5、【证书工具】在证书工具中,将复制的商户信息粘贴并点击“下一步”。

image.png
6、获取请求串

【证书工具】中操作
image.png
【商户平台】中操作
image.png
【商户平台】中操作
image.png
7、【证书工具】复制证书串

image.png
8、【证书工具】粘贴证书串

image.png
9、【证书工具】生成证书成功

image.png
10、在【证书工具】-“生成证书”环节,已完成申请证书流程,点击“查看证书文件夹”,查看已生成的证书文件。

11、完成

注意:在前面带【商户平台】,意思是在商户平台中的操作,前面带【证书工具】,意思是在证书工具中操作,望勿弄混!

6、获取证书中的商户序列号,支付需要用到

步骤:
1、【商户平台】商户可登录微信商户平台,在【账户中心】->【API安全】->【管理证书】
2、打开的窗口,展示证书列表,第一列就是证书序列号,将其保存,以待后面用到。

正式开发步骤:

提要:步骤分的很细,很费心,但可以更直辩的理解!

1、Maven引入支付依赖包

<!--微信支付依赖包-->
<dependency>
    <groupId>com.github.wxpay</groupId>
    <artifactId>wxpay-sdk</artifactId>
    <version>0.0.3</version>
</dependency>

2、Maven引入支付签名、应答签名的验证封装依赖包

<!--微信支付签名、应答签名的验证封装包-->
<dependency>
    <groupId>com.github.wechatpay-apiv3</groupId>
    <artifactId>wechatpay-apache-httpclient</artifactId>
    <version>0.4.7</version>
</dependency>

3、Maven引入生成二维码的依赖包

<!--引入生成二维码的依赖-->
<!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.zxing/javase -->
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>javase</artifactId>
    <version>3.3.0</version>
</dependency>

4、创建微信支付工具类WeChatPayUtils.java

提要:本工具类:包含下单方法、查单方法,以及可能会用到的转换以及获取方法等

/**
 * 微信支付工具类
 * @date 2022/6/16
 * @author gxw
 */
public class WeChatPayUtils {
    /*公众号/小程序信息*/
    //appId
    private static final String APP_ID = PropertiesValues.getPropertiesValue("wx.pay.app_id", "application.properties");
    //secret
    private static final String APP_SECRET = "";

    /*商户信息*/
    //商户号mch_id
    private static final String MCH_ID = PropertiesValues.getPropertiesValue("wx.pay.mch_id", "application.properties");
    //商户私钥mch_key
    private static final String MCH_KEY = "下载证书的***key.pem文件内容";
    //商户证书序列号
    private static final String MCH_SERIAL_NO = PropertiesValues.getPropertiesValue("wx.pay.mch_serial_no", "application.properties");
    //API3私钥
    private static final String MCH_API_V3_KEY = PropertiesValues.getPropertiesValue("wx.pay.api_key", "application.properties");

    /*支付信息*/
    //native 统一下单API
    public static final String NATIVE_PAY_API = PropertiesValues.getPropertiesValue("wx.pay.native.url", "application.properties");
    //native 商户订单号查单API
    public static final String NATIVE_PAY_OUT_TRADE_NO_QUERY_ORDER_API = PropertiesValues.getPropertiesValue("wx.pay.out_trade_no.query_order", "application.properties");
    //native 微信系统订单号查单API
    public static final String NATIVE_PAY_TRANSACTIONS_ID_QUERY_ORDER_API = PropertiesValues.getPropertiesValue("wx.pay.transactions_id.query_order", "application.properties");
    //货币类型
    public static final String CURRENCY_CNY = "CNY";
    //支付类型
    public static final String TRADE_TYPE = "NATIVE";
    //异步回调地址
    public static final String NOTIFY_URL = PropertiesValues.getPropertiesValue("wx.pay.notify_url", "application.properties");

    /**
     * NATIVE获取CloseableHttpClient
     */
    private static CloseableHttpClient initHttpClient(){
        PrivateKey merchantPrivateKey = null;
        try {
            merchantPrivateKey = PemUtil
                    .loadPrivateKey(new ByteArrayInputStream(MCH_KEY.getBytes("utf-8")));
//            //*加载证书管理器实例*//*
//            // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
//            AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
//                    new WechatPay2Credentials(MCH_ID, new PrivateKeySigner(MCH_SERIAL_NO, merchantPrivateKey)),MCH_API_V3_KEY.getBytes("utf-8"));
//            //获取单例实例
            CertificatesManager certificatesManager = CertificatesManager.getInstance();
//            //向证书管理器增加商户信息,并开启自动更新
            certificatesManager.putMerchant(
                    MCH_ID,
                    new WechatPay2Credentials(
                            MCH_ID, new PrivateKeySigner(MCH_SERIAL_NO, merchantPrivateKey)),
                    MCH_API_V3_KEY.getBytes("utf-8")
            );
            //从证书管理器获得验签器
            Verifier verifier = certificatesManager.getVerifier(MCH_ID);
            CloseableHttpClient httpClient = WechatPayHttpClientBuilder.create()
                    .withMerchant(MCH_ID, MCH_SERIAL_NO, merchantPrivateKey)
                    .withValidator(new WechatPay2Validator(verifier)).build();
            return httpClient;
        } catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * NATIVE 统一下单
     * @param money
     * @param body
     * @return
     */
    public static Map<String, String> native_payment_order(String money, String body, String outTradeNo) {
        try {
            CloseableHttpClient httpClient = initHttpClient();

            HttpPost httpPost = new HttpPost(NATIVE_PAY_API);
            // 请求body参数
            String reqdata = "{"
                    //+ "\"time_expire\":\"2018-06-08T10:34:56+08:00\","
                    + "\"amount\": {"
                    + "\"total\":" + Integer.parseInt(String.valueOf(Float.parseFloat(money) * 100).split("\\.")[0]) + ","
                    + "\"currency\":\"" + CURRENCY_CNY + "\""
                    + "},"
                    + "\"mchid\":\"" + MCH_ID + "\","
                    + "\"description\":\"" + body + "\","
                    + "\"notify_url\":\"" + NOTIFY_URL + "\","
                    + "\"out_trade_no\":\"" + outTradeNo + "\","
                    + "\"goods_tag\":\"课程购买\","
                    + "\"appid\":\"" + APP_ID + "\""
                    + "}";
            StringEntity entity = new StringEntity(reqdata, "utf-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);
            httpPost.setHeader("Accept", "application/json");

            //完成签名并执行请求
            CloseableHttpResponse response = null;
            Map<String, String> resultMap = new HashMap<>();
            try {
                response = httpClient.execute(httpPost);

                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) { //处理成功
                    String codeUrl = EntityUtils.toString(response.getEntity());
                    codeUrl = codeUrl.substring(codeUrl.indexOf("w"), codeUrl.indexOf("}") - 1);
                    String path = QRCodeGenerator.generateQRCodeImage(codeUrl);
                    resultMap.put("code", "200");
                    resultMap.put("data", path);
                    System.out.println("生成成功,路径为:" + path);
                    System.out.println("success,return body = " + codeUrl);
                    return resultMap;
                } else if (statusCode == 204) { //处理成功,无返回Body
                    System.out.println("success");
                    resultMap.put("code", "204");
                    resultMap.put("msg", "处理成功,但无返回Body");
                    return resultMap;
                } else {
                    System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
                    throw new IOException("request failed");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                response.close();
            }
        }  catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * NATIVE 查询订单
     * @param outTradeNo 商户订单号
     * @return
     */
    public static Map<String, String> native_query_order(String outTradeNo) {
        CloseableHttpResponse response = null;
        try {
            String url = NATIVE_PAY_OUT_TRADE_NO_QUERY_ORDER_API + outTradeNo;
            //请求URL
            URIBuilder uriBuilder = new URIBuilder(url);

            uriBuilder.setParameter("mchid", MCH_ID);

            //完成签名并执行请求
            HttpGet httpGet = new HttpGet(uriBuilder.build());
            httpGet.addHeader("Accept", "application/json");
            response = initHttpClient().execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            Map<String, String> resultMap = new HashMap<>();
            if (statusCode == 200) {
                String resData = EntityUtils.toString(response.getEntity());
                Map<String, Object> data = JSON.parseObject(resData, HashMap.class);
                String tradeState = String.valueOf(data.get("trade_state"));
                if("SUCCESS".equals(tradeState)){
                    resultMap.put("msg", "支付成功");
                }else if("NOTPAY".equals(tradeState)){
                    resultMap.put("msg", "订单尚未支付");
                }else if("CLOSED".equals(tradeState)){
                    resultMap.put("msg", "此订单已关闭,请重新下单");
                }else if("USERPAYING".equals(tradeState)){
                    resultMap.put("msg", "正在支付中,请尽快支付完成哦");
                }else if("PAYERROR".equals(tradeState)){
                    resultMap.put("msg", "支付失败,请重新下单");
                }
                resultMap.put("code", "200");
                resultMap.put("tradeState", tradeState);
//                resultMap.put("openId", String.valueOf(JSON.parseObject(String.valueOf(data.get("payer")), HashMap.class).get("openid")));
//                resultMap.put("transactionId", String.valueOf(data.get("transaction_id")));
                return resultMap;
            } else if (statusCode == 204) {
                System.out.println("success");resultMap.put("code", "204");
                resultMap.put("msg", "处理成功,但无返回Body");
                return resultMap;
            } else {
                System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
                throw new IOException("request failed");
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * APIV3密钥版,NATIVE支付回调参数解密
     * @param map
     * @return
     */
    public static Map<String, Object> paramDecodeForAPIV3(Map<String, Object> map){
        //使用微信SDK提供的AesUtil工具类和APIV3密钥进行签名验证
        AesUtil aesUtil = new AesUtil(MCH_API_V3_KEY.getBytes(StandardCharsets.UTF_8));
        JSONObject paramsObj = new JSONObject(map);
        JSONObject rJ = paramsObj.getJSONObject("resource");
        Map<String, String> paramMap = (Map) rJ;
        try {
            //如果APIV3密钥和微信返回的resource中的信息不一致,是拿不到微信返回的支付信息
            String decryptToString = aesUtil.decryptToString(
                    paramMap.get("associated_data").getBytes(StandardCharsets.UTF_8),
                    paramMap.get("nonce").getBytes(StandardCharsets.UTF_8),
                    paramMap.get("ciphertext"));

            //验证成功后将获取的支付信息转为Map
            Map<String, Object> resultMap = WeChatPayUtils.strToMap(decryptToString);
            return resultMap;
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 交易起始时间
     */
    public static String getTimeStart(){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sdf.format(new Date());
    }

    /**
     * 交易结束时间(订单失效时间)
     * @return
     */
    public static String getTimeExpire(){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        Calendar now = Calendar.getInstance();
        now.add(Calendar.MINUTE, 30);
        return sdf.format(now.getTimeInMillis());
    }

    /**
     * 获取32位随机字符串
     * @return
     */
    public static String getRandomStr() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 生成订单号
     * @return
     */
    public static String generateOrderNo() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        return sdf.format(new Date()) + makeRandom(15);
    }

    /**
     * 生成随机数 纯数字
     *
     * @return
     */
    public static String makeRandom(int len) {
        return RandomUtils.generateRandomString(len);
    }

    /**
     * 将Map转换为XML格式的字符串
     *
     * @param data Map类型数据
     * @return XML格式的字符串
     * @throws Exception
     */
    public static String mapToXml(Map<String, String> data) throws Exception {
        org.w3c.dom.Document document = WXPayXmlUtil.newDocument();
        org.w3c.dom.Element root = document.createElement("xml");
        document.appendChild(root);
        for (String key: data.keySet()) {
            String value = data.get(key);
            if (value == null) {
                value = "";
            }
            value = value.trim();
            org.w3c.dom.Element filed = document.createElement(key);
            filed.appendChild(document.createTextNode(com.gxw.util.StringUtils.toUTF8(value)));
            root.appendChild(filed);
        }
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        DOMSource source = new DOMSource(document);
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        StringWriter writer = new StringWriter();
        StreamResult result = new StreamResult(writer);
        transformer.transform(source, result);
        String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
        try {
            writer.close();
        }
        catch (Exception ex) {
        }
        return output;
    }

    /**
     * Xml字符串转换为Map
     *
     * @param xmlStr
     * @return
     */
    public static Map<String, String> xmlStrToMap(String xmlStr) {
        Map<String, String> map = new HashMap<String, String>();
        Document doc;
        try {
            doc = DocumentHelper.parseText(xmlStr);
            Element root = doc.getRootElement();
            List children = root.elements();
            if (children != null && children.size() > 0) {
                for (int i = 0; i < children.size(); i++) {
                    Element child = (Element) children.get(i);
                    map.put(child.getName(), child.getTextTrim());
                }
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return map;
    }



    /**
     * 方法用途: 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序),并且生成url参数串<br>
     * 实现步骤: <br>
     *
     * @param paraMap    要排序的Map对象
     * @param urlEncode  是否需要URLENCODE
     * @param keyToLower 是否需要将Key转换为全小写
     *                   true:key转化成小写,false:不转化
     * @return
     */
    public static String formatUrlMap(Map<String, String> paraMap, boolean urlEncode, boolean keyToLower) {
        String buff = "";
        Map<String, String> tmpMap = paraMap;
        try {
            List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(tmpMap.entrySet());
            // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
            Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
                @Override
                public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
                    return (o1.getKey()).toString().compareTo(o2.getKey());
                }
            });
            // 构造URL 键值对的格式
            StringBuilder buf = new StringBuilder();
            for (Map.Entry<String, String> item : infoIds) {
                if (StringUtils.isNotBlank(item.getKey())) {
                    String key = item.getKey();
                    String val = item.getValue();
                    if (urlEncode) {
                        val = URLEncoder.encode(val, "utf-8");
                    }
                    if (keyToLower) {
                        buf.append(key.toLowerCase() + "=" + val);
                    } else {
                        buf.append(key + "=" + val);
                    }
                    buf.append("&");
                }

            }
            buff = buf.toString();
            if (buff.isEmpty() == false) {
                buff = buff.substring(0, buff.length() - 1);
            }
        } catch (Exception e) {
            return null;
        }
        return buff;
    }

    /**
     * 字符串转换为Map集合
     * @param str
     * @return
     */
    public static Map<String, Object> strToMap(String str){
        Map<String, Object> map = JSON.parseObject(str, HashedMap.class);
        return map;
    }


}

5、Controller支付下单接口

 /**
     * native 支付下单
     * @param request
     * @param lcGoodsOrder
     * @return
     */
    @RequestMapping("/nativePaymentOrder")
    @NoVerify
    public synchronized Map<String, String> nativePaymentOrder(
            HttpServletRequest request,
            @RequestBody LcGoodsOrder lcGoodsOrder){
        logger.info("【微信Native支付-支付下单】************开始处理*************");
        //商户订单号
        String outTradeNo = ALiPayUtils.generateOrderNum();
        Map<String, String> data = WeChatPayUtils.native_payment_order(lcGoodsOrder.getTotalAmount(), lcGoodsOrder.getSubject(), outTradeNo);
        if("200".equals(data.get("code"))){
            logger.info("【微信Native支付-支付下单】下单成功,下单用户:{}, 下单手机号:{}", lcGoodsOrder.getPayUserName(), lcGoodsOrder.getPayUserPhone());
            /*订单记录数据库中*/
            lcGoodsOrder.setOutTradeNo(outTradeNo);
            lcGoodsOrder.setPayType("1");//微信Native支付类型
            lcGoodsOrderService.wxInsert(lcGoodsOrder);
            /*处理返回前端需要数据*/
            data.put("outTradeNo", outTradeNo);
            data.put("payUserName", lcGoodsOrder.getPayUserName());
            data.put("payUserPhone", lcGoodsOrder.getPayUserPhone());
            data.put("totalAmount", lcGoodsOrder.getTotalAmount());

            return data;
        }
        logger.info("【微信Native支付-支付下单】下单失败,下单用户:{}, 下单手机号:{}", lcGoodsOrder.getPayUserName(), lcGoodsOrder.getPayUserPhone());
        logger.info("【微信Native支付-支付下单】************结束处理*************");
        return null;
    }

6、Controller支付回调接口

/**
     * native 异步回调处理方法
     * @param request
     * @return
     */
    @PostMapping("/nativeNotifyProcess")
    @NoVerify
    public synchronized String nativeNotifyProcess(
            HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        logger.info("【微信Native支付-支付回调】************开始处理*************");
        Map<String, Object> map = new ObjectMapper().readValue(request.getInputStream(), Map.class);
        logger.info("【微信Native支付-支付回调】返回结果:{}",map);
        Map<String, Object> dataMap = WeChatPayUtils.paramDecodeForAPIV3(map);
        //判断是否⽀付成功
        if("SUCCESS".equals(dataMap.get("trade_state"))){
            logger.info("【微信Native支付-支付回调】判断支付成功, 商户订单号:{}", dataMap.get("out_trade_no"));
            //支付成功,业务处理
            LcGoodsOrder lcGoodsOrder = new LcGoodsOrder();
            //商户订单号
            lcGoodsOrder.setOutTradeNo(String.valueOf(dataMap.get("out_trade_no")));
            //付款用户openId
            lcGoodsOrder.setWxOpenId(String.valueOf(JSON.parseObject(String.valueOf(dataMap.get("payer")), HashMap.class).get("openid")));
            //支付成功
            lcGoodsOrder.setOrderStatus("2");
            //微信系统生成的订单号
            lcGoodsOrder.setWxSysOrderNo(String.valueOf(dataMap.get("transaction_id")));
            //修改订单信息
            lcGoodsOrderService.updateById(lcGoodsOrder);

            //给微信发送我已接收通知的响应
            //创建给微信响应的对象
            Map<String, String> returnMap = new HashMap<>();
            returnMap.put("code", "SUCCESS");
            returnMap.put("message", "成功");
            //将返回微信的对象转换为xml
            String returnXml = WeChatPayUtils.mapToXml(returnMap);
            logger.info("【微信Native支付-支付回调】微信Native支付成功,并且给微信返回响应数据!, 商户订单号:{}", dataMap.get("out_trade_no"));
            return returnXml;
        }
        //支付失败
        //创建给微信响应的对象
        Map<String, String> returnMap = new HashMap<>();
        returnMap.put("code", "FALL");
        returnMap.put("message", "");
        //将返回微信的对象转换为xml
        String returnXml = WeChatPayUtils.mapToXml(returnMap);
        logger.info("【微信Native支付-支付回调】判断支付失败, 商户订单号:{}", dataMap.get("out_trade_no"));
        logger.info("【微信Native支付-支付回调】************结束处理*************");
        return returnXml;
    }

7、Controller查询订单接口

/**
     * native 支付查单,通过商户订单号查询订单状态
     * @param lcGoodsOrder
     * @return
     */
    @RequestMapping("/nativeQueryOrder")
    @NoVerify
    public synchronized Map<String, String> nativeQueryOrder(
            @RequestBody LcGoodsOrder lcGoodsOrder){
        logger.info("【微信Native支付-商户订单号查单】************开始处理*************,商户订单号:{}", lcGoodsOrder.getOutTradeNo());
        Map<String, String> data = WeChatPayUtils.native_query_order(lcGoodsOrder.getOutTradeNo());
        //判断查单是否成功
        if("200".equals(data.get("code"))){
            logger.info("【微信Native支付-商户订单号查单】查单成功,商户订单号:{}", lcGoodsOrder.getOutTradeNo());
            //判断查询订单是否支付成功
            if("SUCCESS".equals(data.get("tradeState"))){
                logger.info("【微信Native支付-商户订单号查单-支付成功】查单结果支付成功,商户订单号:{}", lcGoodsOrder.getOutTradeNo());
                ResultMap resultMap = lcGoodsOrderService.selectByType("outTradeNo", lcGoodsOrder.getOutTradeNo());
                //判断数据库订单查询是否成功
                if("200".equals(resultMap.getCode())){
                    logger.info("【微信Native支付-商户订单号查单-数据库数据验证】数据库订单数据查询成功,商户订单号:{}", lcGoodsOrder.getOutTradeNo());
                    LcGoodsOrder lcGoodsOrder1 = (LcGoodsOrder) resultMap.getData();
                    //如果数据库数据尚未修改订单为完成状态,则进行修改
                    if(lcGoodsOrder1.getOrderStatus().equals("1")){
                        logger.info("【微信Native支付-商户订单号查单-数据库数据验证】数据库订单数据尚未确认订单完成,商户订单号:{}", lcGoodsOrder.getOutTradeNo());
                        //付款用户openId
                        lcGoodsOrder.setWxOpenId(data.get("openId"));
                        //支付成功
                        lcGoodsOrder.setOrderStatus("2");
                        //微信系统生成的订单号
                        lcGoodsOrder.setWxSysOrderNo(data.get("transactionId"));
                        lcGoodsOrderService.updateById(lcGoodsOrder);
                        logger.info("【微信Native支付-商户订单号查单-数据库数据验证】数据库订单数据确认订单完成,商户订单号:{}", lcGoodsOrder.getOutTradeNo());
                    }
                }
            }
//            data.remove("openId");
//            data.remove("transactionId");
            logger.info("【微信Native支付-商户订单号查单】************结束处理*************,商户订单号:{}", lcGoodsOrder.getOutTradeNo());
            return data;
        }
        return null;
    }

8、PC网站页面调用下单接口

/**
 * 调用微信支付接口
 * @param {Object} data
 * @autors gxw
 */
function wechatPay(data){
    var url = "http://127.0.0.1:8686/lcWeChataPay/nativePaymentOrder";
    $.ajax({
        url: url,
        type: 'post',
        data: JSON.stringify({
            payUserName: data.payUserName,
            payUserPhone: data.payUserPhone,
            payMessage: data.payMessage,
            goodsId: data.goodsId,
            totalAmount: data.totalAmount,
            subject: data.subject,
        }),
        contentType: "application/json",
        dataType: 'json',
        success: function(res){
            if(res != null){
                if(res.code == "200"){
                    window.location.href = "wx_pay.html?otn="+res.outTradeNo
                    +"&pun="+encodeURI(res.payUserName)
                    +"&pup="+res.payUserPhone
                    +"&codePath="+res.data
                    +"&m="+res.totalAmount
                }else{
                    alert("网络异常");
                    alert(res.msg);
                }
            }else{
                alert("网络异常,确认网络无问题,请刷新页面!");
            }
            
        },
        fail: function(res){
            console.log("失败")
            console.log(res);
        }
      })
}

9、支付完成,点击已支付,调用查单接口,判断是否支付成功,成功,则跳转到成功页面

        /**
         * 查询订单,检验订单状态
         * @autors gxw
         */
        function checkPayStatus(){
            var url = "http://127.0.0.1:8686/lcWeChataPay/nativeQueryOrder";
            $.ajax({
                url: url,
                type: 'post',
                data: JSON.stringify({
                    outTradeNo: otn
                }),
                contentType: "application/json",
                dataType: 'json',
                success: function(res){
                    if(res != null){
                        if(res.code == "200"){
                            if(res.tradeState == "SUCCESS"){
                                window.location.href = "pay_success.html?otn="+otn
                                +"&pun="+encodeURI(pun)
                                +"&pup="+pup
                                +"&m="+m
                            }else{
                                alert(res.msg);
                                return false;
                            }
                        }else{
                            alert("网络异常");
                            alert(res.msg);
                        }
                    }else{
                        alert("网络异常,确认网络无问题,请刷新页面!");
                    }
                    
                },
                fail: function(res){
                    console.log("失败")
                    console.log(res);
                }
              })
        }

10、这样PC网站微信NATIVE网页支付,即可完成!

=========================但这还没有结束====================

在这个章节第4条,微信支付工具类里面,有需要生成二维码的一段代码引用
image.png
但,这块生成二维码代码工具类尚未提供,所以下面的地址,就是你想的那样哟!
== https://segmentfault.com/a/11... ==
也可以点击二维码工具类代码这里哟

遇到问题:

1、the trustAnchors parameter must be non-empty

原因:
遇到JDK8/jre/lib/security/cacerts因证书过期或不存在导致

解决:
将C盘的**\jre\lib\security(这个路径前面各有不同,但后缀几个文件目录都一样,也可以直接在C盘搜索栏搜索”cacerts”,也可以找到)下的cacerts替换掉JDK8下路径的cacerts即可。

2、java.security.InvalidKeyException: Illegal key size

原因:
为了数据代码在传输过程中的安全,很多时候我们都会将要传输的数据进行加密,然后等对方拿到后再解密使用。我们在使用AES加解密的时候,在遇到128位密钥加解密的时候,没有进行什么特殊处理;然而,在使用256位密钥加解密的时候,如果不进行特殊处理的话,往往会出现这个异常java.security.InvalidKeyException: Illegal key size。

解决:
去官方下载JCE无限制权限策略文件。

jdk5:http://www.oracle.com/technet...

jdk6:http://www.oracle.com/technet...

JDK7:http://www.oracle.com/technet...
JDK8:http://www.oracle.com/technet...

下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt
如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件。

如果安装了JDK,还要将两个jar文件也放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件。

==================== 分享 =====================
JDK8 JCE无限制权限策略文件:
百度网盘链接:https://pan.baidu.com/s/11vPh...
提取码:tnc7


稳之楠
130 声望25 粉丝

行之稳,为之楠!