APP第三方支付的实现-支付宝篇

APP第三方支付的实现-支付宝篇

关于支付宝的支付实现,在支付宝开放平台已经有了很完善的开发流程( app支付api)、(app支付demo),最近公司的项目需要使用用到app支付,作为支付的初次体验者,以下把开发的流程以及开发过程中遇到的问题记录下来。

开发准备

官方文档

1. 支付宝沙箱环境
2.配置沙箱账号,下载沙箱测试版支付宝app
3.下载秘钥生成工具,同时配置到沙箱
在这里插入图片描述4.下载客户端调试工具

代码实现

引入支付包支付 jar 包

        <!--alipay-->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.5.0.ALL</version>
        </dependency>

从沙箱环境获取 app_id、支付宝公钥、商户私钥
从官方demo中可以获取到对应的基础配置类

/* *
 *类名:AlipayConfig
 *功能:基础配置类
 *详细:设置帐户有关信息及返回路径
 *修改日期:2020-04-05
 *说明:
 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
 */

@Configuration
public class AlipayConfig {

    //↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

    // 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
    public static String app_id = "";

    // 商户私钥,您的PKCS8格式RSA2私钥
    public static String merchant_private_key = "";
    // 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
    public static String alipay_public_key = "";

    // 服务器异步通知页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public static String notify_url = "";

    // 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public static String return_url = "";

    // 签名方式(自己生成秘钥时使用的加密方式,官方推荐为RSA2)
    public static String sign_type = "RSA2";

    // 字符编码格式
    public static String charset = "utf-8";

    // 支付宝网关(沙箱环境)
    // 正式环境网关为 https://mapi.alipay.com/gateway.do
    public static String gatewayUrl = "https://mapi.alipaydev.com/gateway.do";

配置类中需要注意的几点:

  1. 签名方式一定为以及生成秘钥时使用的签名方式
  2. 支付宝测试环境与正式环境的网关有所不同
  3. 服务器异步回调url 一定为外网可访问的地址(localhost 是访问不到的)。有服务器的可以写自己或公司服务器的公网IP。如果本地回调测试可以进行一下内网穿透,来让外网访问本地服务。
    附:NETAPP内网穿透教程
    下载内网穿透客户端
    购买免费的隧道后只需要配置自己的端口号即可
    根据教程实现内网穿透对应的Forwarding就是可访问的内网的域名。回调地址写入 域名/xxx/xxx 即可访问本地方法的回调
    在这里插入图片描述
支付接口
    @RequestMapping(value = "/pay", method = RequestMethod.POST)   // 参数+body 商品描述 type 支付设置
    @ResponseBody
    public Msg payController(ServletRequest request, HttpServletResponse response, @RequestBody PayParameters payParameters) throws IOException {

            //这里你可以做一些存表操作..具体根据你们自己的业务来操作... 比如生成预支付订单
            String orderString = "";//这个字符串是用来返回给前端的
            // 获取用户的支付宝账号信息

            String appId = AlipayConfig.app_id  // appId
            String merchantPrivateKey = AlipayConfig.merchant_private_key // 商户私钥
            String publicKey = AlipayConfig.alipay_public_key // 支付包公钥
            //获得初始化的AlipayClient
            AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, appId, merchantPrivateKey, "json", AlipayConfig.charset, publicKey, AlipayConfig.sign_type);
            //设置请求参数
            AlipayTradeAppPayRequest alipayRequest = new AlipayTradeAppPayRequest();
            //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            // 信息描述 自定义
            model.setBody("购买" + payParameters.getCommodity());
            // 商品名称  自定义
            model.setSubject("购买" + payParameters.getCommodity());
            //订单编号  根据用户id生成订单编号
            model.setOutTradeNo("自己生成订单编号");
            //交易超时时间
            model.setTimeoutExpress("30m");
            //支付金额  只能保留两位小数
            model.setTotalAmount(money.toString());

