java实现web商城微信支付五 微信支付取消订单查询退款等

源码资料在第六章最后(本文最后有链接)

一 商户定时查询本地订单

1.1、后端定义商户查单接口

支付成功后,商户则查询本地数据库,订单是否支付成功

OrderInfoController.java

/**
* 查询本地订单状态
*/
@ApiOperation("查询本地订单状态")
@GetMapping("/query-order-status/{orderNo}")
public R queryOrderStatus(@PathVariable String orderNo) {
	String orderStatus = orderInfoService.getOrderStatus(orderNo);
	if (OrderStatus.SUCCESS.getType().equals(orderStatus)) {//支付成功
		return R.ok();
	}
	return R.ok().setCode(101).setMessage("支付中...");
}

1.2、前端定时轮询查单

在二维码展示页面,前端定时轮询查询订单是否已支付,如果支付成功则跳转到订单页面
(1)定义定时器(前端vue)

 //启动定时器
 this.timer = setInterval(() => {
   //查询订单是否支付成功
   this.queryOrderStatus()
 }, 3000)

(2)查询订单

// 查询订单状态
queryOrderStatus() {

  orderInfoApi.queryOrderStatus(this.orderNo).then(response => {
    console.log('查询订单状态:' + response.code)

    // 支付成功后的页面跳转
    if (response.code === 0) {
      console.log('清除定时器')
      clearInterval(this.timer)
      // 三秒后跳转到订单列表
      setTimeout(() => {
        this.$router.push({ path: '/success' })
      }, 3000)
    }
  })
}

二 用户取消订单API

实现用户主动取消订单的功能

2.1、定义取消订单接口

WxPayController中添加接口方法

/**
   * 用户取消订单
   * @param orderNo
   * @return
   * @throws Exception
   */
  @ApiOperation("用户取消订单")
  @PostMapping("/cancel/{orderNo}")
  public R cancel(@PathVariable String orderNo) throws Exception {

      log.info("取消订单");

      wxPayService.cancelOrder(orderNo);
      return R.ok().setMessage("订单已取消");
  }

2.2 WxPayService

接口:

void cancelOrder(String orderNo) throws Exception;

实现:

/**
 * 用户取消订单
 * @param orderNo
 */
@Override
public void cancelOrder(String orderNo) throws Exception {

    //调用微信支付的关单接口
    this.closeOrder(orderNo);

    //更新商户端的订单状态
    orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.CANCEL);
}

关单方法

/**
 * 关单接口的调用
 * @param orderNo
 */
private void closeOrder(String orderNo) throws Exception {

    log.info("关单接口的调用,订单号 ===> {}", orderNo);

    //创建远程请求对象
    String url = String.format(WxApiType.CLOSE_ORDER_BY_NO.getType(), orderNo);
    url = wxPayConfig.getDomain().concat(url);
    HttpPost httpPost = new HttpPost(url);

    //组装json请求体
    Gson gson = new Gson();
    Map<String, String> paramsMap = new HashMap<>();
    paramsMap.put("mchid", wxPayConfig.getMchId());
    String jsonParams = gson.toJson(paramsMap);
    log.info("请求参数 ===> {}", jsonParams);

    //将请求参数设置到请求对象中
    StringEntity entity = new StringEntity(jsonParams,"utf-8");
    entity.setContentType("application/json");
    httpPost.setEntity(entity);
    httpPost.setHeader("Accept", "application/json");

    //完成签名并执行请求
    CloseableHttpResponse response = wxPayClient.execute(httpPost);

    try {
        int statusCode = response.getStatusLine().getStatusCode();//响应状态码
        if (statusCode == 200) { //处理成功
            log.info("成功200");
        } else if (statusCode == 204) { //处理成功,无返回Body
            log.info("成功204");
        } else {
            log.info("Native下单失败,响应码 = " + statusCode);
            throw new IOException("request failed");
        }

    } finally {
        response.close();
    }
}

三 微信支付查单API

3.1 查单接口的调用

商户后台未收到异步支付结果通知时,商户应该主动调用《微信支付查单接口》,同步订单状态。
(1)WxPayController

/**
 * 查询订单
 * @param orderNo
 * @return
 * @throws Exception
 */
