IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 微信支付(app+小程序)--用java -> 正文阅读

[移动开发]微信支付(app+小程序)--用java

app微信支付

pom依赖

        <!--微信支付-->
        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.jodd</groupId>
            <artifactId>jodd-core</artifactId>
            <version>5.1.5</version>
        </dependency>

        <dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-apache-httpclient</artifactId>
            <version>0.2.1</version>
        </dependency>

yml中的相关的配置

?实现类里的具体内容,(一般流程是,要调用预下单接口,然后返回给安卓的二次签名,安卓拿着二次签名去拉起微信支付,如果成功拉起支付,就可以付款,付款成功以后,就会主动回调咱们自己写的回调接口,修改业务逻辑,最后完成此次支付)

预下单接口

   @Value("${ayj.wechat.notifyUrlMall}")
    private String notifyUrlMall;

    @Value("${ayj.wechat.notifyUrlMiniMall}")
    private String notifyUrlMiniMall;


    @Value("${ayj.wechat.appId}")
    private String appId;

    @Value("${ayj.wechat.miniAppId}")
    private String miniAppId;

    @Value("${ayj.wechat.mchId}")
    private String mchId;

    @Value("${ayj.wechat.bodyMall}")
    private String bodyMall;

    @Value("${ayj.wechat.bodyCharity}")
    private String  bodyCharity;

    @Value("${ayj.wechat.key}")
    private String key;


    @Value("${ayj.wechat.feeType}")
    private String feeType;

    @Value("${ayj.wechat.tradeType}")
    private String tradeType;

    @Value("${ayj.wechat.miniTradeType}")
    private String miniTradeType;

    @Value("${ayj.wechat.package}")
    private String wxPackage;


/**
     * 预下单接口--商城-app
     *
     * @return
     */
    @Override
    public R<WXPaymentResponseDto> prePayMall(Integer userId, Integer orderId,BigDecimal money) {
        int penny = money.multiply(new BigDecimal("100")).intValue();//已分为单位
        Map<String, String> resp = new HashMap<>();
        try {
            WXPay wxpay = appConfigService.myWXPay();
            SortedMap<String, String> data = new TreeMap<String, String>();
            data.put("appid", appId);//微信支付id
            data.put("mch_id", mchId);//商户号
            data.put("nonce_str", WXPayUtil.generateNonceStr());
            data.put("sign_type", "MD5");
            data.put("body", bodyMall);
            data.put("out_trade_no", OrderNoUtil.getOrderId());//订单号
            data.put("fee_type", feeType);// 金额类型	默认CNY
            data.put("total_fee", penny+"");//订单处理金额
            data.put("notify_url", notifyUrlMall);//支付成功以后调用的地址
            data.put("trade_type", tradeType);  // 此处指定为app支付
           // data.put("profit_sharing","Y");//分账
            //生成签名--一次签名,在预下单之前
            String characterEncoding = "UTF-8";
           String oneSign=  createSign(characterEncoding,data,key);
            data.put("sign",oneSign);
            resp = wxpay.unifiedOrder(data);
            log.info("微信预下单返回的对象:", resp);
            if (resp.get("return_code").equals("SUCCESS")) {
                log.info("微信预下单成功!");
                //生成微信预下单对象
                WXPrePay prePay = new WXPrePay();
                prePay.setMemberId(userId);//用户id
                prePay.setOrderNo(data.get("out_trade_no"));//支付订单单号
                prePay.setOrderId(orderId);//项目自增id
                prePay.setOrderType(MallEmums.PRE_PAY_TYPE_MALL.getCode());//订单类型
                prePay.setTotalAmount(penny);//金额
                baseMapper.insert(prePay);
                //返回WXPaymentResponseDto对象给前端
                WXPaymentResponseDto dto = new WXPaymentResponseDto();
                dto.setNonceStr(resp.get("nonce_str"));
                dto.setPrepayId(resp.get("prepay_id"));
                dto.setPartnerId(mchId); //商户id
                dto.setAppId(appId); //商户id
                dto.setWxPackage(wxPackage);
                String time = new Date().getTime()+"";
                dto.setTimestamp(time.substring(0,10));
                //统一下单以后,生成的二次签名
                Map<String, String> signmap = new TreeMap<>();
                signmap.put("appid",appId);
                signmap.put("noncestr",resp.get("nonce_str"));
                signmap.put("package",wxPackage);
                signmap.put("partnerid",mchId);
                signmap.put("prepayid",resp.get("prepay_id"));
               // signmap.put("signtype","MD5");
                signmap.put("timestamp",time.substring(0,10));//官网上写到,时间戳要十位并且精确到秒,平常使用的时间戳都是毫秒13位
                String sign = WxUtils.createSign(characterEncoding,signmap,key);
                System.out.println("二次签名:"+sign);
                dto.setSign(sign.substring(0,30)); //注意,就是这里,为什么是截取签名的前30位,正常生成的签名是32位,这是个坑,我被困扰很久,一会附上图片,告诉大家

                return R.success(dto);
            }
            log.info("微信预下单失败:",resp.get("return_msg"));
            return R.fail("微信预下单失败:"+resp.get("return_msg"));
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail("微信预下单失败:"+resp.get("return_msg"));
        }
    }



