杉德微信小程序(云函数h5)支付详解

最近在工作中,有机会使用了杉德的微信支付,其实对于杉德我也不是很了解,这里,我也只说一下我对接的过程,希望对后面有接这个支付的朋友们会有一点帮助,然后就是,我只是开发,里面的一些配置我其实也不太清楚,所以大家如果出现一些什么配置的问题,自己多去和领导沟通,是不是什么配置没弄。
先来看看杉德的官网: https://open.sandpay.com.cn/developmentAccess/docs

在这里插入图片描述
找到自己对应的业务,去查看对应的api接口文档,我这里是微信小程序。
在这里插入图片描述
如果有时间的话,我建议大家从头都看一遍,而不是直接就看api文档,最起码要看看支付流程吧,错误码等这些东西。
看完这些东西后,我对接是杉德新收银台,这个可能是官方给的新文档,我们来看看支付的流程:
在这里插入图片描述
从这张图来看,后台只需要做创建订单,然后生成签名,返回到前端,然后写一个接收支付回调的方法就搞定了,实际上,好像接所有的支付接口好像都是这样,很简单的,接下来就看看下单需要的参数。

支付下单

1、商户服务端下单支付的订单信息数据包、附带支持的支付列表编码
2、参数说明:
(非必填字段是指参数参与打包,参数值可为空字符) 请注意不参与签名字段!!!!!
剔除不参与签名字段和sign字段,为空字段剔除,不参与签名。如:return_url=“”(不参与签名)

这是下单参数的注意点,下单的全部参数我就不一 一 列举出来了,我就说说参数中需要注意的几个点吧
notify_url 回调地址,这里是接收支付结果的方法,可以在这里获取支付的结果,并且进行自己的业务处理
product_code : 支付的产品编号 ,好好看看 杉德有很多产品,支付,微信等,每一个都不一样,比如 微信小程序 h5 的是 02010006
pay_extra 支付扩展域 这里大家就自己看看就行了,根据文档的填

meta_option : 终端/网站参数 可以填个默认值过去,一定是必填的,这里如果不填会出现访问 404的画面
在这里插入图片描述

签名流程

在这里插入图片描述
对照上面的步骤一步一步的来就很好去理解了,把上面描述的变成代码就ok了。
后面就是最后的一步了,服务端把上面的参数拼接成连接放回到客户端,客户端直接拿到链接跳转就能进入支付的页面了。
在这里插入图片描述
提供就以上几种,这里是对应上面参数的产品编号的,大家填的啥就看啥
在这里插入图片描述
很简单了,把上面的连接拼接参数 #/applet 去区分不同的支付场景的,一定要注意。