@ApiOperation("查询订单:测试订单状态用")
@GetMapping("/query/{orderNo}")
public R queryOrder(@PathVariable String orderNo) throws Exception {

    log.info("查询订单");

    String result = wxPayService.queryOrder(orderNo);
    return R.ok().setMessage("查询成功").data("result", result);
}

(2)WxPayService
接口:

String queryOrder(String orderNo) throws Exception;

实现:

@Override
public String queryOrder(String orderNo) throws Exception {

    log.info("查单接口调用 ===> {}", orderNo);

    String url = String.format(WxApiType.ORDER_QUERY_BY_NO.getType(), orderNo);
    url = wxPayConfig.getDomain().concat(url).concat("?mchid=").concat(wxPayConfig.getMchId());

    HttpGet httpGet = new HttpGet(url);
    httpGet.setHeader("Accept", "application/json");

    //完成签名并执行请求
    CloseableHttpResponse response = wxPayClient.execute(httpGet);

    try {
        String bodyAsString = EntityUtils.toString(response.getEntity());//响应体
        int statusCode = response.getStatusLine().getStatusCode();//响应状态码
        if (statusCode == 200) { //处理成功
            log.info("成功, 返回结果 = " + bodyAsString);
        } else if (statusCode == 204) { //处理成功,无返回Body
            log.info("成功");
        } else {
            log.info("查单接口调用,响应码 = " + statusCode+ ",返回结果 = " + bodyAsString);
            throw new IOException("request failed");
        }

        return bodyAsString;

    } finally {
        response.close();
    }
}

3.2 集成Spring Task

Spring 3.0后提供Spring Task实现任务调度

(1)启动类添加注解
statistics启动类添加注解

@EnableScheduling

(2)测试定时任务
创建 task 包,创建 WxPayTask.java

package com.atguigu.paymentdemo.task;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class WxPayTask {
	/**
	* 测试
	* (cron="秒 分 时 日 月 周")
	* *:每隔一秒执行
	* 0/3:从第0秒开始,每隔3秒执行一次
	* 1-3: 从第1秒开始执行,到第3秒结束执行
	* 1,2,3:第1、2、3秒执行
	* ?:不指定,若指定日期,则不指定周,反之同理
	*/
	@Scheduled(cron="0/3 * * * * ?")
	public void task1() {
		log.info("task1 执行");
	}
}

3.3 定时查找超时订单

(1)WxPayTask

@Resource
private OrderInfoService orderInfoService;
@Resource
private WxPayService wxPayService;
/**
 * 从第0秒开始每隔30秒执行1次,查询创建超过5分钟,并且未支付的订单
 */
@Scheduled(cron = "0/30 * * * * ?")
public void orderConfirm() throws Exception {
    log.info("orderConfirm 被执行......");

    List<OrderInfo> orderInfoList = orderInfoService.getNoPayOrderByDuration(1);

    for (OrderInfo orderInfo : orderInfoList) {
        String orderNo = orderInfo.getOrderNo();
        log.warn("超时订单 ===> {}", orderNo);

        //核实订单状态:调用微信支付查单接口
        wxPayService.checkOrderStatus(orderNo);
    }
}

(2)OrderInfoService
接口

List<OrderInfo> getNoPayOrderByDuration(int minutes);

实现

/**
 * 查询创建超过minutes分钟并且未支付的订单
 * @param minutes
 * @return
 */
@Override
public List<OrderInfo> getNoPayOrderByDuration(int minutes) {

    Instant instant = Instant.now().minus(Duration.ofMinutes(minutes));

    QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("order_status", OrderStatus.NOTPAY.getType());
    queryWrapper.le("create_time", instant);

    List<OrderInfo> orderInfoList = baseMapper.selectList(queryWrapper);

    return orderInfoList;
}

3.4 处理超时订单

WxPayService
核实订单状态
接口:

void checkOrderStatus(String orderNo) throws Exception;

实现

/**
 * 根据订单号查询微信支付查单接口,核实订单状态
 * 如果订单已支付,则更新商户端订单状态,并记录支付日志
 * 如果订单未支付,则调用关单接口关闭订单,并更新商户端订单状态
 * @param orderNo
 */