在这里给大家附上图片,我被这个二次签名困扰48小时,每次安卓一拉起微信支付,就报错,说是签名错误,我就百度,看到有个大神说,截取前30位就好了,?

安卓拉起微信支付以后,并支付成功,这个时候,微信会去自动调用咱们的写的回调接口

?

 public String callBackMall(HttpServletRequest request, HttpServletResponse response) {
        response.setHeader("Content-Type", "application/xml"); //设置响应数据格式为xml
        Map<String, String> returnMap = new HashMap<>();
        returnMap.put("return_code", "SUCCESS");
        returnMap.put("return_msg", "");
        Long hxcode =null;
        // 读取参数,解析Xml为map
        Map<String, String> map = null;
        try {
            map = WXPayUtil.xmlToMap(wxUtils.readRequest(request));
            // 转换为有序 map,判断签名是否正确
            boolean isSignSuccess = WXPayUtil.isSignatureValid(new TreeMap<String, 
          String>(map), key, WXPayConstants.SignType.HMACSHA256);
            // 签名校验成功,说明是微信服务器发出的数据
            if (isSignSuccess) {
                //拿出订单支付编号
                String orderNo = map.get("out_trade_no");
                //根据订单支付编号去查找订单id,等相关的数据
                WXPrePay pay = prePayService.getWxPrePayByOrderNo(orderNo).getData();
                System.out.println("预下单对象:" + pay);
                Integer orderId = pay.getOrderId();
                String transactionId = map.get("transaction_id");
                System.out.println("微信订单支付单号" + transactionId);
                Boolean b = orderFeignService.hasPayByOrderId(orderId).getData();
                System.out.println(b);
                if (!b) { //false,已支付------一定要在这里去判断是否支付成功,因为微信支付的回调,是分时间,一直在调用,这个具体看官网怎么写的
                    returnMap.put("hx_code", hxcode.toString());
                    return WXPayUtil.mapToXml(returnMap);
                }
                if (map.get("return_code").equals("SUCCESS")) {
                    if (map.get("result_code").equals("SUCCESS")) {
                        System.out.println("微信回调:支付成功,orderNo为:" + orderNo);
                        //------------------自己处理业务逻辑
                        pay.setTransactionId(transactionId);
                        prePayService.updateById(pay);
                        System.out.println(map);
                        returnMap.put("hx_code", hxcode.toString());
                        return WXPayUtil.mapToXml(returnMap);
                    } else {
                        System.out.println("微信回调:支付失败,orderNo为:" + orderNo);
                    }
                }
                // 签名校验失败(可能不是微信服务器发出的数据)
                returnMap.put("return_code", "FAIL");
                returnMap.put("return_msg", "");
                return WXPayUtil.mapToXml(returnMap);

            } else {
                // 签名校验失败(可能不是微信服务器发出的数据)
                returnMap.put("return_code", "FAIL");
                returnMap.put("return_msg", "");
                return WXPayUtil.mapToXml(returnMap);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return "<xml>\n" +
                    "  <return_code><![CDATA[FAIL]]></return_code>\n" +
                    "  <return_msg><![CDATA[]]></return_msg>\n" +
                    "</xml>";
        } catch (Exception e) {
            e.printStackTrace();
            return "<xml>\n" +
                    "  <return_code><![CDATA[FAIL]]></return_code>\n" +
                    "  <return_msg><![CDATA[]]></return_msg>\n" +
                    "</xml>";
        }

    }

这里附上两个工具类,上面会用到

package com.ayjmall.thirdparty.wechat.utils;
import jodd.util.ResourcesUtil;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;

/**
 * @Auther swj
 * @description 带双向证书的post请求工具类
 * @Date 2021/1/20
 */
public class WxCertHttpUtil {

    private static int socketTimeout = 10000;// 连接超时时间,默认10秒
    private static int connectTimeout = 30000;// 传输超时时间,默认30秒
    private static RequestConfig requestConfig;// 请求配置
    private static CloseableHttpClient httpClient;// HTTP请求

    /**

     *
     * @param url API地址
     * @param --xmlObj 要提交的XML
     * @param mchId 服务商商户ID
     * @param --certPath证书路径
     * @return
     */
    public static String postData(String url, String xml, String mchId, String certPath) {
        // 加载证书
        try {
            loadCert(mchId, certPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String result = null;
        HttpPost httpPost = new HttpPost(url);
        StringEntity postEntity = new StringEntity(xml, "UTF-8");
        httpPost.addHeader("Content-Type", "application/xml");
        httpPost.setEntity(postEntity);
        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();

        httpPost.setConfig(requestConfig);
        try {
            HttpResponse response = null;
            try {
                response = httpClient.execute(httpPost);
            } catch (IOException e) {
                e.printStackTrace();
            }
            HttpEntity entity = response.getEntity();
            try {
                result = EntityUtils.toString(entity, "UTF-8");
            } catch (IOException e) {
                e.printStackTrace();
            }
        } finally {
            httpPost.abort();
        }
        return result;
    }

    /**
     *加载证书
     *
     * @param mchId 服务商商户ID
     * @param certPath 证书路径
     * @throws Exception
     */
    private static void loadCert(String mchId, String certPath) throws Exception {
        // 证书密码,默认为服务商商戶ID
        String key = mchId;
        // 证书路径

        String path = certPath;
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        // 指定证书格式为PKCS12
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        // 读取PKCS12证书文件
        InputStream instream = ResourcesUtil.getResourceAsStream(path);
        try {
            // 指定PKCS12的密碼(商戶ID)
            keyStore.load(instream, key.toCharArray());
        } finally {
            instream.close();
        }
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray()).build();
        SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslcontext, NoopHostnameVerifier.INSTANCE);
        httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
    }
}
package com.ayjmall.thirdparty.wechat.utils;

import com.ayjmall.common.utils.MD5Util;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;


/**
 * Created by suneo.
 * User: neo
 * Date: 29/01/2018
 * Time: 5:21 PM
 * Describe:
 * <编码格式统一为 UTF-8>
 * <p>
 * 便于使用,将所有的工具方法都集中在此,包含:
 * 1. 执行 HTTP POST 请求,返回执行结果的 String
 * 2. 创建签名(为下单数据创建)
 * 3. 创建签名(为 APP 创建)
 * 4. 检验签名
 * 5. 读取 HTTP Request 内容
 * 6. 读取 HTTP Response 内容
 * 7. 将 Map 转化为 Xml
 * 8. 将 Xml 转化为 Map
 * 9. 生成 32 位随机字符串
 * 10. MD5 签名
 */
@Service
public class WxUtils {

    /**
     * 微信支付签名算法sign
     *
     * @param characterEncoding
     * @param parameters
     * @return
     */
    public static String createSign(String characterEncoding, Map<String, String> parameters, String key) {
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();// 所有参与传参的参数按照accsii排序(升序)
        Iterator it = es.iterator();
        while (it.hasNext()) {
            @SuppressWarnings("rawtypes")
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k)
                    && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + key); //KEY是商户秘钥
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding)
                .toUpperCase();
        return sign;
    }


    /**
     * 读取 request body 内容作为字符串
     *
     * @param request
     * @return
     * @throws IOException
     */
    public String readRequest(HttpServletRequest request) throws IOException {
        InputStream inputStream;
        StringBuffer sb = new StringBuffer();
        inputStream = request.getInputStream();
        String str;
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
        while ((str = in.readLine()) != null) {
            sb.append(str);
        }
        in.close();
        inputStream.close();
        return sb.toString();
    }

}

