Africa项目之支付部分(一、对接支付宝)

环境介绍

开发环境

实际生产环境,每次测试需要0.01元的巨资;使用的为前端为uiapp 后端为spring boot框架

前期准备工作:

通过支付宝平台注册获取商户appid,使用密钥工具(Windowsios)生成商家的公私密钥,通过用户的公钥在支付宝端进行注册,形成支付宝公钥

支付宝密钥支付流程
支付宝密钥支付流程
###在pom中导入maven依赖

<!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-sdk-java -->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.10.97.ALL</version>
        </dependency>

以下为配置类

import org.springframework.context.annotation.Configuration;
@Configuration
public class AliPayConfig {
	// 商户appid
	public static String APPID = "保密";
	// 私钥 pkcs8格式的
	public static String RSA_PRIVATE_KEY = "保密";
	// 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
	public static String notify_url = "http://保密:8085/Alipay/notify";
	// 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
	public static String return_url = "http://商户网关地址/alipay.trade.wap.pay-JAVA-UTF-8/return_url.jsp";
	// 请求网关地址
	public static String gatewayUrl = "https://openapi.alipay.com/gateway.do";
	// 编码
	public static String CHARSET = "UTF-8";
	// 返回格式
	public static String FORMAT = "json";
	// 支付宝公钥
	public static String ALIPAY_PUBLIC_KEY = "保密";
	// 日志记录目录
	public static String log_path = "/log";
	// RSA2
	public static String SIGNTYPE = "RSA2";
}

还是配置类,主要是通过Bean来管理了创建DefaultAlipayClient,避免之后每次调用都要写一堆参数去new


import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;

@Slf4j
@Component
@Configuration
public class AliPayClientConfig {
	@Resource
	private AliPayConfig alipayConfig;

	/**
	 * 支付宝gatewayUrl
	 */
	private String gatewayUrl = alipayConfig.gatewayUrl;
	/**
	 * 商户应用id
	 */
	private String appid = alipayConfig.APPID;
	/**
	 * RSA私钥,用于对商户请求报文加签
	 */
	private String appPrivateKey = alipayConfig.RSA_PRIVATE_KEY;
	/**
	 * 支付宝RSA公钥,用于验签支付宝应答
	 */
	private String alipayPublicKey = alipayConfig.ALIPAY_PUBLIC_KEY;
	/**
	 * 签名类型
	 */
	private String signType = alipayConfig.SIGNTYPE;
	/**
	 * 格式
	 */
	private String formate = alipayConfig.FORMAT;
	/**
	 * 编码
	 */
	private String charset = alipayConfig.CHARSET;
	/**
	 * 同步地址
	 */
	private String returnUrl = alipayConfig.return_url;
	/**
	 * 异步地址
	 */
	private String notifyUrl = alipayConfig.notify_url;
	/**
	 * 最大查询次数
	 */
	private static int maxQueryRetry = 5;
	/**
	 * 查询间隔(毫秒)
	 */
	private static long queryDuration = 5000;
	/**
	 * 最大撤销次数
	 */
	private static int maxCancelRetry = 3;
	/**
	 * 撤销间隔(毫秒)
	 */
	private static long cancelDuration = 3000;
		public String getAppid() {
		return appid;
	}

	public void setAppid(String appid) {
		this.appid = appid;
	}

	public String getAppPrivateKey() {
		return appPrivateKey;
	}

	public void setAppPrivateKey(String appPrivateKey) {
		this.appPrivateKey = appPrivateKey;
	}

	public String getAlipayPublicKey() {
		return alipayPublicKey;
	}

	public void setAlipayPublicKey(String alipayPublicKey) {
		this.alipayPublicKey = alipayPublicKey;
	}

	public String getSignType() {
		return signType;
	}

	public void setSignType(String signType) {
		this.signType = signType;
	}

	public String getFormate() {
		return formate;
	}

	public void setFormate(String formate) {
		this.formate = formate;
	}

	public String getCharset() {
		return charset;
	}

	public void setCharset(String charset) {
		this.charset = charset;
	}

	public String getGatewayUrl() {
		return gatewayUrl;
	}

	public void setGatewayUrl(String gatewayUrl) {
		this.gatewayUrl = gatewayUrl;
	}

	public String getReturnUrl() {
		return returnUrl;
	}

	public void setReturnUrl(String returnUrl) {
		this.returnUrl = returnUrl;
	}

	public String getNotifyUrl() {
		return notifyUrl;
	}

	public void setNotifyUrl(String notifyUrl) {
		this.notifyUrl = notifyUrl;
	}