@Transactional(rollbackFor = Exception.class)
@Override
public void checkOrderStatus(String orderNo) throws Exception {

    log.warn("根据订单号核实订单状态 ===> {}", orderNo);

    //调用微信支付查单接口
    String result = this.queryOrder(orderNo);

    Gson gson = new Gson();
    Map<String, String> resultMap = gson.fromJson(result, HashMap.class);

    //获取微信支付端的订单状态
    String tradeState = resultMap.get("trade_state");

    //判断订单状态
    if(WxTradeState.SUCCESS.getType().equals(tradeState)){

        log.warn("核实订单已支付 ===> {}", orderNo);

        //如果确认订单已支付则更新本地订单状态
        orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.SUCCESS);
        //记录支付日志
        paymentInfoService.createPaymentInfo(result);
    }

    if(WxTradeState.NOTPAY.getType().equals(tradeState)){
        log.warn("核实订单未支付 ===> {}", orderNo);

        //如果订单未支付,则调用关单接口
        this.closeOrder(orderNo);

        //更新本地订单状态
        orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.CLOSED);
    }
}

四 申请退款API

4.1 创建退款单

文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_9.shtml

(1)根据订单号查询订单
OrderInfoService
接口:

OrderInfo getOrderByOrderNo(String orderNo);

实现:

/**
 * 根据订单号获取订单
 * @param orderNo
 * @return
 */
@Override
public OrderInfo getOrderByOrderNo(String orderNo) {

    QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("order_no", orderNo);
    OrderInfo orderInfo = baseMapper.selectOne(queryWrapper);

    return orderInfo;
}

(2)创建退款单记录
RefundsInfoService
接口:

RefundInfo createRefundByOrderNo(String orderNo, String reason);

实现

/**
 * 根据订单号创建退款订单
 * @param orderNo
 * @return
 */
@Override
public RefundInfo createRefundByOrderNo(String orderNo, String reason) {

    //根据订单号获取订单信息
    OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderNo);

    //根据订单号生成退款订单
    RefundInfo refundInfo = new RefundInfo();
    refundInfo.setOrderNo(orderNo);//订单编号
    refundInfo.setRefundNo(OrderNoUtils.getRefundNo());//退款单编号
    refundInfo.setTotalFee(orderInfo.getTotalFee());//原订单金额(分)
    refundInfo.setRefund(orderInfo.getTotalFee());//退款金额(分)
    refundInfo.setReason(reason);//退款原因

    //保存退款订单
    baseMapper.insert(refundInfo);

    return refundInfo;
}

4.2 更新退款单

RefundInfoService
接口:

void updateRefund(String content);

实现:

/**
 * 记录退款记录
 * @param content
 */
@Override
public void updateRefund(String content) {

    //将json字符串转换成Map
    Gson gson = new Gson();
    Map<String, String> resultMap = gson.fromJson(content, HashMap.class);

    //根据退款单编号修改退款单
    QueryWrapper<RefundInfo> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("refund_no", resultMap.get("out_refund_no"));

    //设置要修改的字段
    RefundInfo refundInfo = new RefundInfo();

    refundInfo.setRefundId(resultMap.get("refund_id"));//微信支付退款单号

    //查询退款和申请退款中的返回参数
    if(resultMap.get("status") != null){
        refundInfo.setRefundStatus(resultMap.get("status"));//退款状态
        refundInfo.setContentReturn(content);//将全部响应结果存入数据库的content字段
    }
    //退款回调中的回调参数
    if(resultMap.get("refund_status") != null){
        refundInfo.setRefundStatus(resultMap.get("refund_status"));//退款状态
        refundInfo.setContentNotify(content);//将全部响应结果存入数据库的content字段
    }

    //更新退款单
    baseMapper.update(refundInfo, queryWrapper);
}

4.3 申请退款

(1)WxPayController

@ApiOperation("申请退款")
@PostMapping("/refunds/{orderNo}/{reason}")
public R refunds(@PathVariable String orderNo, @PathVariable String reason) throws Exception {

    log.info("申请退款");
    wxPayService.refund(orderNo, reason);
    return R.ok();
}

(2)WxPayService
接口

void refund(String orderNo, String reason) throws Exception;

实现

/**
 * 退款
 * @param orderNo
 * @param reason
 * @throws IOException
 */