            //销售产品码(固定值) //这个不做多解释..看文档api接口参数解释
            model.setProductCode("QUICK_MSECURITY_PAY");
            alipayRequest.setBizModel(model);
            alipayRequest.setNotifyUrl(AlipayConfig.notify_url);        	// 异步回调地址
            // 这里和普通的接口调用不同,使用的是sdkExecute
            //返回支付宝订单信息(预处理)
            AlipayTradeAppPayResponse alipayTradeAppPayResponse = null;
            try {
                alipayTradeAppPayResponse = alipayClient.sdkExecute(alipayRequest);
            } catch (AlipayApiException e) {
                e.printStackTrace();
            }
            //就是orderString 可以直接给APP请求,无需再做处理。
            orderString = alipayTradeAppPayResponse.getBody();
            return Msg.success().add("orderString", orderString);
            }

支付接口调用之后会生成一个加密的 orderString 拿着这个orderString 去之前下载的客服端调试中测试,看是否能唤起沙箱支付宝 并付款。
如付款成功后,支付宝会异步回调我们定义的接口,回调接口如下:

@RestController
public class AliNotify {

    private static final Logger log = LoggerFactory.getLogger(AliNotify.class);

    /**
     * 支付宝支付成功后.异步请求该接口
     *
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/aliNotify", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class) //开启事务
    public String aliNotify(HttpServletRequest request) throws IOException {

        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        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] + ",";
            }
            //乱码解决,这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        //切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
        //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)

        //2.封装必须参数
        String out_trade_no = request.getParameter("out_trade_no");            // 商户订单号
        String orderType = request.getParameter("body");                    // 订单内容
        String tradeStatus = request.getParameter("trade_status");            //交易状态


        // 3.签名验证
        boolean flag = false;

        String appId = ;  // appId
        String merchantPrivateKey = ; // 商户私钥
        String publicKey = ; // 支付包公钥

        try {
            flag = AlipaySignature.rsaCheckV1(params, publicKey, AlipayConfig.charset, AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        //4.对验签结果进行处理 
        if (flag) {
            if (tradeStatus.equals("TRADE_SUCCESS")) {    //只处理支付成功的订单: 修改交易表状态,支付成功
                //此处可以做一些支付成功后的操作,比如修改订单状态为已支付
                 return "success";
            }
        }
        return "fail";
    }
}

支付流程已完成

代码中的具体使用到的实体类 如下

// 支付入参  根据自己实际需求来使用 数据都可模拟
public class PayParameters {

    // 支付类型   --前端传入 微信 or 支付包
    private Integer type;

    // 商品姓名  --前端传入
    private String productName;

    // 商品描述  
    private String body;

    // 订单编号 
    private String orderNum;

    // 付款金额  --在接口中根据实际计算金额  数据可模拟
    private BigDecim alpayAmount;

    // 购买类型  --前端传入
    private String commodity;

    // 购买规格  --前端传入
    private Integer commoditySpecifications;

    // 销售产品码 固定
    private String productCode;

	// get set 方法

Msg 定义的一个返回对象


//专门用来返回json数据的通用类
public class Msg {
    //状态码100-成功    200-失败
    private int code;
    private String msg;
    private Map<String, Object> extend = new HashMap<String, Object>();

    public static Msg success() {
        Msg result = new Msg();
        result.setCode(100);
        result.setMsg("处理成功");
        return result;
    }

    public static Msg NoImpact() {
        Msg result = new Msg();
        result.setCode(300);
        result.setMsg("处理结束");
        return result;
    }

    public static Msg fail() {
        Msg result = new Msg();
        result.setCode(200);
        result.setMsg("处理失败");
        return result;
    }

    public Msg() {
    }

    public Msg(int code, String msg, Map<String, Object> extend) {
        this.code = code;
        this.msg = msg;
        this.extend = extend;
    }

    public Msg add(String key, Object value) {
        this.getExtend().put(key, value);
        return this;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Map<String, Object> getExtend() {
        return extend;
    }

    public void setExtend(Map<String, Object> extend) {
        this.extend = extend;
    }
}

以上就是App支付唤醒支付包支付的全流程。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值