对接微信支付

对接微信支付,先聊一聊开发步骤:你需要提交必要参数请求微信下单,微信会给你返回一个微信下单号,表示下单成功,然后拿上下单号,和一些必须的参数再次请求微信调起微信支付,付款成功后,微信会访问你的回调地址(必须外网能访问的地址),给你返回信息,然后你需要在回调接口中进行业务处理,并给微信正确返回回调. 其中下单和付款都需要验证签名(就是判断他传给你的参数在传输中有没有被篡改,具体验证方式见微信说明,工具类微信开发文档上也有)

微信开发地址:  https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1

涉及工具类微信开发文档基本有, 

链接:https://pan.baidu.com/s/1Ec89zdogUluKoyE1zBeIVA 
提取码:7z0y 

1.微信下单接口:

@ApiOperation(value = "微信下单,返回微信预付款订单号", notes = "传入付款金额,订单号 ,商品信息")
@PostMapping("/create/wxorder")
public Object createWXOrder(@RequestBody HWeiXinPayParam payParam) throws Exception {
    SortedMap<String, String> sortedMap = new TreeMap<String, String>();
    sortedMap.put("appid", wxPayConfigEntity.getApppid()); //应用ID
    sortedMap.put("mch_id", wxPayConfigEntity.getMchid()); //商户号
    String nonceStr = WXPayUtil.generateNonceStr(); //生成随机数
    sortedMap.put("nonce_str", nonceStr); //随机字符串
    sortedMap.put("body", "玖阅-" + payParam.getBody()); //商品描述
    String orderSn = payParam.getOrderSn();//商户订单号
    sortedMap.put("out_trade_no", orderSn); //商户订单号
    Integer totalFee = payParam.getTotalFee() * 100;//总金额  需要乘以100 ,微信支付默认单位分
    sortedMap.put("total_fee", totalFee + ""); //总金额
    sortedMap.put("spbill_create_ip", wxPayConfigEntity.getSpbillcreateip()); //终端IP
    sortedMap.put("notify_url", wxPayConfigEntity.getNotifyurl()); //通知地址
    sortedMap.put("trade_type", wxPayConfigEntity.getTradetype()); //交易类型
    //生成签名
    String sign = WXPayUtil.generateSignature(sortedMap, wxPayConfigEntity.getKey(), WXPayConstants.SignType.MD5);
    sortedMap.put("sign", sign);
    //将Map转换为XML格式的字符串  发送给微信xml
    String xml = WXPayUtil.generateSignedXml(sortedMap, wxPayConfigEntity.getKey(), WXPayConstants.SignType.MD5);
    HttpClient httpClient = HttpClientBuilder.create().build();
    HttpPost httpPost = new HttpPost(wxPayConfigEntity.getPayurl());
    RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(30000).setConnectTimeout(30000).build();
    httpPost.setConfig(requestConfig);
    StringEntity postEntity = new StringEntity(xml, "UTF-8");
    httpPost.addHeader("Content-Type", "text/xml");
    httpPost.setEntity(postEntity);
    HttpResponse httpResponse = httpClient.execute(httpPost);
    HttpEntity httpEntity = httpResponse.getEntity();
    String string = EntityUtils.toString(httpEntity, "UTF-8"); //微信返回的xml信息
    boolean bool = WXPayUtil.isSignatureValid(string, wxPayConfigEntity.getKey());//验证签名是否正确
    Map map = new HashMap();
    if (bool) {
        Map<String, String> resultMap = WXPayUtil.xmlToMap(string);
        String prepayId = resultMap.get("prepay_id");//微信下单号
        String timeStamp = (new Date().getTime() / 1000) + ""; //时间戳
        SortedMap<String, String> twoSortedMap = new TreeMap<String, String>();
        twoSortedMap.put("appid", wxPayConfigEntity.getApppid()); //应用ID
        twoSortedMap.put("partnerid", wxPayConfigEntity.getMchid()); //商户号
        twoSortedMap.put("package", wxPayConfigEntity.getPackages()); //商户号
        twoSortedMap.put("noncestr", nonceStr);//随机数
        twoSortedMap.put("prepayid", prepayId); //微信下单号
        twoSortedMap.put("timestamp", timeStamp); //时间戳
        //二次签名   将请求参数返回前端,由前端app调起支付接口支付
        String twoSign = WXPayUtil.generateSignature(twoSortedMap, wxPayConfigEntity.getKey(), WXPayConstants.SignType.MD5);
        map.put("return_code", "操作成功");
        map.put("prepayId", prepayId); //微信下单号
        map.put("nonceStr", nonceStr); //随机数
        map.put("sign", twoSign); //二次签名
        map.put("timestamp", timeStamp);//时间戳
        cartItemService.updateTotleFree(totalFee, prepayId, orderSn); //数据库保存信息 根据订单编号修改订单表保存微信需要付款总金额,支付微信下单号
        return map;
    }
    map.put("return_code", "操作失败");
    return map;
}