@Transactional(rollbackFor = Exception.class)
@Override
public void refund(String orderNo, String reason) throws Exception {

    log.info("创建退款单记录");
    //根据订单编号创建退款单
    RefundInfo refundsInfo = refundsInfoService.createRefundByOrderNo(orderNo, reason);

    log.info("调用退款API");

    //调用统一下单API
    String url = wxPayConfig.getDomain().concat(WxApiType.DOMESTIC_REFUNDS.getType());
    HttpPost httpPost = new HttpPost(url);

    // 请求body参数
    Gson gson = new Gson();
    Map paramsMap = new HashMap();
    paramsMap.put("out_trade_no", orderNo);//订单编号
    paramsMap.put("out_refund_no", refundsInfo.getRefundNo());//退款单编号
    paramsMap.put("reason",reason);//退款原因
    paramsMap.put("notify_url", wxPayConfig.getNotifyDomain().concat(WxNotifyType.REFUND_NOTIFY.getType()));//退款通知地址

    Map amountMap = new HashMap();
    amountMap.put("refund", refundsInfo.getRefund());//退款金额
    amountMap.put("total", refundsInfo.getTotalFee());//原订单金额
    amountMap.put("currency", "CNY");//退款币种
    paramsMap.put("amount", amountMap);

    //将参数转换成json字符串
    String jsonParams = gson.toJson(paramsMap);
    log.info("请求参数 ===> {}" + jsonParams);

    StringEntity entity = new StringEntity(jsonParams,"utf-8");
    entity.setContentType("application/json");//设置请求报文格式
    httpPost.setEntity(entity);//将请求报文放入请求对象
    httpPost.setHeader("Accept", "application/json");//设置响应报文格式

    //完成签名并执行请求,并完成验签
    CloseableHttpResponse response = wxPayClient.execute(httpPost);

    try {

        //解析响应结果
        String bodyAsString = EntityUtils.toString(response.getEntity());
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) {
            log.info("成功, 退款返回结果 = " + bodyAsString);
        } else if (statusCode == 204) {
            log.info("成功");
        } else {
            throw new RuntimeException("退款异常, 响应码 = " + statusCode+ ", 退款返回结果 = " + bodyAsString);
        }

        //更新订单状态
        orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.REFUND_PROCESSING);

        //更新退款单
        refundsInfoService.updateRefund(bodyAsString);

    } finally {
        response.close();
    }
}

五 查询退款API

文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_10.shtml

5.1 查单接口的调用

(1)WxPayController

/**
 * 查询退款
 * @param refundNo
 * @return
 * @throws Exception
 */
@ApiOperation("查询退款:测试用")
@GetMapping("/query-refund/{refundNo}")
public R queryRefund(@PathVariable String refundNo) throws Exception {

    log.info("查询退款");

    String result = wxPayService.queryRefund(refundNo);
    return R.ok().setMessage("查询成功").data("result", result);
}

(2)WxPayService
接口

String queryRefund(String orderNo) throws Exception;

实现

/**
 * 查询退款接口调用
 * @param refundNo
 * @return
 */
@Override
public String queryRefund(String refundNo) throws Exception {

    log.info("查询退款接口调用 ===> {}", refundNo);

    String url =  String.format(WxApiType.DOMESTIC_REFUNDS_QUERY.getType(), refundNo);
    url = wxPayConfig.getDomain().concat(url);

    //创建远程Get 请求对象
    HttpGet httpGet = new HttpGet(url);
    httpGet.setHeader("Accept", "application/json");

    //完成签名并执行请求
    CloseableHttpResponse response = wxPayClient.execute(httpGet);

    try {
        String bodyAsString = EntityUtils.toString(response.getEntity());
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) {
            log.info("成功, 查询退款返回结果 = " + bodyAsString);
        } else if (statusCode == 204) {
            log.info("成功");
        } else {
            throw new RuntimeException("查询退款异常, 响应码 = " + statusCode+ ", 查询退款返回结果 = " + bodyAsString);
        }

        return bodyAsString;

    } finally {
        response.close();
    }
}

5.2 定时查找退款中的订单

(1)WxPayTask

/**
 * 从第0秒开始每隔30秒执行1次,查询创建超过5分钟,并且未成功的退款单
 */
