栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

微信支付(app+小程序)--用java

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

微信支付(app+小程序)--用java

app微信支付 pom依赖
        
        
            com.github.wxpay
            wxpay-sdk
            0.0.3
        
        
            org.jodd
            jodd-core
            5.1.5
        

        
            com.github.wechatpay-apiv3
            wechatpay-apache-httpclient
            0.2.1
        
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;



    @Override
    public R prePayMall(Integer userId, Integer orderId,BigDecimal money) {
        int penny = money.multiply(new BigDecimal("100")).intValue();//已分为单位
        Map resp = new HashMap<>();
        try {
            WXPay wxpay = appConfigService.myWXPay();
            SortedMap data = new TreeMap();
            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 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 returnMap = new HashMap<>();
        returnMap.put("return_code", "SUCCESS");
        returnMap.put("return_msg", "");
        Long hxcode =null;
        // 读取参数,解析Xml为map
        Map map = null;
        try {
            map = WXPayUtil.xmlToMap(wxUtils.readRequest(request));
            // 转换为有序 map,判断签名是否正确
            boolean isSignSuccess = WXPayUtil.isSignaturevalid(new TreeMap(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 "n" +
                    "  n" +
                    "  n" +
                    "";
        } catch (Exception e) {
            e.printStackTrace();
            return "n" +
                    "  n" +
                    "  n" +
                    "";
        }

    }

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

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;


public class WxCertHttpUtil {

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

    
    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;
    }

    
    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.*;



@Service
public class WxUtils {

    
    public static String createSign(String characterEncoding, Map 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;
    }


    
    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 MiniPrePayMall(Integer userId, Integer orderId, BigDecimal money) {
        AyjMallMembers members = memberFeignService.getMembersById(userId).getData();
        int penny = money.multiply(new BigDecimal("100")).intValue();//已分为单位
        Map resp = new HashMap<>();
        try {
            MiniWXPay miniWXPay = miniUserMyConfig.miniMyWXPay();
            SortedMap data = new TreeMap();
            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 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"));
        }
    }

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/351172.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号