2.微信回调接口:

@ApiOperation(value = "微信支付回调地址,", notes = "")
@PostMapping("/callback/wxorder")
public Object callBack(HttpServletRequest request) throws Exception {
    //读取微信回调的内容
    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);
    }
    String resultxml = new String(outSteam.toByteArray(), "utf-8");
    outSteam.close();
    inStream.close();

    //xml转成map
    Map<String, String> params = WXPayUtil.xmlToMap(resultxml);
    Map<String, String> return_data = new HashMap<String, String>(); //返回给微信信息
    if ("SUCCESS".equals(params.get("return_code"))) { //返回成功 付款成功
        boolean bool = WXPayUtil.isSignatureValid(resultxml, wxPayConfigEntity.getKey());//验证签名是否正确
        if (bool) {  //签名验证成功
            String outTradeNo = params.get("out_trade_no"); //返回的商户订单号
            Integer totalFee = Integer.parseInt(params.get("total_fee")); //总金额
            Integer totalFeeTable = cartItemService.selectTotleFre(outTradeNo);//根据订单编号查询订单表保存微信需要付款总金额
            if (null != totalFeeTable && totalFee.equals(totalFeeTable)) {  //验证金额是否相同
                int wechatStatus = cartItemService.selectWechatStatus(outTradeNo);//查询订单处理状态
                if (wechatStatus == 1) {  //订单业务已处理,直接返回成功
                    return_data.put("return_code", "SUCCESS");
                    return_data.put("return_msg", "OK");
                    return WXPayUtil.mapToXml(return_data); //转成xml返回
                }
                String paymentTime = params.get("time_end"); //支付完成时间
                //发票表添加支付时间
                cartItemService.updatePaymentTime(paymentTime, outTradeNo);
                String transactionId = params.get("transaction_id"); //微信支付订单号
                Integer status = 1; //待发货
                wechatStatus = 1; //业务已处理
                String modifyTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());//修改时间
                //支付成功后修改订单信息 paymentTime transactionId微信支付订单号  status modifyTime outTradeNo
                cartItemService.updateOrderMessage(paymentTime, transactionId, status, modifyTime, outTradeNo, wechatStatus);  //修改数据库字段信息,业务处理
                return_data.put("return_code", "SUCCESS");
                return_data.put("return_msg", "OK");  //正确返回给微信
                return WXPayUtil.mapToXml(return_data);
            }
        }
    }
    // 支付失败
    return_data.put("return_code", "FAIL");
    return_data.put("return_msg", "return_code不正确");
    return WXPayUtil.mapToXml(return_data);
}

3.申请退款,(申请退款需要证书):

@ApiOperation(value = "微信申请退款", notes = "")
@PostMapping("/refund/wxorder")
public Object refundOrder(@RequestBody
                          @ApiParam(name = "参数说明", value = "totalFee:订单金额 ,refundFee:退款金额 ,orderSn:订单号")
                                  HWeiXinRefundParam param) throws Exception {
    SortedMap<String, String> sortedMap = new TreeMap<String, String>();
    Integer totalFee = param.getTotalFee() * 100; //订单金额 金额单位为分 *100
    Integer refundFee = param.getRefundFee() * 100; //退款金额  金额单位为分 *100
    String refundId = cartItemService.selectRefundId(param.getOrderSn());  //根据订单编号查询退款单号
    if (refundId != null) {
        sortedMap.put("out_refund_no", refundId);  //商户退款单号
    }
    sortedMap.put("appid", wxPayConfigEntity.getApppid()); //应用ID
    sortedMap.put("mch_id", wxPayConfigEntity.getMchid()); //商户号
    String nonceStr = WXPayUtil.generateNonceStr(); //生成随机数
    sortedMap.put("nonce_str", nonceStr); //随机字符串
    sortedMap.put("out_trade_no", param.getOrderSn());  //商户订单号
    sortedMap.put("total_fee", totalFee + "");
    sortedMap.put("refund_fee", refundFee + "");
    //生成签名
    String sign = WXPayUtil.generateSignature(sortedMap, wxPayConfigEntity.getKey(), WXPayConstants.SignType.MD5);
    sortedMap.put("sign", sign);
    //将Map转换为XML格式的字符串  发送给微信xml
    String xml = WXPayUtil.generateSignedXml(sortedMap, wxPayConfigEntity.getKey(), WXPayConstants.SignType.MD5);
    String string = clientCustomSSL.doRefund(wxPayConfigEntity.getRefund(), xml); //发起申请退款请求
    System.out.println("微信返回的xml===>>>" + string);
    boolean bool = WXPayUtil.isSignatureValid(string, wxPayConfigEntity.getKey());//验证签名是否正确
    Map<String, String> map = new HashMap<String, String>();
    if (bool) {
        Map<String, String> resultMap = WXPayUtil.xmlToMap(string);
        if ("SUCCESS".equals(resultMap.get("return_code"))) { //返回成功 退款成功
            map.put("refund_fee", resultMap.get("refund_fee"));//退款金额
            map.put("out_refund_no", resultMap.get("out_refund_no")); //退款单号
            map.put("message", "SUCCESS");//退款成功
            return map;
        }
    }
    map.put("message", "faild"); //退款失败
    return map;
}

