策略+工厂模式实现支付(支付宝)

发布时间:2024年01月19日

最近做了支付宝支付,但是因为之后也要对接微信支付,各种支付API的原理是一样的,就采用了工厂模式实现支付,下面是我的代码。

1.实现工厂

1.1 支付接口类


import com.alibaba.fastjson.JSONObject;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface PayStrategy {
    // 创建支付订单 
    String createOrder(SdopRecPay sdopRecPay, String json);

    // 查询支付结果
    boolean queryResult(String orderId);
    // 同步
    void returnPay(HttpServletRequest request, HttpServletResponse response);
    //异步
    JSONObject notifyPay(HttpServletRequest request, HttpServletResponse response);


}

1.2 具体实现(以支付宝为例)

1.配置信息 (需要补全)


public class AlipayConstant {
    //沙箱
    // 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
    public static String appId = "";
    // 商户私钥 沙箱
    public static String merPrivateKey = "";
    // 支付宝公钥
    public static String aliPublicKey = "";
    // 支付宝网关
    public static String gatewayUrl = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";
  
    // 签名方式
    public static String signType = "RSA2";
    // 服务器异步通知页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public static String notifyUrl = "https://www.szdsoft.cn/pay/sdop/plat/pay/notifyPay";
    // 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public static String returnUrl = "https://www.szdsoft.cn/pay/sdop/plat/pay/returnPay";
    // 字符编码格式
    public static String charset = "utf-8";



    // 自定义
    // 特有字段 用来区分是否是支付支付
    public static String uniqueFile = "auth_app_id";
    // 支付类型编码 表示采用了支付宝支付
    public static String payType = "alipay";



}

2.实现类

@Service
@Slf4j
public class AlipayService implements PayStrategy {
    @Resource
    private ClientCore clientCore;
    @Resource
    private SdopRecPayMapper sdopRecPayMapper;