@Scheduled(cron = "0/30 * * * * ?")
public void refundConfirm() throws Exception {
    log.info("refundConfirm 被执行......");

    //找出申请退款超过5分钟并且未成功的退款单
    List<RefundInfo> refundInfoList = refundInfoService.getNoRefundOrderByDuration(1);

    for (RefundInfo refundInfo : refundInfoList) {
        String refundNo = refundInfo.getRefundNo();
        log.warn("超时未退款的退款单号 ===> {}", refundNo);

        //核实订单状态:调用微信支付查询退款接口
        wxPayService.checkRefundStatus(refundNo);
    }
}

(2)RefundInfoService
接口

List<RefundInfo> getNoRefundOrderByDuration(int minutes);

实现

/**
* 找出申请退款超过minutes分钟并且未成功的退款单
 * @param minutes
 * @return
 */
@Override
public List<RefundInfo> getNoRefundOrderByDuration(int minutes) {

    //minutes分钟之前的时间
    Instant instant = Instant.now().minus(Duration.ofMinutes(minutes));

    QueryWrapper<RefundInfo> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("refund_status", WxRefundStatus.PROCESSING.getType());
    queryWrapper.le("create_time", instant);
    List<RefundInfo> refundInfoList = baseMapper.selectList(queryWrapper);
    return refundInfoList;
}

5.3 处理超时未退款订单

WxPayService
核实订单状态
接口:

void checkRefundStatus(String refundNo);

实现

/**
 * 根据退款单号核实退款单状态
  * @param refundNo
  * @return
  */
 @Transactional(rollbackFor = Exception.class)
 @Override
 public void checkRefundStatus(String refundNo) throws Exception {

     log.warn("根据退款单号核实退款单状态 ===> {}", refundNo);

     //调用查询退款单接口
     String result = this.queryRefund(refundNo);

     //组装json请求体字符串
     Gson gson = new Gson();
     Map<String, String> resultMap = gson.fromJson(result, HashMap.class);

     //获取微信支付端退款状态
     String status = resultMap.get("status");

     String orderNo = resultMap.get("out_trade_no");

     if (WxRefundStatus.SUCCESS.getType().equals(status)) {

         log.warn("核实订单已退款成功 ===> {}", refundNo);

         //如果确认退款成功,则更新订单状态
         orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.REFUND_SUCCESS);

         //更新退款单
         refundsInfoService.updateRefund(result);
     }

     if (WxRefundStatus.ABNORMAL.getType().equals(status)) {

         log.warn("核实订单退款异常  ===> {}", refundNo);

         //如果确认退款成功,则更新订单状态
         orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.REFUND_ABNORMAL);

         //更新退款单
         refundsInfoService.updateRefund(result);
     }
 }

六 退款结果通知API

文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_11.shtml

6.1 接收退款通知

WxPayController

/**
 * 退款结果通知
 * 退款状态改变后,微信会把相关退款结果发送给商户。
 */
@ApiOperation("退款结果通知")
@PostMapping("/refunds/notify")
public String refundsNotify(HttpServletRequest request, HttpServletResponse response){

    log.info("退款通知执行");
    Gson gson = new Gson();
    Map<String, String> map = new HashMap<>();//应答对象

    try {
        //处理通知参数
        String body = HttpUtils.readData(request);
        Map<String, Object> bodyMap = gson.fromJson(body, HashMap.class);
        String requestId = (String)bodyMap.get("id");
        log.info("支付通知的id ===> {}", requestId);

        //签名的验证
        WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest
                = new WechatPay2ValidatorForRequest(verifier, requestId, body);
        if(!wechatPay2ValidatorForRequest.validate(request)){

            log.error("通知验签失败");
            //失败应答
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "通知验签失败");
            return gson.toJson(map);
        }
        log.info("通知验签成功");

        //处理退款单
        wxPayService.processRefund(bodyMap);

        //成功应答
        response.setStatus(200);
        map.put("code", "SUCCESS");
        map.put("message", "成功");
        return gson.toJson(map);

    } catch (Exception e) {
        e.printStackTrace();
        //失败应答
        response.setStatus(500);
        map.put("code", "ERROR");
        map.put("message", "失败");
        return gson.toJson(map);
    }
}

6.2 处理订单和退款单

WxPayService
接口:

void processRefund(Map<String, Object> bodyMap) throws Exception;

实现:

/**
     * 处理退款单
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void processRefund(Map<String, Object> bodyMap) throws Exception {

        log.info("退款单");

        //解密报文
        String plainText = decryptFromResource(bodyMap);

        //将明文转换成map
        Gson gson = new Gson();
        HashMap plainTextMap = gson.fromJson(plainText, HashMap.class);
        String orderNo = (String)plainTextMap.get("out_trade_no");

        if(lock.tryLock()){
            try {

                String orderStatus = orderInfoService.getOrderStatus(orderNo);
                if (!OrderStatus.REFUND_PROCESSING.getType().equals(orderStatus)) {
                    return;
                }

                //更新订单状态
                orderInfoService.updateStatusByOrderNo(orderNo, OrderStatus.REFUND_SUCCESS);

                //更新退款单
                refundsInfoService.updateRefund(plainText);

            } finally {
                //要主动释放锁
                lock.unlock();
            }
        }
    }

七 账单

7.1 申请交易账单和资金账单

(1)WxPayController

@ApiOperation("获取账单url:测试用")
@GetMapping("/querybill/{billDate}/{type}")
public R queryTradeBill(
        @PathVariable String billDate,
        @PathVariable String type) throws Exception {

    log.info("获取账单url");

    String downloadUrl = wxPayService.queryBill(billDate, type);
    return R.ok().setMessage("获取账单url成功").data("downloadUrl", downloadUrl);
}

(2)WxPayService
接口

 String queryBill(String billDate, String type) throws Exception;

实现

/**
 * 申请账单
 * @param billDate
 * @param type
 * @return
 * @throws Exception
 */
@Override
public String queryBill(String billDate, String type) throws Exception {
    log.warn("申请账单接口调用 {}", billDate);

    String url = "";
    if("tradebill".equals(type)){
        url =  WxApiType.TRADE_BILLS.getType();
    }else if("fundflowbill".equals(type)){
        url =  WxApiType.FUND_FLOW_BILLS.getType();
    }else{
        throw new RuntimeException("不支持的账单类型");
    }

    url = wxPayConfig.getDomain().concat(url).concat("?bill_date=").concat(billDate);

    //创建远程Get 请求对象
    HttpGet httpGet = new HttpGet(url);
    httpGet.addHeader("Accept", "application/json");

    //使用wxPayClient发送请求得到响应
    CloseableHttpResponse response = wxPayClient.execute(httpGet);

    try {

        String bodyAsString = EntityUtils.toString(response.getEntity());

        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) {
            log.info("成功, 申请账单返回结果 = " + bodyAsString);
        } else if (statusCode == 204) {
            log.info("成功");
        } else {
            throw new RuntimeException("申请账单异常, 响应码 = " + statusCode+ ", 申请账单返回结果 = " + bodyAsString);
        }

        //获取账单下载地址
        Gson gson = new Gson();
        Map<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);
        return resultMap.get("download_url");

    } finally {
        response.close();
    }
}

7.2 下载账单

(1)WxPayController

@ApiOperation("下载账单")
@GetMapping("/downloadbill/{billDate}/{type}")
public R downloadBill(
        @PathVariable String billDate,
        @PathVariable String type) throws Exception {

    log.info("下载账单");
    String result = wxPayService.downloadBill(billDate, type);

    return R.ok().data("result", result);
}

(2)WxPayService
接口:

String downloadBill(String billDate, String type) throws Exception;

实现:

/**
     * 下载账单
     * @param billDate
     * @param type
     * @return
     * @throws Exception
     */
    @Override
    public String downloadBill(String billDate, String type) throws Exception {
        log.warn("下载账单接口调用 {}, {}", billDate, type);

        //获取账单url地址
        String downloadUrl = this.queryBill(billDate, type);
        //创建远程Get 请求对象
        HttpGet httpGet = new HttpGet(downloadUrl);
        httpGet.addHeader("Accept", "application/json");

        //使用wxPayClient发送请求得到响应
        CloseableHttpResponse response = wxPayNoSignClient.execute(httpGet);

        try {

            String bodyAsString = EntityUtils.toString(response.getEntity());

            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                log.info("成功, 下载账单返回结果 = " + bodyAsString);
            } else if (statusCode == 204) {
                log.info("成功");
            } else {
                throw new RuntimeException("下载账单异常, 响应码 = " + statusCode+ ", 下载账单返回结果 = " + bodyAsString);
            }

            return bodyAsString;

        } finally {
            response.close();
        }
    }

第六章:微信基础支付API V2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麦芽糖0219

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值