	@Bean
	public AlipayClient alipayClient(){
		return new DefaultAlipayClient(this.getGatewayUrl(),
				this.getAppid(),
				this.getAppPrivateKey(),
				this.getFormate(),
				this.getCharset(),
				this.getAlipayPublicKey(),
				this.getSignType());
	}
}

支付宝支付Controller

C层本来不该写业务逻辑的,那时为了测试方便就没改回来,见谅,我还是个小菜。
请求参数之后我会封装一下,大家勉强看看吧,支付部分都通了

import com.commerce.mall.common.api.CommonResult;
import com.commerce.mall.mapper.OmsOrderMapper;
import com.commerce.mall.model.OmsOrder;
import com.commerce.mall.model.OmsOrderExample;
import com.commerce.mall.portal.service.AlipayOrderService;
import io.micrometer.core.instrument.util.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;


/**
 * 支付宝支付Controller
 */
@Api(tags = "AlipayOrderController", description = "支付宝支付相关接口 测试中")
@RestController
@SpringBootApplication
@RequestMapping("/Alipay")
public class AliPayOrderController {
    @Autowired
        private AlipayOrderService alipayOrderService;
    @Autowired
        private OmsOrderMapper omsOrderMapper;

        /**
         * 创建订单
         */
        @ApiOperation(value = "创建订单", notes = "支付宝支付创建订单")
        @PostMapping("/createOrder")
        public CommonResult createOrder(@ApiParam(value = "说明:商户网站唯一订单号") @RequestParam String orderSn,
                                        @ApiParam(value = "说明:订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]") @RequestParam Double total_amount,
                                        @ApiParam(value = "说明:商品的标题/交易标题/订单标题/订单关键字等") @RequestParam String subject,
                                        @ApiParam(value = "商品描述") @RequestParam String body) {
            try {
                // 1、验证订单是否存在
                OmsOrderExample omsOrder = new OmsOrderExample();
                omsOrder.createCriteria().andOrderSnEqualTo(orderSn);
                long count = omsOrderMapper.countByExample(omsOrder);
                int newcount = (int)count;
                if(newcount < 1){return CommonResult.failed("订单不存在,订单生成失败");}
                // 2、创建支付宝订单
                String orderStr = alipayOrderService.createOrder(orderSn, total_amount, subject,body);
                return CommonResult.success("data", orderStr);
            } catch (Exception e) {
                return CommonResult.failed("订单生成失败"+e);
            }
               }

        /**
         * 支付异步通知
         * 接收到异步通知并验签通过后,一定要检查通知内容,
         * 包括通知中的app_id、out_trade_no、total_amount是否与请求中的一致,并根据trade_status进行后续业务处理。
         * https://docs.open.alipay.com/194/103296
         */
        @ApiOperation(value = "支付异步通知", notes = "接收到异步通知并验签通过后,一定要检查通知内容")
        @PostMapping("/notify")
        public String notify(HttpServletRequest request) {
            // 验证签名,确保是支付宝返回的
            boolean flag = alipayOrderService.rsaCheckV1(request);
            if (flag) {
                String tradeStatus = request.getParameter("trade_status"); // 交易状态
                String outTradeNo = request.getParameter("out_trade_no"); // 商户订单号
                String tradeNo = request.getParameter("trade_no"); // 支付宝订单号
                String totalAmount = request.getParameter("total_amount"); // 本次交易支付的订单金额
                String sellerId = request.getParameter("seller_id"); // 收款支付宝账号对应的支付宝唯一用户号
                String notify_time = request.getParameter("notify_time"); // 通知的发送时间。格式为yyyy-MM-dd HH:mm:ss
                String trade_status = request.getParameter("trade_status"); // 交易目前所处的状态
                /**
                 * 还可以从request中获取更多有用的参数,自己尝试
                 */
                boolean notify = alipayOrderService.notify(tradeStatus, outTradeNo, tradeNo,totalAmount,sellerId,notify_time,trade_status);
                if(notify){
                    return "success";
                }
            }
            return "fail";
        }

    @ApiOperation(value = "查询订单", notes = "查询订单,半成品,禁止调用")
    @PostMapping("/cheak")
    public CommonResult checkAlipay(@ApiParam(value = "订单号") @RequestParam String orderNo) {
        if(StringUtils.isBlank(orderNo)){
            return CommonResult.failed("订单编号不能为空");
        }
        String aByte = alipayOrderService.checkAlipay(orderNo);
        return CommonResult.success("data",aByte);
    }