    @Override
    public String createOrder(SdopRecPay sdopRecPay, String json) {
        String pageRedirectionData = "";
        if (sdopRecPay.getPayPlan() != null) {
            sdopRecPay.setPayPlan(sdopRecPay.getPayActual());
        }
        sdopRecPay.setAuthTypeDesc(clientCore.mdm.getDescDict("SDOP_AUTH_TYPE", sdopRecPay.getAuthType(), "1"));
        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConstant.gatewayUrl, AlipayConstant.appId, AlipayConstant.merPrivateKey,
                "json", AlipayConstant.charset, AlipayConstant.aliPublicKey, AlipayConstant.signType);

        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        //异步接收地址,仅支持http/https,公网可访问
        request.setNotifyUrl(AlipayConstant.notifyUrl);
        //同步跳转地址,仅支持http/https
        request.setReturnUrl(AlipayConstant.returnUrl);
        /******必传参数******/
        JSONObject bizContent = new JSONObject();
        //商户订单号,商家自定义,保持唯一性
        bizContent.put("out_trade_no", sdopRecPay.getPayId());
        //支付金额,最小值0.01元
        bizContent.put("total_amount", sdopRecPay.getPayActual().doubleValue());
        //订单标题,不可使用特殊符号
        bizContent.put("subject", sdopRecPay.getAuthTypeDesc());
        //电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
        request.setBizContent(bizContent.toString());
        // 也可以是GET请求
        AlipayTradePagePayResponse response = null;
        sdopRecPay.setPayTime(new Date());
        try {
            log.info("调用统一收单下单并支付页面接口参数{}", bizContent.toString());
            response = alipayClient.pageExecute(request, "POST");
            log.info("调用统一收单下单并支付页面接口结果{}", response.getBody());
            if (response.isSuccess()) {
                System.out.println("调用成功");
                pageRedirectionData = response.getBody();
            } else {
                sdopRecPay.setStatus("E");
                pageRedirectionData = "调用失败";
            }

        } catch (AlipayApiException e) {
            sdopRecPay.setStatus("E");
            pageRedirectionData = "调用异常:" + e.getErrMsg();
        }
        sdopRecPayMapper.deleteById(sdopRecPay.getPayId());
        sdopRecPay.setCreateJson(json);
        sdopRecPayMapper.insert(sdopRecPay);
        return pageRedirectionData;
    }

    /**
     * 统一收单交易查询接口
     */
    @Override
    public boolean queryResult(String payId) {
        boolean result = false;
        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConstant.gatewayUrl, AlipayConstant.appId, AlipayConstant.merPrivateKey,
                "json", AlipayConstant.charset, AlipayConstant.aliPublicKey, AlipayConstant.signType);
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject bizContent = new JSONObject();
        // trade_no out_trade_no 二选一
        bizContent.put("out_trade_no", payId);
        request.setBizContent(bizContent.toString());
        AlipayTradeQueryResponse response = null;
        SdopRecPay sdopRecPay = new SdopRecPay();
        sdopRecPay.setPayId(payId);
        try {
            log.info("调用统一收单下单并支付页面接口参数{}", bizContent.toString());
            response = alipayClient.execute(request);
            log.info("统一收单交易查询接口结果{}", response.getBody());
        } catch (AlipayApiException e) {
            sdopRecPay.setQueryMsg("调用异常:" + e.getErrMsg());
        }
        if (response != null && response.isSuccess()) {
            result = true;
            sdopRecPay.setQueryCode(response.getCode());
            sdopRecPay.setQueryMsg(response.getMsg());
        }
        sdopRecPay.setQueryTime(new Date());
        sdopRecPayMapper.updateByCond(sdopRecPay);
        return result;
    }

    /**
     * 同步回调
     */
    @Override
    public void returnPay(HttpServletRequest request, HttpServletResponse response) {
        SdopRecPay sdopRecPay = new SdopRecPay();
        String msg = "";
        String status = "E";
        try {
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), AlipayConstant.charset);
            sdopRecPay.setPayTime(new Date());
            sdopRecPay.setPayId(out_trade_no);
            boolean signVerified = getSignVerified(request);
            if (signVerified) {
                msg = checkPayInfo(request);
                if (StringUtil.isEmpty(msg)) {
                    status = "S";
                    this.queryResult(sdopRecPay.getPayId());
                    response.setContentType("text/html;charset=utf-8");
                    String returnResult = clientCore.tool.getGlobalConfigVal("SDOP_SYS_CONFIG:pay_retrun_url");
                    response.sendRedirect(returnResult);
                }
            }
            sdopRecPay.setStatus(status);
            sdopRecPayMapper.updateByCond(sdopRecPay);
        } catch (Exception e) {
            log.info("调用异常{}", e.getMessage());
        }
    }

    /**
     * 异步回调地址
     */
    @Override
    public JSONObject notifyPay(HttpServletRequest request, HttpServletResponse response) {
        String result = "failure";
        String message = "失败";
        PrintWriter out = null;
        JSONObject body = null;
        try {
            out = response.getWriter();
            boolean signVerified = getSignVerified(request);
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), AlipayConstant.charset);
            //交易状态
            String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), AlipayConstant.charset);
            //支付宝交易凭证号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), AlipayConstant.charset);
            //支付金额信息 渠道+金额
            String fund_bill_list = new String(request.getParameter("fund_bill_list").getBytes("ISO-8859-1"), AlipayConstant.charset);

            SdopRecPay sdopRecPay =  sdopRecPayMapper.selectById(out_trade_no);
            if (signVerified) {
                message = checkPayInfo(request);
                if (StringUtil.isEmpty(message)) {
                    if (trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")) {
                        this.queryResult(sdopRecPay.getPayId());
                        body = JSONObject.parseObject(sdopRecPay.getCreateJson());
                        body.put("payId", out_trade_no);
                    }
                    if (trade_status.equals("TRADE_FINISHED")) {
                        //注意:
                        //不支持退款付款成功、支持退款,并且退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
                        message = "订单已完成";
                    } else if (trade_status.equals("TRADE_SUCCESS")) {
                        //注意:
                        //支持退款,付款完成后,支付宝系统发送该交易状态通知
                        message = "订单付款成功";

                    } else if (trade_status.equals("WAIT_BUYER_PAY")) {
                        message = "交易创建成功";
                    } else if (trade_status.equals("TRADE_CLOSED")) {
                        message = "交易关闭成功";
                    }
                    result = "success";
                }
            } else {
                message = "验签失败";
            }
            sdopRecPay.setRetPayId(trade_no);
            sdopRecPay.setRetCode(trade_status);
            sdopRecPay.setRetMsg(StringUtil.isNotEmpty(message) ? message : fund_bill_list);
            sdopRecPay.setRetTime(new Date());
            sdopRecPayMapper.updateByCond(sdopRecPay);
            out.println(result);
        } catch (IOException e) {
            message = "参数异常";
        }
        return body;
    }

    /**
     * 验签
     */
    private boolean getSignVerified(HttpServletRequest request) throws IOException {
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<>(16);
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = iter.next();
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决,这段代码在出现乱码时使用
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), charset);
            params.put(name, valueStr);
        }
        log.info("验签参数{}", params);

        boolean signVerified = false; //调用SDK验证签名
        try {
            signVerified = AlipaySignature.rsaCheckV1(params, AlipayConstant.aliPublicKey, AlipayConstant.charset, AlipayConstant.signType);
        } catch (AlipayApiException e) {
            log.info("验签异常{}", e.getErrMsg());
        }
        return signVerified;
    }

    /**
     * 验证其他信息
     */
    private String checkPayInfo(HttpServletRequest request) throws UnsupportedEncodingException {
        /*
        1、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
        2、暂无 校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
        3、验证app_id是否为该商户本身。
        4、验证该通知数据中的out_trade_no是否为商户系统中创建的订单号
        */
        SdopRecPay sdopRecPay = null;
        String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), AlipayConstant.charset);
        String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), AlipayConstant.charset);
        String seller_id = new String(request.getParameter("seller_id").getBytes("ISO-8859-1"), AlipayConstant.charset);
        String app_id = new String(request.getParameter("app_id").getBytes("ISO-8859-1"), AlipayConstant.charset);
        if (StringUtil.isNotEmpty(out_trade_no) && StringUtil.isNotEmpty(total_amount) && StringUtil.isNotEmpty(seller_id) && StringUtil.isNotEmpty(app_id)) {
            sdopRecPay = sdopRecPayMapper.selectById(out_trade_no);
            if (sdopRecPay == null) {
                return "订单号不匹配";
            }
            BigDecimal amount = new BigDecimal(total_amount);
            if (sdopRecPay.getPayActual().compareTo(amount) != 0) {
                return "订单金额不匹配";
            }
            if (!app_id.equals(AlipayConstant.appId)) {
                return "APPID不匹配";
            }
        } else {
            return "必填参数不能为空";
        }
        return "";
    }
}