小程序支付

小程序支付跟app支付有不一样的地方,但是区别不大,我已经在代码中注释了,小程序有单独的小程序id.还要在单独指定小程序的支付方式,而且还有单独的小程序的openid,请大家注意

    public R<WXPaymentResponseDto> MiniPrePayMall(Integer userId, Integer orderId, BigDecimal money) {
        AyjMallMembers members = memberFeignService.getMembersById(userId).getData();
        int penny = money.multiply(new BigDecimal("100")).intValue();//已分为单位
        Map<String, String> resp = new HashMap<>();
        try {
            MiniWXPay miniWXPay = miniUserMyConfig.miniMyWXPay();
            SortedMap<String, String> data = new TreeMap<String, String>();
            data.put("appid", miniAppId);//微信小程序支付id
            data.put("mch_id", mchId);//商户号
            data.put("nonce_str", MiniWXPayUtil.generateNonceStr());
            data.put("sign_type", "MD5");
            data.put("body", bodyMall);
            data.put("out_trade_no", OrderNoUtil.getOrderId());//订单号
            data.put("fee_type", feeType);// 金额类型	默认CNY
            data.put("total_fee", penny+"");//订单处理金额
            data.put("notify_url", notifyUrlMiniMall);//支付成功以后调用的地址
            data.put("trade_type", miniTradeType);  // 此处指定为小程序支付
            data.put("openid",members.getOpenidMiniUserId());//小程序支付必须使用小程序登录的openid
            //生成签名--一次签名,在预下单之前
            String characterEncoding = "UTF-8";
            String oneSign=  createSign(characterEncoding,data, key);
            data.put("sign",oneSign);
            resp = miniWXPay.unifiedOrder(data);
            log.info("微信预下单返回的对象-----------------:", resp);
            if (resp.get("return_code").equals("SUCCESS")) {
                log.info("微信预下单成功!");
                //生成微信预下单对象
                WXPrePay prePay = new WXPrePay();
                prePay.setMemberId(userId);//用户id
                prePay.setOrderNo(data.get("out_trade_no"));//支付订单单号
                prePay.setOrderId(orderId);//项目自增id
                prePay.setOrderType(4);//订单类型
                prePay.setTotalAmount(penny);//金额
                baseMapper.insert(prePay);
                //返回WXPaymentResponseDto对象给前端
                WXPaymentResponseDto dto = new WXPaymentResponseDto();
                dto.setNonceStr(resp.get("nonce_str"));
                dto.setPrepayId(resp.get("prepay_id"));
                dto.setPartnerId(mchId); //商户id
                dto.setAppId(miniAppId); //商户id
                dto.setWxPackage(wxPackage);
                String time = new Date().getTime()+"";
                dto.setTimestamp(time.substring(0,10));
                //统一下单以后,生成的二次签名
                Map<String, String> signmap = new TreeMap<>();
                signmap.put("appId",miniAppId);
                signmap.put("nonceStr",resp.get("nonce_str"));
                signmap.put("package","prepay_id="+resp.get("prepay_id"));
                signmap.put("signType","MD5");
                signmap.put("timeStamp",time.substring(0,10));
                //signmap.put("mchId",mchId);
                String sign = WxUtils.createSign(characterEncoding,signmap,key);//商户的key
                System.out.println(signmap+"---------------");
                System.out.println("二次签名:"+sign);
                dto.setSign(sign);
                System.out.println(resp);
                return R.success(dto);
            }
            log.info("微信预下单失败:",resp.get("return_msg"));
            return R.fail("微信预下单失败:"+resp.get("return_msg"));
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail("微信预下单失败:"+resp.get("return_msg"));
        }
    }

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-28 12:30:08  更:2021-10-28 12:30:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:09:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码