代码实例

 /**
     *
     * @param orderId 订单号 服务端创建 uuid 就行
     * @param orderAmt 订单金额 自己定义 12
     * @param createIp 客户端ip 当前请求的ip地址 前端传入
     * @param goodsName 商品名称 123456 前端传入
     * @param productCode 支付产品 02010006 支付的产品编号,上面说了的,自己看文档
     * @return
     */
    @Override
    public String createOrder(String orderId, Double orderAmt, String createIp, String goodsName, String productCode) {
        // 参考文档:body 前面这些是必须需要签名的所以放在签名
        Map<String, String> body = new HashMap<>();
        Date date = new Date();
        body.put("version", "1.0"); // 版本号
        body.put("mer_no",sandpayConf.getMerchMid());
        body.put("mer_key",sandpayConf.getMerKey());
        body.put("mer_order_no",orderId);//订单号
        body.put("create_time",df.format(date));//创建时间
        body.put("order_amt",orderAmt/100+"");//订单金额
        body.put("notify_url",sandpayConf.getGateWayBacknoticeUrl());//回调地址
        body.put("return_url","");//支付后返回的商户显示页面 没有就填 “”
        body.put("create_ip",createIp.replace(".","_"));
        body.put("store_id","000000");//门店号
        JSONObject jsonObject = new JSONObject(); // 支付扩展域 内容字段
        jsonObject.put("wx_app_id",sandpayConf.getWxappid()); //appid
        jsonObject.put("gh_ori_id",sandpayConf.getWxorid()); // "gh_ori_id":"小程序原始id
        jsonObject.put("miniProgramType","1");
        body.put("pay_extra",jsonObject.toString());//支付扩展域
        body.put("accsplit_flag","NO");
        body.put("sign_type","MD5");//签名类型
        body.put("gh_static_url",sandpayConf.getWxStaticUrl()); //小程序云静态网站url" 如果是小程序支付,一定要加上,不然支付请求就看不到了,直接问领导拿
        try {
            // 报文签名 
            String reqSign = sadeSign(body);
            body.put("sign",reqSign);
            body.put("goods_name",goodsName);
            body.put("expire_time",endTime(date));//失效时间
            body.put("product_code",productCode);//  支付产品,多个以英文逗号分隔,具体产品见产品编码文档
            body.put("clear_cycle","0");
            body.put("jump_scheme","sandcash://scpay");
//            Map<String, Object> metaOption = new HashMap<>();
            JSONObject metaOption = new JSONObject();
            metaOption.put("s","Android");
            metaOption.put("n","");
            metaOption.put("id","");
            metaOption.put("sc","测试");
            body.put("meta_option",metaOption.toString());
            //APPRY_MIXIENET 官方的接口地址 https://sandcash.mixienet.com.cn/h5/
            //这一段就是官方给的页面地址 拼接参数 #/alipayh5 ,弄好后,放回给客户端,让他打开地址进行支付
            String url = APPRY_MIXIENET+"?"+getUrl(body);
            return url;
        } catch (Exception e) {
            log.error("CashierPayServlet post error <<<", e);
        }
        return null;
    }

签名方法:

 /**
     * 签名方法
     *
     * @param data 待签名数据
     * @return
     * @throws Exception
     */
    public String sadeSign(Map<String, String> data) throws Exception {
        if (null == data) {
            return null;
        } else {
            String merprivateKey = sandpayConf.getMerprivateKey(); //杉德的md5 key
           return  generateSignature(data, merprivateKey);
        }
    }

    /**
     * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
     *
     * @param data 待签名数据
     * @param key API密钥
     * @return  String 签名
     * @see Exception
     */
    public static String generateSignature(final Map<String, String> data, String key) throws Exception {
        Set<String> keySet = data.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
                sb.append(k).append("=").append(data.get(k).trim()).append("&");
        }
        sb.append("key=").append(key);
        return MD5(sb.toString());
    }

    /**
     *
     *
     * @param data 待处理数据
     * @return String MD5结果
     * @see Exception
     */
    public static String MD5(String data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }
    
    public String endTime(Date creatTime){
        //设置生效时间为一小时后
        Calendar cal = Calendar.getInstance();
        cal.setTime(creatTime);
        cal.add(Calendar.HOUR, 1);// 24小时制
        Date effectivetime = cal.getTime();
        return df.format(effectivetime);
    }

这一段代码就对应了上面 杉德的签名的描述,大家可以好好看看,如果对自己业务有改动的地方,自己就动手改改吧

生成签名后,参数拼接方法:

    public  String getUrl(Map<String, String> jsonObject) throws UnsupportedEncodingException {
        String paramStr = "";
        if (null != jsonObject) {
            for (String key : jsonObject.keySet()) {
                if (!StringUtils.isEmpty(paramStr)) {
                    paramStr += "&";
                }
                if(key.equals("gh_static_url")){
                    paramStr += key + "=" + jsonObject.get(key);
                }else{
                    paramStr += key + "=" + URLEncoder.encode(jsonObject.get(key).toString(),"utf-8");
                }
            }
        }
        return  paramStr+"#/applet"; //注意这里哦,如果不是微信小程序h5支付得改一下自己对应跳转的位置
    }

好,到这里杉德的支付基本就搞定了,作者上面的代码是真实跑过的,如果有问题肯定不是我的问题,
希望对大家有帮助。
如果这篇文章,有帮助到大家的,请给作者一个一键三连,谢谢。

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值