1.3 工厂类

/**
 * 支付策略工厂
 */
@Component
public class PayStrategyFactory {
    private final ApplicationContext applicationContext;

    @Autowired
    public PayStrategyFactory(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    public PayStrategy getPayStrategy(String payType) {
        if(AlipayConstant.payType.equals(payType)){
            return applicationContext.getBean(AlipayService.class);
        }
        throw new ClientCustomException("没找到支付策略,请联系管理员!");
    }
    public PayStrategy getPayStrategyByPara(HttpServletRequest request) {
        //支付宝回调
        String auth_app_id = request.getParameter(AlipayConstant.uniqueFile);
        if(StringUtil.isNotEmpty(auth_app_id)){
            return getPayStrategy(AlipayConstant.payType);
        }
        throw new ClientCustomException("没找到支付策略,请联系管理员!");
    }
}

2.实现通用的支付接口

2.1支付策略Controller

    // 支付
    @PostMapping("/createOrder")
    public void createOrder(@RequestBody SdopAuthBody sdopAuthBody, HttpServletRequest request, HttpServletResponse response) {
        SdopCust loginUser = tokenService.getLoginUser(request);
        sdopAuthBody.setLoginCustId(loginUser.getCustId());
        payStrategyService.createOrder(sdopAuthBody, response);
    }
    // 查询
    @PostMapping("/queryResult/{payId}/{payType}")
    public ClientAjaxResult queryResult(@PathVariable String payId, @PathVariable String payType, HttpServletResponse response) {
        boolean b = payStrategyService.queryResult(payId, payType);
        return b ? ClientAjaxResult.success(b) : ClientAjaxResult.error("支付未成功");
    }
    // 同步
    @GetMapping("/returnPay")
    public void returnPay(HttpServletRequest request, HttpServletResponse response) {
        payStrategyService.returnPay(request, response);
    }
    // 异步
    @PostMapping("/notifyPay")
    public void notifyPay(HttpServletRequest request, HttpServletResponse response) {
        //支付宝必须是post请求
        payStrategyService.notifyPay(request, response);
    }

2.2支付策略Service

@Service
@Slf4j
public class PayStrategyService {
    @Resource
    private PayStrategyFactory payFactory;
    @Resource
    private SdopAuthService sdopAuthService;


