content: package com.example.pay.controller;
  
  import com.alipay.api.AlipayApiException;
  import com.alipay.api.AlipayClient;
  import com.alipay.api.domain.AlipayTradeCloseModel;
  import com.alipay.api.domain.AlipayTradeFastpayRefundQueryModel;
  import com.alipay.api.domain.AlipayTradeRefundModel;
  import com.alipay.api.internal.util.AlipaySignature;
  import com.alipay.api.request.AlipayTradeCloseRequest;
  import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
  import com.alipay.api.request.AlipayTradeRefundRequest;
  import com.alipay.api.response.AlipayTradeCloseResponse;
  import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
  import com.alipay.api.response.AlipayTradeQueryResponse;
  import com.alipay.api.response.AlipayTradeRefundResponse;
  import com.alipay.demo.trade.model.builder.AlipayTradeQueryRequestBuilder;
  import com.alipay.demo.trade.model.result.AlipayF2FQueryResult;
  import com.alipay.demo.trade.service.AlipayTradeService;
  import com.example.pay.configuration.AlipayProperties;
  import lombok.extern.slf4j.Slf4j;
  import org.springframework.beans.factory.annotation.Autowired;
  
  import javax.servlet.http.HttpServletRequest;
  import java.io.UnsupportedEncodingException;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  
  /**
   * 支付宝通用接口
   */
  @Slf4j
  @RestController
  @RequestMapping("/alipay")
  public class AlipayController {
  
      @Autowired
      private AlipayProperties aliPayProperties;
  
      @Autowired
      private AlipayClient alipayClient;
  
      @Autowired
      private AlipayTradeService alipayTradeService;
  
      /**
       * 支付异步通知
       *
       * 接收到异步通知并验签通过后，一定要检查通知内容，包括通知中的app_id、out_trade_no、total_amount是否与请求中的一致，并根据trade_status进行后续业务处理。
       *
       * https://docs.open.alipay.com/194/103296
       */
      @RequestMapping("/notify")
      public String notify(HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {
          // 一定要验签，防止黑客篡改参数
          Map<String, String[]> parameterMap = request.getParameterMap();
          StringBuilder notifyBuild = new StringBuilder("/****************************** alipay notify ******************************/\n");
          parameterMap.forEach((key, value) -> notifyBuild.append(key + "=" + value[0] + "\n") );
          log.info(notifyBuild.toString());
  
  
          boolean flag = this.rsaCheckV1(request);
          if (flag) {
              /**
               * TODO 需要严格按照如下描述校验通知数据的正确性
               *
               * 商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
               * 并判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
               * 同时需要校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email），
               *
               * 上述有任何一个验证不通过，则表明本次通知是异常通知，务必忽略。
               * 在上述验证通过后商户必须根据支付宝不同类型的业务通知，正确的进行不同的业务处理，并且过滤重复的通知结果数据。
               * 在支付宝的业务通知中，只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时，支付宝才会认定为买家付款成功。
               */
  
              //交易状态
              String tradeStatus = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");
              // 商户订单号
              String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
              //支付宝交易号
              String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
              //付款金额
              String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");
              // TRADE_FINISHED(表示交易已经成功结束，并不能再对该交易做后续操作);
              // TRADE_SUCCESS(表示交易已经成功结束，可以对该交易做后续操作，如：分润、退款等);
              if(tradeStatus.equals("TRADE_FINISHED")){
                  //判断该笔订单是否在商户网站中已经做过处理
                  //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，
                  // 并判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），并执行商户的业务程序
                  //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
                  //如果有做过处理，不执行商户的业务程序
  
                  //注意：
                  //如果签约的是可退款协议，退款日期超过可退款期限后（如三个月可退款），支付宝系统发送该交易状态通知
                  //如果没有签约可退款协议，那么付款完成后，支付宝系统发送该交易状态通知。
              } else if (tradeStatus.equals("TRADE_SUCCESS")){
                  //判断该笔订单是否在商户网站中已经做过处理
                  //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，
                  // 并判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），并执行商户的业务程序
                  //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
                  //如果有做过处理，不执行商户的业务程序
  
                  //注意：
                  //如果签约的是可退款协议，那么付款完成后，支付宝系统发送该交易状态通知。
  
              }
  
              return "success";
          }
  
          return "fail";
      }
  
      /**
       * 订单查询(最主要用于查询订单的支付状态)
       * @param orderNo 商户订单号
       * @return
       */
      @GetMapping("/query")
      public String query(String orderNo){
  
          AlipayTradeQueryRequestBuilder builder = new AlipayTradeQueryRequestBuilder()
                  .setOutTradeNo(orderNo);
          AlipayF2FQueryResult result = alipayTradeService.queryTradeResult(builder);
          switch (result.getTradeStatus()) {
              case SUCCESS:
                  log.info("查询返回该订单支付成功: )");
  
                  AlipayTradeQueryResponse resp = result.getResponse();
                  log.info(resp.getTradeStatus());
  //                log.info(resp.getFundBillList());
                  break;
  
              case FAILED:
                  log.error("查询返回该订单支付失败!!!");
                  break;
  
              case UNKNOWN:
                  log.error("系统异常，订单支付状态未知!!!");
                  break;
  
              default:
                  log.error("不支持的交易状态，交易返回异常!!!");
                  break;
          }
          return result.getResponse().getBody();
      }
  
      /**
       * 退款
       * @param orderNo 商户订单号
       * @return
       */
      @PostMapping("/refund")
      @ResponseBody
      public String refund(String orderNo) throws AlipayApiException {
          AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
  
          AlipayTradeRefundModel model=new AlipayTradeRefundModel();
          // 商户订单号
          model.setOutTradeNo(orderNo);
          // 退款金额
          model.setRefundAmount("0.01");
          // 退款原因
          model.setRefundReason("无理由退货");
          // 退款订单号(同一个订单可以分多次部分退款，当分多次时必传)
  //        model.setOutRequestNo(UUID.randomUUID().toString());
          alipayRequest.setBizModel(model);
  
          AlipayTradeRefundResponse alipayResponse = alipayClient.execute(alipayRequest);
          System.out.println(alipayResponse.getBody());
  
          return alipayResponse.getBody();
      }
  
      /**
       * 退款查询
       * @param orderNo 商户订单号
       * @param refundOrderNo 请求退款接口时，传入的退款请求号，如果在退款请求时未传入，则该值为创建交易时的外部订单号
       * @return
       * @throws AlipayApiException
       */
      @GetMapping("/refundQuery")
      @ResponseBody
      public String refundQuery(String orderNo, String refundOrderNo) throws AlipayApiException {
          AlipayTradeFastpayRefundQueryRequest alipayRequest = new AlipayTradeFastpayRefundQueryRequest();
  
          AlipayTradeFastpayRefundQueryModel model=new AlipayTradeFastpayRefundQueryModel();
          model.setOutTradeNo(orderNo);
          model.setOutRequestNo(refundOrderNo);
          alipayRequest.setBizModel(model);
  
          AlipayTradeFastpayRefundQueryResponse alipayResponse = alipayClient.execute(alipayRequest);
          System.out.println(alipayResponse.getBody());
  
          return alipayResponse.getBody();
      }
  
      /**
       * 关闭交易
       * @param orderNo
       * @return
       * @throws AlipayApiException
       */
      @PostMapping("/close")
      @ResponseBody
      public String close(String orderNo) throws AlipayApiException {
          AlipayTradeCloseRequest alipayRequest = new AlipayTradeCloseRequest();
          AlipayTradeCloseModel model =new AlipayTradeCloseModel();
          model.setOutTradeNo(orderNo);
          alipayRequest.setBizModel(model);
  
          AlipayTradeCloseResponse alipayResponse = alipayClient.execute(alipayRequest);
          System.out.println(alipayResponse.getBody());
  
          return alipayResponse.getBody();
      }
  
      /**
       * 校验签名
       * @param request
       * @return
       */
      public boolean rsaCheckV1(HttpServletRequest request){
          // https://docs.open.alipay.com/54/106370
          // 获取支付宝POST过来反馈信息
          Map<String,String> params = new HashMap<>();
          Map requestParams = request.getParameterMap();
          for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
              String name = (String) iter.next();
              String[] values = (String[]) requestParams.get(name);
              String valueStr = "";
              for (int i = 0; i < values.length; i++) {
                  valueStr = (i == values.length - 1) ? valueStr + values[i]
                          : valueStr + values[i] + ",";
              }
              params.put(name, valueStr);
          }
  
          try {
              boolean verifyResult = AlipaySignature.rsaCheckV1(params,
                      aliPayProperties.getAlipayPublicKey(),
                      aliPayProperties.getCharset(),
                      aliPayProperties.getSignType());
  
              return verifyResult;
          } catch (AlipayApiException e) {
              log.debug("verify sigin error, exception is:{}", e);
              return false;
          }
      }
  }
  