        @ApiOperation(value = "退款", notes = "退款,半成品")
        @PostMapping("/refund")
        public CommonResult refund(@ApiParam(value = "订单号") @RequestParam String orderNo,
        @ApiParam(value = "退款金额") @RequestParam double amount,
        @ApiParam(value = "退款原因") @RequestParam(required = false) String refundReason) {
            if(StringUtils.isBlank(orderNo)){
                return CommonResult.failed("订单编号不能为空");
            }
            if(amount <= 0){
                return CommonResult.failed("退款金额必须大于0");
            }
            String refund = alipayOrderService.refund(orderNo, amount, refundReason);
            if (StringUtils.isBlank(refund)){return CommonResult.failed("失败");}
            return CommonResult.success("退款成功");
        }
    }

支付宝管理Service实现类(Service没啥看的,就不贴了)

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.commerce.mall.mapper.OmsAlipayFlowMapper;
import com.commerce.mall.mapper.OmsOrderMapper;
import com.commerce.mall.model.*;
import com.commerce.mall.portal.config.AliPayClientConfig;
import com.commerce.mall.portal.service.AlipayOrderService;
import io.micrometer.core.instrument.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 支付宝管理Service实现类
 */
@Service
public class AlipayOrderServiceImpl implements AlipayOrderService {
    private final Logger logger = LoggerFactory.getLogger(AlipayOrderServiceImpl.class);
    @Autowired
    private AliPayClientConfig alipayClientConfig;
    @Autowired
    private OmsOrderMapper omsOrderMapper;
    @Autowired
    private OmsAlipayFlowMapper omsAlipayFlowMapper;

    @Override
    public String createOrder(String orderSn, Double total_amount, String subject, String body) throws AlipayApiException {

        //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setOutTradeNo(orderSn);
        model.setSubject(subject);
        model.setTotalAmount(String.valueOf(total_amount));
        model.setBody(body);
        //model.setPassbackParams("公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数");
        model.setProductCode("QUICK_MSECURITY_PAY");
        // 该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天 (屁股后面的字母一定要带,不然报错)
        model.setTimeoutExpress("30m");    //
        //实例化具体API对应的request类,类名称和接口名称对应,app支付接口2.0
        //https://opendocs.alipay.com/apis/api_1/alipay.trade.app.pay
        AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest();
        ali_request.setBizModel(model);
        ali_request.setNotifyUrl(alipayClientConfig.getNotifyUrl());// 回调地址
        //就是orderString 可以直接给客户端请求,无需再做处理。
        try {
            // 注意这里是sdkExecute方法, 如果是网页支付的话调用pageExecute方法
            return alipayClientConfig.alipayClient().sdkExecute(ali_request).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new RuntimeException("支付异常");
        }
    }

    @Override
    public boolean notify(String tradeStatus, String orderNo, String tradeNo,String totalAmount,String sellerId,String notify_time,String trade_status)   {
        if ("TRADE_FINISHED".equals(tradeStatus)
                || "TRADE_SUCCESS".equals(tradeStatus)) {
            // 支付成功,根据业务逻辑修改相应数据的状态
            //修改订单表状态
            OmsOrder omsOrder = new OmsOrder();
            omsOrder.setId(Long.parseLong(orderNo));
            //支付方式:0->未支付;1->支付宝;2->微信
            omsOrder.setPayType(1);
            //订单状态:0->待付款;1->待发货;2->已发货;3->已完成;4->已关闭;5->无效订单;6->售后
            omsOrder.setStatus(1);
            int i = omsOrderMapper.updateByPrimaryKeySelective(omsOrder);
            //创建支付宝流水记录
            OmsAlipayFlow alipayFlow = new OmsAlipayFlow();
            alipayFlow.setOrderSn(orderNo);
            alipayFlow.setTradeNo(tradeNo);
            alipayFlow.setTotalAmount(new BigDecimal(totalAmount));
            alipayFlow.setSellerId(Long.parseLong(sellerId));
            //把string转化为date
            try {
                alipayFlow.setNotifyTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(notify_time));
            } catch (ParseException e) {
                e.printStackTrace();
                return false;
            }
            alipayFlow.setTradeStatus(trade_status);
            int insert = omsAlipayFlowMapper.insert(alipayFlow);
            if (i>0 && insert>0) {
                return true;
            }
        }
        return false;
    }