    /**
     * 支付接口
     * 参数 authType payPlan payActual payId
     */
    public void createOrder(SdopAuthBody sdopAuthBody, HttpServletResponse httpResponse) {
        PrintWriter out = null;
        try {
            // 重新计算预防篡改
            sdopAuthBody = sdopAuthService.confirmInfo(sdopAuthBody);
            PayStrategy alipay = payFactory.getPayStrategy(sdopAuthBody.getPayType());
            SdopRecPay sdopRecPay = new SdopRecPay();
            sdopRecPay.setPayPlan(sdopAuthBody.getPrice());
            sdopRecPay.setPayActual(sdopAuthBody.getPrice());
            sdopRecPay.setAuthType(sdopAuthBody.getAuthType());
            /*ClientResult clientResult = clientCore.tool.getNumDocB("SDOP_PAY",null);
            if(!clientResult.getStatus().equals("S")){
                throw new ClientCustomException("创建支付号失败,请联系管理员");
            }*/
            sdopRecPay.setPayId(sdopAuthBody.getLoginCustId() + ClientUtilSeq.getSnowflake());
            String json = JSON.toJSONString(sdopAuthBody);
            String pageRedirectionData = alipay.createOrder(sdopRecPay, json);
            if (StringUtil.isEmpty(pageRedirectionData)) {
                throw new ClientCustomException("创建支付订单失败,请联系管理员");
            }
            httpResponse.setContentType("text/html;charset=utf-8");
            out = httpResponse.getWriter();
            out.println(pageRedirectionData);
        } catch (IOException e) {
            log.info("写入异常{}", e.getMessage());
        }
    }

    /**
     * 查询接口
     * 参数 authType payPlan payActual payId
     */
    public boolean queryResult(String payId, String payType) {
        PayStrategy alipay = payFactory.getPayStrategy(payType);
        return alipay.queryResult(payId);
    }

    /**
     * 同步回调 通过特有参数判断是什么支付
     */
    public void returnPay(HttpServletRequest request, HttpServletResponse response) {
        PayStrategy alipay = payFactory.getPayStrategyByPara(request);
        alipay.returnPay(request, response);
    }

    /**
     * 异步回调地址 通过参数判断是什么支付
     */
    public void notifyPay(HttpServletRequest request, HttpServletResponse response) {
        PayStrategy alipay = payFactory.getPayStrategyByPara(request);
        JSONObject body = alipay.notifyPay(request, response);
        if (body != null) {
            SdopAuthBody sdopAuthBody = JSONObject.toJavaObject(body, SdopAuthBody.class);
            // 付款成功或者完成生成授权码
            sdopAuthService.genAuthCode(sdopAuthBody);
        }
    }
}

3.前端实现

    // 支付
    btnPay() {
      if (this.submitFormCheck()) {
        // 设置支付策略
        this.objDataOne.payType = "alipay"
        createOrder(this.objDataOne).then((response) =>{
          const newWindow = window.open('');
          newWindow.document.write(response);
          newWindow.focus();
          //document.write(response)
          this.activeStep = 3;
          this.dialogParams.retcode = "S"
        })
      }
    },

文章来源:https://blog.csdn.net/sky2019116/article/details/135641253
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。