退款还涉及到一个工具类粘一下:退款需要证书,证书是在申请微信商户号,发送到你的邮箱,然后下载下来.这里需要读取证书

@Component
public class ClientCustomSSL {

    @Autowired
    private WXPayConfigEntity wxPayConfigEntity;

    @SuppressWarnings("deprecation")
    public String doRefund(String url,String data) throws Exception {

        /**
         * 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
         */

        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        /**
         *此处要改
         *wxconfig.SSLCERT_PATH : 指向你的证书的绝对路径,带着证书去访问
         */
                                                                    //你下载的证书,解压后的apiclient_cert.p12这个文件全路径加全名
        FileInputStream instream = new FileInputStream(new File(wxPayConfigEntity.getCertificateurl()));//P12文件目录
        try {
            /**
             * 此处要改
             *
             * 下载证书时的密码、默认密码是你的MCHID mch_id
             * */
            keyStore.load(instream, wxPayConfigEntity.getMchid().toCharArray());//这里写密码.默认商户id
        } finally {
            instream.close();
        }

        // Trust own CA and all self-signed certs
        /**
         * 此处要改
         * 下载证书时的密码、默认密码是你的MCHID mch_id
         * */
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, wxPayConfigEntity.getMchid().toCharArray())//这里也是写密码的,默认商户id
                .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                new String[] { "TLSv1" },
                null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build();
        try {
            HttpPost httpost = new HttpPost(url); // 设置响应头信息
            httpost.addHeader("Connection", "keep-alive");
            httpost.addHeader("Accept", "*/*");
            httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            httpost.addHeader("Host", "api.mch.weixin.qq.com");
            httpost.addHeader("X-Requested-With", "XMLHttpRequest");
            httpost.addHeader("Cache-Control", "max-age=0");
            httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
            httpost.setEntity(new StringEntity(data, "UTF-8"));
            CloseableHttpResponse response = httpclient.execute(httpost);
            try {
                HttpEntity entity = response.getEntity();
                String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
                EntityUtils.consume(entity);
                return jsonStr;
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }
}

5,统一管理发起请求微信需要的参数,这里涉及隐私,这些有的参数需要申请微信支付商户才会有.

@Component
@Setter
@Getter
public class WXPayConfigEntity {

    @Value(value = "${wx.appid}")
    private  String apppid;  //应用ID
    @Value(value = "${wx.mchid}")
    private  String mchid ;          //商户ID
    @Value(value = "${wx.key}")
    private  String key ;  //密钥key
    @Value(value = "${wx.spbillcreate.ip}")
    private  String spbillcreateip; //终端IP
    @Value(value = "${wx.notify.url}")
    private  String notifyurl;  //通知回调地址
    @Value(value = "${wx.tradetype}")
    private  String tradetype;  //交易类型
    @Value(value = "${wx.pay.url}")
    private  String payurl;  //下单地址
    @Value(value = "${wx.package}")
    private  String packages; //扩展字段
    @Value(value = "${wx.refund}")
    private  String refund; //微信退款地址
    @Value(value = "${wx.certificate.url}")
    private  String certificateurl;//证书地址

}

6.大概就这么多

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值