• 小黑式烂代码之微信APP支付 + 退款(JAVA实现)


    首先,你得先有微信开发平台账号密码还需要开通应用,然后还有微信服务商平台商户版账号(这些我都是给产品经理拿的)

    其次我认为你先去看一看微信开发平台的文档!  https://pay.weixin.qq.com/wiki/doc/api/index.html

     这里有很多种支付,我就采用APP支付来说了(会了APP支付其实H5支付都差不多的!)

    进来后是这样的,随便看看'APP支付那几篇文章'讲的流程!,看完后知道大概了就可以看看'API列表了'

    我们后台开发需要关注的就是这三个API了!

    那我还是简单介绍一下APP支付的一个业务流程吧(其实文档里简述的了,我就直接贴图了!)

     

    这些圈圈起来的流程步骤,就是我们后台要做的了,其他的都是由移动端来实现的,我们可以不理会,还有步骤6查询订单支付结果,这个可做可不做吧,为了系统更安全些更慎重些也可以去实现,不过我就没有实现了

    下面就说一下如何对接这个所谓的第三方接口,其实就是跟前端来调用我们后端接口是一样的,我们在写接口文档时,有请求地址,请求参数,返回数据以及返回数据格式这4样!

    只要提供这4种东西,前端就可以来对接我们后台接口啦!所以,同个道理的,这次是由我们后台人员去请求微信提供的接口!

    所以文档上都有提供的了,我们只需要用httpclient来想微信接口那边发送同步请求获取返回结果数据即可,这样听起来貌似很简单!不过还真不是很简单,很多坑的,毕竟是腾讯的文档!

    然后要注意的首先是请求参数,请求参数是否必填这个如果是否的话我就建议不用填上去了,然后签名参数也要去看文档,如何生成签名,还有,参数是要以xml格式形式发送过去,

    而且返回结果也是以xml返回回来,所以和微信对接的交互就是xml,这点有点蛋疼呀!

    好了,上面说了该怎么去请求第三方接口,想必大家有点懵吧,不知道该如何下手,其实上面的那个请求方式有点难度,小白可以忽略上面那套方式,直接使用微信支付的一个开源jar!

    对 你没看错,就这一个,这个jar包里面已经封装好了我们如何获取签名,如何验签等api方法,而且还不需要我们去将参数转化成xml格式,它已经封装好了一切了,所以非常方便!

    这个jar包可以在这个地址去下载http://www.mvnjar.com/com.github.liyiorg/weixin-popular/2.8.14/detail.html

    好了,那上面的介绍看完还有微信jar拿到手后,现在就可以开始来实现了! 我就直接亮代码了!

      1 /**
      2  * @description:微信支付JAVA-SDK: APP支付,退款
      3  * @author:小黑
      4  */
      5 @Service
      6 public class WechatPayService {
      7     private static final Logger LOGGER = LoggerFactory.getLogger(WechatPayService.class);
      8     
      9     /************ 微信开放平台配置  ***************/
     10     
     11     /** APPID */
     12     private static final String APPID = ""; 
     13     
     14     /** 商户号 */
     15     private static final String MCH_ID = "";  
     16     
     17     /** 密钥 */
     18     private static final String PRIVATE_KEY = "";
     19     
     20     /** 用户订单支付结果异步通知url */
     21     private static final String NOTIFY_URL = "";
     22     
     23     /** 商户支付证书路径 */
     24     private static final String API_CLIENT_CERT_PATH = "";
     25     
     26     // 加载商户支付证书文件;
     27     static {
     28         LocalHttpClient.initMchKeyStore(MCH_ID, API_CLIENT_CERT_PATH);
     29     }
     30     
     31     /**
     32      * @description:使用微信支付-APP支付方式-统一下单;
     33      * @return 支付参数,如果支付失败则返回null
     34      * @author:Fanhaojian
     35      */
     36     public MchPayApp orderAppPay(PayLog payLog) {
     37         
     38         Unifiedorder unifiedorder = new Unifiedorder();
     39         
     40         /** APPID */
     41         unifiedorder.setAppid(APPID);
     42         
     43         /** 商户号 */
     44         unifiedorder.setMch_id(MCH_ID);
     45         
     46         /** 随机字符串 */
     47         unifiedorder.setNonce_str(UUID.randomUUID().toString().replaceAll("-", ""));
     48         
     49         /** 商品描述 */
     50         unifiedorder.setBody(payLog.getPayCode());
     51         
     52         /** 商户订单号 */
     53         unifiedorder.setOut_trade_no(payLog.getPayCode());
     54         
     55         /** 订单总金额 */
     56         unifiedorder.setTotal_fee(payLog.getPayPrice().multiply(new BigDecimal(100)).intValue() + "");   // 订单总金额,单位为分;
     57         
     58         /** 用户端请求IP地址 */
     59         unifiedorder.setSpbill_create_ip(IpUtils.getClientIp());
     60         
     61         /** 异步通知回调地址 */
     62         unifiedorder.setNotify_url(NOTIFY_URL);
     63         
     64         /** 交易类型 */
     65         unifiedorder.setTrade_type("APP");
     66         
     67         LOGGER.warn("微信APP支付--(签名前):" + XMLConverUtil.convertToXML(unifiedorder));
     68         
     69         /** 获取签名 */
     70         UnifiedorderResult unifiedorderResult = PayMchAPI.payUnifiedorder(unifiedorder, PRIVATE_KEY);
     71         
     72         LOGGER.warn("微信APP支付--支付统一下单接口请求状态(return_code):" + unifiedorderResult.getReturn_code());
     73         LOGGER.warn("微信APP支付--支付统一下单接口请求状态(return_msg):" + unifiedorderResult.getReturn_msg());
     74         LOGGER.warn("微信APP支付--支付统一下单接口请求状态(result_code):" + unifiedorderResult.getResult_code());
     75         LOGGER.warn("微信APP支付--支付请求参数封装(签名后):" + XMLConverUtil.convertToXML(unifiedorder));
     76         LOGGER.warn("微信APP支付--支付统一下单接口返回数据:" + FastJSONUtils.getJsonHelper().toJSONString(unifiedorderResult));
     77         
     78         // 下单结果验签; 
     79         if(unifiedorderResult.getSign_status() != null && unifiedorderResult.getSign_status()) {
     80             LOGGER.warn("微信APP支付验签成功");
     81             return PayUtil.generateMchAppData(unifiedorderResult.getPrepay_id(), APPID, MCH_ID, PRIVATE_KEY);
     82         }
     83         return null;
     84     }
     85     
     86     /**
     87      * @description:微信退款业务封装(支付押金退还);
     88      * @param   PayLog order:支付订单信息
     89      *           Double refundAmount:退款金额
     90      * @return 微信退款接口返回数据  true 退款成功  false 退款失败
     91      * @author:FanHaoJian
     92      */
     93     public Boolean refundOrder(PayLog order, Double refundAmount) {
     94         
     95         // 调用微信支付退款接口;
     96         SecapiPayRefund payRefund = new SecapiPayRefund();
     97         payRefund.setAppid(APPID);
     98         payRefund.setMch_id(MCH_ID);
     99         payRefund.setNonce_str(UUID.randomUUID().toString().replaceAll("-", ""));
    100         payRefund.setOut_trade_no(order.getPayCode());//支付订单号
    101         payRefund.setOut_refund_no(order.getRefundCode());//退款单号
    102         payRefund.setTotal_fee(order.getPayPrice().multiply(new BigDecimal(100)).intValue());//原订单金额,单位:分;
    103         payRefund.setRefund_fee(new BigDecimal(refundAmount).multiply(new BigDecimal(100)).intValue());//退款订单金额,单位:分;
    104         
    105         SecapiPayRefundResult refundResult = PayMchAPI.secapiPayRefund(payRefund, PRIVATE_KEY);
    106         
    107         // 微信支付退款接口返回数据验签;
    108         if(refundResult.getSign_status() != null && refundResult.getSign_status()) {
    109             LOGGER.warn("微信退款接口--接口请求状态(return_code):" + refundResult.getReturn_code());
    110             LOGGER.warn("微信退款接口--接口请求状态(return_msg):" + refundResult.getReturn_msg());
    111             
    112             // 退款信息提交成功;
    113             if("SUCCESS".equals(refundResult.getReturn_code())) {
    114                 LOGGER.warn("微信退款接口--接口请求状态(result_code):" + refundResult.getResult_code());
    115                 LOGGER.warn("微信退款接口--接口请求状态(err_code):" + refundResult.getErr_code());
    116                 LOGGER.warn("微信退款接口--接口请求状态(err_code_des):" + refundResult.getErr_code_des());
    117                 
    118                 return Boolean.TRUE;
    119             }
    120         }
    121         
    122         return Boolean.FALSE;
    123     }
    124 }

    在项目建一个sdk包,然后统一放入sdk,类似这样!

    然后创建一个微信支付SDK,将上面代码复制过去,然后看一遍代码里的方法流程,看明白后在改改里面的代码!

    然后我简单介绍一下上面的微信支付SDK吧,里面有两个方法,一个是统一下单,一个是退款!

    统一下单返回的数据就是要拿给移动端的签名数据,退款返回的数据就是true和false,没什么判断成功还是失败就行了,成功该做什么,失败该做什么!

    OK! 现在说完了统一下单和退款后,还有一个支付通知结果的API,也就是异步通知了!如果你看完了那篇流程图,你就会知道,当移动端调起支付并且支付成功后,微信后台那边会向我们这边后台发送一个请求过来!

    当然微信那边发送请求过来我们这边的接口,我也直接亮代码了!

     1 /**
     2  * @description:微信支付异步通知请求URL
     3  * @author:小黑
     4  */
     5 public class WechatOrderNotify extends ActionSupport {
     6     private static final Logger LOGGER = LoggerFactory.getLogger(WechatOrderNotify.class);
     7     private static final long serialVersionUID = 1L;
     8     
     9     /** 密钥 */
    10     private static final String PRIVATE_KEY = "";
    11     
    12     /** 定义应答变量 */
    13     private String xml;
    14     
    15     @Override
    16     public String wechatOrderNotify() throws Exception {
    17         
    18         // 解析微信支付异步通知请求参数;
    19         HttpServletRequest request = ServletActionContext.getRequest();
    20         String xml = StreamUtils.copyToString(request.getInputStream(), Charset.forName("utf-8"));
    21         Map<String, String> params = XMLConverUtil.convertToMap(xml);
    22         MchPayNotify payNotify = XMLConverUtil.convertToObject(MchPayNotify.class, xml);
    23         
    24         /** 打印日志信息 */
    25         LOGGER.warn("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$---进入微信支付异步通知请求接口---$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
    26         LOGGER.warn("微信支付用户订单支付结果异步通知请求参数(xml):" + params);
    27         LOGGER.warn("微信支付用户订单支付结果异步通知请求参数(map):" + params);
    28         LOGGER.warn("return_code:" + payNotify.getReturn_code());
    29         LOGGER.warn("return_msg:" + params.get("return_msg"));
    30         
    31         /** 校验支付成功还是失败 */
    32         if("SUCCESS".equals(payNotify.getReturn_code())) {
    33             
    34             /** 获取微信后台返回来的异步通知参数 */
    35             String outTradeNo = payNotify.getOut_trade_no();  // 用户订单号;
    36             String tradeNo = payNotify.getTransaction_id();   // 微信交易号;
    37             String tradeStatus = payNotify.getResult_code();  // 微信支付状态;
    38             Integer totalFee = payNotify.getTotal_fee();      // 支付金额
    39             
    40             /** 获取验签结果 true说明验签成功   false说明验签失败 */
    41             boolean flag = SignatureUtil.validateSign(params, PRIVATE_KEY);
    42             
    43             /** 打印日志信息 */
    44             LOGGER.warn("微信支付--APP支付方式支付用户订单异步通知订单号(out_trade_no):" + outTradeNo);
    45             LOGGER.warn("微信支付--APP支付方式支付用户订单异步通知交易号(trade_no):" + tradeNo);
    46             LOGGER.warn("微信支付--APP支付方式支付用户订单异步通知交易状态(result_code):" + tradeStatus);
    47             LOGGER.warn("微信支付--APP支付方式支付用户订单异步通知支付金额(total_fee):" + totalFee);
    48             LOGGER.warn("微信支付--APP支付方式支付用户订单异步通知验签状态:" + flag);
    49             
    50             /** 根据订单号获取订单支付信息: 支付状态为 '未支付' */
    51             ...此处省略 根据订单号去查订单 我用hibernate的 你们可能用mybatis或者其他,所以自己去查吧!
    52             
    53             /** 支付成功/处理订单业务信息 */
    54             if(flag && "SUCCESS".equals(tradeStatus) && order != null) {
    55                 
    56                 /** 更新订单支付信息: */
    57                 ...此处省略 根据自己项目的业务去处理逻辑!
    58                 
    59                 /** 封装通知信息 */
    60                 MchBaseResult baseResult = new MchBaseResult();
    61                 baseResult.setReturn_code("SUCCESS");
    62                 baseResult.setReturn_msg("OK");
    63                 xml =  XMLConverUtil.convertToXML(baseResult);
    64             
    65             /** 支付成功 */
    66             }else if(flag && "SUCCESS".equals(tradeStatus)){
    67                 MchBaseResult baseResult = new MchBaseResult();
    68                 baseResult.setReturn_code("SUCCESS");
    69                 baseResult.setReturn_msg("OK");
    70                 xml =  XMLConverUtil.convertToXML(baseResult);
    71             
    72             /** 支付失败 */
    73             }else {    
    74                 MchBaseResult baseResult = new MchBaseResult();
    75                 baseResult.setReturn_code("FAIL");
    76                 baseResult.setReturn_msg("FAIL");
    77                 xml =  XMLConverUtil.convertToXML(baseResult);
    78             }
    79         
    80         /** 支付失败 */    
    81         }else {
    82             MchBaseResult baseResult = new MchBaseResult();
    83             baseResult.setReturn_code("FAIL");
    84             baseResult.setReturn_msg("FAIL");
    85             xml =  XMLConverUtil.convertToXML(baseResult);
    86         }
    87         LOGGER.warn("微信支付--APP支付方式支付用户订单异步通知返回数据:" + xml);
    88         return Results.XML;
    89     }
    90     
    91     public String getXml() {
    92         return xml;
    93     }
    94 
    95     public void setXml(String xml) {
    96         this.xml = xml;
    97     }
    98 }

    这里也是直接招搬过去,然后改改代码即可!需要注意的就是这个返回数据xml,你可能要自己定义一下,应答是要这种格式的:

  • 相关阅读:
    Windows 系统共享文件扫描
    工业以太网EtherNet/IP协议安全分析整理
    说说搜索,你觉得自己的信息有多安全
    java网络编程
    攻击WordPress和其他程序
    ZenMap扫描笔记
    WireShark Wifi认证数据包分析(论文idea)
    linux 基础知识(三)
    unity 3D 学习笔记
    WPA-PSK无线网络密码破解原理
  • 原文地址:https://www.cnblogs.com/xiaohei520/p/9146723.html
Copyright © 2020-2023  润新知