//开放平台 SDK 提供了 AlipaySignature.rsaCertCheckV1 方法,可以使用该方法对通知报文验签。
//生活号异步通知需要使用 AlipaySignature.rsaCertCheckV2 方法,会保留 sign_type 参数参与验签。
    @Override
    public boolean rsaCheckV1(HttpServletRequest request){
        try {
            Map<String, String> params = new HashMap<>();
            Map<String, String[]> requestParams = request.getParameterMap();
            for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
                String name = (String) 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] + ",";
                }
                params.put(name, valueStr);
            }

            boolean verifyResult = AlipaySignature.rsaCheckV1(params, alipayClientConfig.getAlipayPublicKey(), alipayClientConfig.getCharset(), alipayClientConfig.getSignType());
            return verifyResult;
        } catch (AlipayApiException e) {
            logger.debug("verify sigin error, exception is:{}", e);
            return false;
        }
    }

    @Override
    public String checkAlipay(String outTradeNo) {
        logger.info("==================向支付宝发起查询,查询商户订单号为:"+outTradeNo);

        try {
            AlipayTradeQueryRequest alipayTradeQueryRequest = new AlipayTradeQueryRequest();
            alipayTradeQueryRequest.setBizContent("{" +
                    "\"out_trade_no\":\""+outTradeNo+"\"" +
                    "}");
            AlipayTradeQueryResponse alipayTradeQueryResponse = alipayClientConfig.alipayClient().execute(alipayTradeQueryRequest);
            if(alipayTradeQueryResponse.isSuccess()){
//业务逻辑具体看个人 这不展示了
                switch (alipayTradeQueryResponse.getTradeStatus()) // 判断交易结果
                {
                    case "TRADE_FINISHED": // 交易结束并不可退款
                        //            修改订单状态的代码
                        return "TRADE_FINISHED 交易结束并不可退款";
                     //   break;
                    case "TRADE_SUCCESS": // 交易支付成功
                        //         修改订单状态的代码
                        return "TRADE_SUCCESS 交易支付成功";
                    //    break;
                    case "TRADE_CLOSED": // 未付款交易超时关闭或支付完成后全额退款
                        //            修改订单状态的代码
                        return "TRADE_CLOSED 未付款交易超时关闭或支付完成后全额退款";
                     //   break;
                    case "WAIT_BUYER_PAY": // 交易创建并等待买家付款
                        //          修改订单状态的代码
                        return "WAIT_BUYER_PAY 交易创建并等待买家付款";
                    //    break;
                    default:
                        break;
                }
//                 更新表记录
//                return alipaymentOrder.getTradeStatus();
                return (alipayTradeQueryResponse).toString();
            } else {
                logger.info("==================调用支付宝查询接口失败!");
                return "调用支付宝查询接口失败";
            }
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
    @Override
    public String refund(String orderNo, double amount, String refundReason) {
        AlipayTradeRefundModel model=new AlipayTradeRefundModel();
        // 商户订单号
        model.setOutTradeNo(orderNo);
        // 退款金额
        model.setRefundAmount(String.valueOf(amount));
        // 退款原因
        model.setRefundReason(refundReason);
        // 退款订单号(同一个订单可以分多次部分退款,当分多次时必传)
        // model.setOutRequestNo(UUID.randomUUID().toString());
        AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
        alipayRequest.setBizModel(model);

        AlipayTradeRefundResponse alipayResponse = null;
        try {
            alipayResponse = alipayClientConfig.alipayClient().execute(alipayRequest);
        } catch (AlipayApiException e) {
            logger.error("订单退款失败,异常原因:{}", e);
        }
        if(alipayResponse != null){
            String code = alipayResponse.getCode();
            String subCode = alipayResponse.getSubCode();
            String subMsg = alipayResponse.getSubMsg();
            if("10000".equals(code)
                    && StringUtils.isBlank(subCode)
                    && StringUtils.isBlank(subMsg)){
                // 表示退款申请接受成功,结果通过退款查询接口查询
                // 修改用户订单状态为退款
                OmsOrder omsOrder = new OmsOrder();
                omsOrder.setId(Long.parseLong(orderNo));
                //订单状态:0->待付款;1->待发货;2->已发货;3->已完成;4->已关闭;5->无效订单;6->售后
                omsOrder.setStatus(4);
                int i = omsOrderMapper.updateByPrimaryKeySelective(omsOrder);
                //创建支付宝流水记录
                OmsAlipayFlow alipayFlow = new OmsAlipayFlow();
                //TRADE_CLOSED 未付款交易超时关闭,或支付完成后全额退款
                alipayFlow.setTradeStatus("TRADE_CLOSED");
                OmsAlipayFlowExample example = new OmsAlipayFlowExample();
                example.createCriteria()
                        .andOrderSnNotEqualTo(orderNo);
                int insert = omsAlipayFlowMapper.updateByExampleSelective(alipayFlow,example);
                if (i>0 && insert>0) {
                    return "订单退款成功";
                }
            }
            return null;
        }
        return null;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值