为您推荐:
精华内容
最热下载
问答
  • 5星
    8.91MB weixin_40228600 2021-04-26 18:30:33
  • 10.88MB guoruibin123 2021-04-24 08:52:12
  • 支付简单来说就是服务端集成相应的SDK,微信支付宝都有对应不同服务端语言的SDK代码,修改的只有少部分参数,然后定义需要的参数接口暴露给前端。用户点击下单以后,后端接收前端的参数,如用户id(一般支付从token...

    支付简单来说就是服务端集成相应的SDK,微信支付宝都有对应不同服务端语言的SDK代码,修改的只有少部分参数,然后定义需要的参数接口暴露给前端。用户点击下单以后,后端接收前端的参数,如用户id(一般支付从token获取),商品id的集合等创建订单。价格一般是后端自己计算,并且需要使用bigdecima类型避免金额精度损失。然后服务端开启定时任务,一般30分钟,若用户未支付,定时任务会关闭该订单。
    接着是支付,用户下单以后点击支付,后端会根据对应的订单id调用SDK接口,获取对应的url返回给前端,前端打开对应的url网页,微信支付宝会和后端建立socket,实时返回用户的支付情况,支付成功后会调用配置好的回调url,此时支付完成,前端第三方的支付网页自动重定向到之前配置的回调url,后端会在支付成功的钩子函数拿到提示,修改订单的支付状态,此时支付完成。
    现在很多网站都是二维码付款,二维码网页一般自己提供,此时需要前后端建立websocket(ajax轮巡一般不采用),在用户支付完成后关闭该网页。

    • 沙箱环境初始化配置
    • 支付请求发起
    • 支付回调处理

    商品浏览 > 添加购物车 > 结算 > 计算商品总价 > 生成订单 > 选择支付方式 > 支付成功回调

    1. 用户在客户端提交订单 向服务器端发送请求
    2. 服务器返回支付地址,引导客户端跳转到支付地址
    3. 用户支付
    4. 支付成功,支付宝重定向到服务端预设的客户端地址,通知用户支付结果。 同时支付宝向服务端发送 post 请求(请求地址是提前设置好的)告诉服务器当前支付结果 ,服务端创建订单,根据支付结果修改订单状态(未支付、已支付)

    支付宝流程

    支付流程:先去调后台服务的支付接口,传递支付宝和服务端所需参数,服务端会返回一个支付宝支付页面链接,然后前端跳转到链接进行支付,支付完成支付宝会自动跳转到服务端定好的前端指定页面,支付即完成。

    在用户在浏览器点击进入支付过程按钮后,会向网站服务器发送一个带有相关信息的请求,然后服务器会将订单所需要的信息和支付完成后跳转回来的地址一同向支付宝的服务器发送一个请求,然后会得到一个可以用来打开支付页面的url 地址。接着网站服务器会将这个url 地址返回给浏览器,此时浏览器就可以跳转到这个支付页面的支付宝的 url,待到支付完成后,支付宝的支付页面会跳转到之前服务器告知的返回页面,这样就又会回到自己的网站了。浏览器跳转回自己网站的同时,支付宝的服务器还会向网站服务器发送一个post请求,服务器接受到这个 post 请求就可以对订单状态进行处理了。

    a. 客户端点击购买, 向服务端发送请求, 并入参相应参数 
    
    b. 服务端根据接收的信息, 校验通过后, 向支付宝下单, 并获取支付地址, 将该地址传回客户端
    
    c. 客户端获取地址后, 跳转到该支付地址
    
    d. 该地址为支付宝的地址, 在操作登录后(如果未登录), 支付订单
    
    e. 支付宝收到支付请求, 校验通过后, 向服务端发送支付成功的通知, 服务端修改相应订单内容, 支付宝通知客户端支付成功
    
    f. 客户端展示支付成功界面, 尔后跳转到购物车界面
    
    1. 触发提交流程
    2. 传入 支付宝接口要求的必填参数
    3. 传入 服务器端要求的必填业务参数
    4. 输入账号密码等待支付宝完成支付并显示支付结果
    5. 返回支付结果的url
    6. 在项目中定义alipay url 对应的页面组件
    • 提交订单订单的时候,需要传入Alipay相关的参数(订单总金额、订单标题、订单描述)和内部创建订单需要的参数(商品ID和数量、收获地址、用户ID)
    • 使用Alipay提供的sdk,获取支付链接
    • 使用支付宝支付完成后,客户端回跳到自己的支付成功页,同时会异步通知服务端用户已支付成功
    • 服务端调用Alipay的sdk验签接口,如果验证通过,开始创建订单,写入数据库

    1、传递 订单标题 订单金额 订单描述 产品信息 收货地址和当前创建人参数,获取支付地址 2、拿到收货地址后使用 window.location.href 进行跳转
    3、输入支付宝用户名密码登录后输入支付密码支付,支付成功后跳转到设置好的支付成功页面

    注意:支付宝支付接口不支持本地调试

    展开全文
    weixin_40599109 2021-03-10 19:14:46
  • 文章目录 一、订单 1、登录页面配置 2、用户收件地址查询 3、 下单 (1)表结构介绍 (2)下单实现 (3)库存变更 (4)增加积分 二、 支付流程分析 1、 二维码创建 2、微信扫码支付简介 (1)微信扫码支付申请 (2...

    一、订单

    1、登录页面配置

         前面使用的都是采用 Postman 实现登录,现在实现 oauth 自定义登录。
    先 将登录相关的静态资源导入到 changgou-user-oauth 中:
    在这里插入图片描述
    导入 thymeleaf 模板引擎依赖:

    <!--thymeleaf-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    

    提供控制器 com.changgou.oauth.controller.LoginRedirect,实现登录页跳转:

    @Controller
    @RequestMapping(value = "/oauth")
    public class LoginRedirect {
    
        /***
         * 跳转到登录页面
         * @return
         */
        @GetMapping(value = "/login")
        public String login(){
            return "login";
        }
    }
    

    针对静态资源和登录页面,我们需要实现忽略安全配置,并且要指定登录页面。修改com.changgou.oauth.config.WebSecurityConfig 的 2 个 configure 方法:
    在这里插入图片描述

    第 2 个 configure 配置:
    在这里插入图片描述
    测试:
    在这里插入图片描述

    点击登录按钮,访问之前的登录方法实现登录,需要对登录页做一下调整。
    首先,修改 login.html,引入 thymeleaf 命名空间:

    1562915939313
    点击登录按钮,使用 vue+axios 实现登录,需要定义脚本,访问后台登录方法。
    先添加 vue 入口标签,修改 login.html,添加id=“app” :
    在这里插入图片描述
    引入 js:
    在这里插入图片描述

    登录脚本实现:
    在这里插入图片描述
    修改表单:
    在这里插入图片描述
    测试:输入用户名和密码都是 changgou,点击”登录“按钮,页面显示 ”正在登录“后跳转至:
    在这里插入图片描述
    用户未登录的时候,并清除 Cookie ,直接访问购物车:
    在这里插入图片描述
         可以看到,返回的只是个错误状态码,不方便测试,可以设置为重定向到登录页面,让用户登录。需要修改网关的头文件,让用户每次没登录的时候,都跳转到登录页面。
        
    修改 changgou-gateway-web 的 com.changgou.filter.AuthorizeFilter,代码如下:
    在这里插入图片描述
    在这里插入图片描述
        此时再测试,未登录时访问购物车页面,就可以跳转到登录页面了。当然,在实际应用中,这里不能直接跳转到登录页,应该提示状态给页面,让页面根据判断跳转,这里只是为了方便测试。

        现在还有个问题,如果未登录访问购物车,会跳转到登录页面,但是登录成功后,却并没有再返回到要访问的购物车页面。可以将用户要访问的页面作为参数传递给登录控制器,登录控制器记录下来,每次登录成功后,再跳转记录访问路劲参数指定的页面。

        先修改网关,携带当前 URI。修改 changgou-gateway-web 的 com.changgou.filter.AuthorizeFilter,在之前的 URL 后面添加 FROM 参数以及 FROM 参数的值为 request.getURI(),代码如下:
    1565298329794
    再修改 changgou-user-oauth 的 com.changgou.oauth.controller.LoginRedirect 记录访问来源页,使 认证服务器获取 FROM 参数:

    @GetMapping(value = "/login")
        public String login(@RequestParam(value = "FROM",required = false,defaultValue = "")
                                        String from, Model model){
            model.addAttribute("from",from);
            return "login";
        }
    

    修改页面,获取来源页信息,并存到 from 变量中,登录成功后跳转到该地址。
    在这里插入图片描述
    这里的计时跳转逻辑是有问题的,到时间并没能跳转,改成:
    在这里插入图片描述
        此时再测试,就可以识别未登录用户,跳转到登录页,然后根据登录状态,如果登录成功,则跳转到来源页。

    2、用户收件地址查询

    订单的前端页面是这样的:
    在这里插入图片描述
    这里,“收件人信息”,是从 user 工程中获取到的,在数据库中对应 tb_address 表:
    在这里插入图片描述
    对应表结构:

    CREATE TABLE `tb_address` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `username` varchar(50) DEFAULT NULL COMMENT '用户名',
      `provinceid` varchar(20) DEFAULT NULL COMMENT '省',
      `cityid` varchar(20) DEFAULT NULL COMMENT '市',
      `areaid` varchar(20) DEFAULT NULL COMMENT '县/区',
      `phone` varchar(20) DEFAULT NULL COMMENT '电话',
      `address` varchar(200) DEFAULT NULL COMMENT '详细地址',
      `contact` varchar(50) DEFAULT NULL COMMENT '联系人',
      `is_default` varchar(1) DEFAULT NULL COMMENT '是否是默认 1默认 0否',
      `alias` varchar(50) DEFAULT NULL COMMENT '别名',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=utf8;
    

         需要在 user 工程中提供根据用户名查询收件地址的方法。
    在 AddressService 中提供方法:

     List<Address> list(String username);
    

    实现:

       @Override
        public List<Address> list(String username) {
            Address address = new Address();
            address.setUsername(username);
            return addressMapper.select(address);
        }
    

    控制层:

    @GetMapping("/user/list")
    public Result<List<Address>> list(){
    
        // 获取用户登录名
        String username = tokenDecode.getUserInfo().get("username");
        
        List<Address> address=addressService.list(username);
        return new Result<>(true,StatusCode.OK,"查询成功",address);
    }
    

    运行结果:
    在这里插入图片描述

         送货清单其实就是购物车列表,直接查询之前的购物车列表即可。
        

    3、 下单

    在这里插入图片描述
        点击结算页的时候,会立即创建订单数据,创建订单数据会将数据存入到 2 张表中,分别是 订单表 和 订单明细表,此处还需要修改商品对应的库存数量。
        而且提交订单后,需要把商品详情从用户的购物车中删除;需要进行价格校验,检查价格是否变化,以当前数据库中的价格为准,以防出现 “异价” 的问题;需要检查库存,特别是并非库存,以防出现 “超卖” 的问题。
        

    (1)表结构介绍

    订单表:

    CREATE TABLE `tb_order` (
      `id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT '订单id',
      `total_num` int(11) DEFAULT NULL COMMENT '数量合计',
      `total_money` int(11) DEFAULT NULL COMMENT '金额合计',
      `pre_money` int(11) DEFAULT NULL COMMENT '优惠金额',
      `post_fee` int(11) DEFAULT NULL COMMENT '邮费',
      `pay_money` int(11) DEFAULT NULL COMMENT '实付金额',
      `pay_type` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '支付类型,1、在线支付、0 货到付款',
      `create_time` datetime DEFAULT NULL COMMENT '订单创建时间',
      `update_time` datetime DEFAULT NULL COMMENT '订单更新时间',
      `pay_time` datetime DEFAULT NULL COMMENT '付款时间',
      `consign_time` datetime DEFAULT NULL COMMENT '发货时间',
      `end_time` datetime DEFAULT NULL COMMENT '交易完成时间',
      `close_time` datetime DEFAULT NULL COMMENT '交易关闭时间',
      `shipping_name` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流名称',
      `shipping_code` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流单号',
      `username` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '用户名称',
      `buyer_message` varchar(1000) COLLATE utf8_bin DEFAULT NULL COMMENT '买家留言',
      `buyer_rate` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否评价',
      `receiver_contact` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人',
      `receiver_mobile` varchar(12) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人手机',
      `receiver_address` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人地址',
      `source_type` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '订单来源:1:web,2:app,3:微信公众号,4:微信小程序  5 H5手机页面',
      `transaction_id` varchar(30) COLLATE utf8_bin DEFAULT NULL COMMENT '交易流水号',
      `order_status` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '订单状态,0:未完成,1:已完成,2:已退货',
      `pay_status` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '支付状态,0:未支付,1:已支付,2:支付失败',
      `consign_status` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '发货状态,0:未发货,1:已发货,2:已收货',
      `is_delete` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否删除',
      PRIMARY KEY (`id`),
      KEY `create_time` (`create_time`),
      KEY `status` (`order_status`),
      KEY `payment_type` (`pay_type`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    

    订单明细表:

    CREATE TABLE `tb_order_item` (
      `id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT 'ID',
      `category_id1` int(11) DEFAULT NULL COMMENT '1级分类',
      `category_id2` int(11) DEFAULT NULL COMMENT '2级分类',
      `category_id3` int(11) DEFAULT NULL COMMENT '3级分类',
      `spu_id` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT 'SPU_ID',
      `sku_id` bigint(20) NOT NULL COMMENT 'SKU_ID',
      `order_id` bigint(20) NOT NULL COMMENT '订单ID',
      `name` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品名称',
      `price` int(20) DEFAULT NULL COMMENT '单价',
      `num` int(10) DEFAULT NULL COMMENT '数量',
      `money` int(20) DEFAULT NULL COMMENT '总金额',
      `pay_money` int(11) DEFAULT NULL COMMENT '实付金额',
      `image` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '图片地址',
      `weight` int(11) DEFAULT NULL COMMENT '重量',
      `post_fee` int(11) DEFAULT NULL COMMENT '运费',
      `is_return` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否退货,0:未退货,1:已退货',
      PRIMARY KEY (`id`),
      KEY `item_id` (`sku_id`),
      KEY `order_id` (`order_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    

        两个表通过外键 orde_id 进行连结。

    (2)下单实现

        下单的时候,先添加订单,向 tb_order 表中增加数据,再添加订单明细,向 tb_order_item 表中增加数据。
         需要修改 changgou-service-order 微服务,实现下单操作,这里会生成订单号,我们首先需要在 启动类 中创建一个 IdWorker 对象( 为什么不使用自增 ID 呢?因为可能存在重复 和 数值超出范围 问题):

    @Bean
    public IdWorker idWorker(){
        return new IdWorker(1,1);
    }
    
    • 业务层
      修改 changgou-service-order 微服务,修改com.changgou.order.service.impl.OrderServiceImpl:
       void addOrder(Order order);
    

    实现:

     @Override
        public void addOrder(Order order) {
            // 订单主键
            order.setId(String.valueOf(idWorker.nextId()));
    
            // 总数量
            int totolNum = 0;
    
            // 总金额
            int totalMoney = 0;
    
            // 获取订单(购物车)明细
            List<OrderItem> orderItem = redisTemplate.boundHashOps("Cart_" + order.getUsername()).values();
        
            for (OrderItem item : orderItem) {
    
                // 价格校验
                int price = orderItemMapper.selectByPrimaryKey(item.getId()).getPrice();
                if (price == item.getMoney()) {
                    // 总金额
                    totalMoney += item.getMoney();
                } else totalMoney += price;
    
                // 总数量
                totolNum += item.getNum();
            }
    
            // 订单商品总数目 = 每个商品数量之和
            order.setTotalNum(totolNum);
    
            // 订单总金额 = 每个商品金额之和
            order.setTotalMoney(totalMoney);
    
            // 订单实付金额 = 每个商品实付金额之和
            order.setPayMoney(totalMoney);
    
            // 订单优惠金额 = 总金额 - 实付金额,暂时为 0
            order.setPreMoney(0);
    
            // 订单创建时间
            order.setCreateTime(new Date());
    
            // 订单修改时间
            order.setUpdateTime(order.getCreateTime());
    
            // 订单评价状态,0 表示未评价,1 表示已评价
            order.setBuyerRate("0");
    
            // 订单来源,1 表示 Web
            order.setSourceType("1");
    
            // 订单状态,0 表示未完成,1 表示已完成,2 表示已退货
            order.setOrderStatus("0");
    
            // 订单支付状态,0 表示未支付,1 表示已支付,2 表示支付失败
            order.setPayStatus("0");
    
            // 订单删除状态,0 表示未删除
            order.setIsDelete("0");
    
            // 订单发货状态,0 表示未发货,1 表示已发货,2 表示已收货
            order.setConsignStatus("0");
    
            // 先添加订单信息
            orderMapper.insertSelective(order);
    
            // 再添加订单明细信息
            for (OrderItem item : orderItem) {
                item.setId(String.valueOf(idWorker.nextId()));
                // 是否退货,0 表示未退货,1 表示已退货
                item.setIsReturn("0");
                item.setOrderId(order.getId());
                // 退货状态,0 表示未退货
                item.setIsReturn("0");
                orderItemMapper.insertSelective(item);
            }
    
            // 下单后需要把商品从购物车中移除
            redisTemplate.delete("Cart_" + order.getUsername());
        }
    

         可以看到,逻辑是传来 order 对象, 从 Redis 中查到 “Cart_xxx” 为命名空间的记录对应的 value,也就是 xxx 用户购物车/订单的所有记录,遍历,求出总金额和数量;再为 order 对象设置属性,将 order 对象持久化到 order 表中,再遍历一次 Redis 中的记录,把这些记录都持久化到 order_item 表中,下单后还需要把 xxx 用户购物车中的所有记录移除。
         这里,通用 Mapper 使用的是 insertSelective 方法。 如果使用的是 insert ,那么所有的字段都会添加一遍,即使有的字段没有值;如果使用 inserSelective 就会只给有值的字段赋值(会对传进来的值做非空判断)。还有要注意的是,在启动类用 @MapperScan 注解,导入的包应该是 tk 的,而不是 spring mybatis 的。

    ( RedisTemplate 中的命名空间、key、value 的关系示意图:
    在这里插入图片描述 可以看到,用用户名作命名空间,商品的 sku ID 作 key,商品详情的 orderItem 作 value,这设计挺巧妙的 🤗。)

    • 控制层
          修改 com.changgou.order.controller.OrderController 类:
    @Autowired
    private TokenDecode tokenDecode;
      @PostMapping
        public Result add(@RequestBody Order order) {
    
            // 获取用户名
            Map<String, String> userInfo = tokenDecode.getUserInfo();
    
            String userName = userInfo.get("username");
    
            order.setUsername(userName);
            orderService.addOrder(order);
    
            return new Result(true, StatusCode.OK, "添加成功");
        }
    

    保存订单测试,可以看到 Redis 中用户对应的购物记录被删除,而且 MySQL 2 个表数据添加成功。
        现在还有一个问题,下单并不是对购物车所有的商品进行选择,是需要勾选商品的,先在 Order 类中添加一个字段,用于记录当前订单勾选的商品 ID:

    private List<Long> skuIds;
    

    修改业务层逻辑:
    在这里插入图片描述
        这样后续都是对勾选的商品进行的操作。

    (3)库存变更

        上面操作只实现了下单操作,但对应的库存还没跟着一起减少,在下单之后,应该 调用商品微服务,将下单的商品库存减少,销量增加
    先实现库存减少的逻辑:
    在这里插入图片描述
        可以看到,多线程操作时,无法保证数据的 原子性,出现了 “超卖” 问题。
        解决方法:采用数据库的行级锁控制超卖现象,存储引擎是 InnoDB,默认支持 行级锁 ,只允许一个事务修改记录,只有等该事务结束后,其他事务才能操作;当语句执行结果返回 0,即 受影响行数为 0 时,回滚事务。

    在 SkuMapper 中提供方法:

    public interface SkuMapper extends Mapper<Sku> {
    
        @Update("update tb_sku set num=num-#{num} where id=#{id} and num>=#{num}")
        int decrCount(@Param(value = "id") Long id, @Param(value = "num") Integer num);
    }
    

    业务层,先在 SkuService 接口中提供 库存递减 的方法:

    void decrCount(Map<Long, Integer> decrMap);
    

    实现:

    @Override
        public void decrCount(Map<Long, Integer> decrMap) {
            for (Map.Entry<Long, Integer> entry : decrMap.entrySet()) {
                // 商品 ID
                Long id = entry.getKey();
    
                // 数量
                Integer num = entry.getValue();
    
                /**
                 * 使用行级锁防止超卖,通过数据库的事务特性保证数据原子性
                 */
                int row = skuMapper.decrCount(id, num);
                if (row <= 0) {
                    throw new RuntimeException("库存不足,请回滚。");
                }
            }
        }
    

    (回滚还未实现。)
    控制层:

     @GetMapping(value = "/decr")
        public Result decrCount(@RequestParam Map<Long,Integer> decrMap){
    
            skuService.decrCount(decrMap);
            return new Result(true,StatusCode.OK,"库存递减成功");
        }
    

    相应地,在 SkuFeign 中提供:

    @GetMapping(value = "/decr")
        public Result decrCount(@RequestParam Map<Long,Integer> decrMap);
    

    在 OrderServiceImpl 中调用:
    在这里插入图片描述
         这里要注意,Feign 调用的 map 的 key 必须是 String 类型 ,而不能写成 Long,否则会报错 IllegalStateException: QueryMap key must be a String: .Long,因为 Spring Cloud 借助 Feign 调用微服务,是基于 Http 请求的。
        测试一下效果,现在访问 http://localhost:8001/api/cart/list,用户名为 changgou,购物车有 3 个商品记录,对其中一个商品进行下单操作:
    在这里插入图片描述
    可以看到,响应数据是 500 状态码,Feign 调用出现了问题,再看控制台的报错:
    在这里插入图片描述
    主要原因是 java.lang.String cannot be cast to java.lang.Integer,但是这个 decrMap 中 ,key 改成 String 类型了,而 value 确实是 Integer 。

    在这里插入图片描述

    进行debug, 发现 在业务层调用 feign 之前,参数还是 Integer 的:
    在这里插入图片描述

        但是用 Feign 调用后,就都变成 String 了(想想也是,毕竟 Feign 走的是 Http 协议,参数是 String 才是符合常理的,能识别到 Map 类型就不错了,Map 的 Value 应当都是按照 String 处理的)
        所以,得到教训:涉及 Feign 调用,Map 的 key 和 value 都建议使用 String 类型,到了具体的方法中再转化成数值类型。
    在这里插入图片描述
    在这里插入图片描述
    这时对下单功能在进行测试:
    在这里插入图片描述
         因为会调用 skuMapper 的 decrCount 方法,所以只需要保证 下单http://localhost:18090/cart/add?num=xxx&id=xxx 时,num 的值大于等于数据库 tb_sku 中对应记录的 num 值,SQL 语句就会被执行,数据库中 num 值减少了订单中的量,即 实现了库存变更的功能否则会进行回滚。而且可以看到数据库中 tb_order 订单表有新增数据。
        

    (4)增加积分

         除了库存变更,还需要给用户增加积分。实现的步骤是相似的。
        比如每次下单完成之后,给用户增加 10 个积分,这个积分只是用来表示用户活跃度。

    • user 表结构中有积分字段:
      在这里插入图片描述
          对于积分,也是需要保证它的 原子性 的。
    • dao 层
      修改 changgou-service-user 微服务的 com.changgou.user.dao.UserMapper 接口,增加用户积分方法:
    public interface UserMapper extends Mapper<User> {
    
        /**
         * 增加用户积分
         * @param username
         * @param points
         */
        @Update("update tb_user set points=points+#{points} where username=#{username}")
        void addPoints(@Param(value = "username") String username, @Param(value = "points") Integer points);
    }
    
    • 业务层

    修改 com.changgou.user.service.UserService 接口:

       void addPoints(String username,Integer points);
    

    实现:

      @Override
        public void addPoints(String username, Integer points) {
            userMapper.addPoints(username,points);
        }
    
    • 控制层

    修改 UserController,添加增加用户积分方法:

    @Autowired
    private TokenDecode tokenDecode;
    
    /***
     * 增加用户积分
     * @param points
     * @return
     */
    @GetMapping(value = "/points/add")
    public Result addPoints(@RequestParam Integer points){
        String username = tokenDecode.getUserInfo().get("username");
        userService.addPoints(username,points);
        return new Result(true,StatusCode.OK,"积分成功");
    }
    
    • 提供 Feign

    在 changgou-service-user-api 工程 中提供 com.changgou.user.feign.UserFeign:

     @GetMapping(value = "/points/add")
        public Result addPoints(@RequestParam Integer points);
    

    在 order 中要调用 Feign,所以需要添加 changgou-service-user-api 的依赖:

    <!--user api 依赖-->
    <dependency>
        <groupId>com.changgou</groupId>
        <artifactId>changgou-service-user-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    

    相应的,order 的启动类上需要声明 Feign 包:
    在这里插入图片描述

    在下单的 addOrder 方法中,除了更改库存,还要添加积分:
    在这里插入图片描述
        接下来,goods 工程 需要像上一篇 order 工程那样,定义 feign 拦截器( 逻辑是:获取当前的 Http Headers ,并放到 Http Headers 中进后续的请求,相当于 Http Headers 的传递。各大微服务之间的认证,其实就是令牌的传递过程。令牌传递起来了,就可以获取其中的用户信息并解析,比如,TokenDecode 类中有 getUserInfo 方法,可以获取用户名 username)。同样地,applicatin.ym 不能使用 hystrix 的 多线程模式:

    #hystrix 配置
    hystrix:
    command:
    default:
    execution:
    isolation:
    thread:
    timeoutInMilliseconds: 10000
    strategy: SEMAPHORE
    

    二、 支付流程分析

    在这里插入图片描述 骤分析如下:

    • 用户下单之后,订单数据会存入到 MySQL 中,同时会将订单对应的支付日志存入到 Redis ,以队列的方式存储。 (创建延时队列)
    • 用户下单后,进入支付页面,支付页面调用支付系统,从 微信支付服务器 获取二维码数据,并在页面生成支付二维码。
    • 用户扫码支付后,微信支付服务器会通调用前预留的回调地址,并携带支付状态信息到支付系统。
    • 支付系统接到支付状态信息后,将支付状态信息发送给 RabbitMQ 。
    • 订单系统监听 RabbitMQ 中的消息获取支付状态,并根据支付状态修改订单状态。
    • 为了防止网络问题导致 notifyurl 没有接到对应数据,定时任务定时获取 Redis 中队列数据去微信支付接口查询状态,并定时更新对应状态。

    (✨ 对于可能出现付款失败的情况,我们采用延时 MQ,比如 30 min,系统会监听队列,如果还未支付,说明超时,需要回滚库存,取消订单。)

    1、 二维码创建

        简单说下利用 qrious 制作二维码插件。
        qrious 是一款基于 HTML5 Canvas 的纯 JS 二维码生成插件。通过 qrious.js 可以快速生成各种二维码,可以控制二维码的尺寸颜色,还可以将生成的二维码进行Base64 编码。

    qrious.js 二维码插件的可用配置参数如下:

    参数	    类型	默认值		描述
    background	String	"white"		二维码的背景颜色。
    foreground	String	"black"		二维码的前景颜色。
    level		String	"L"			二维码的误差校正级别(L, M, Q, H)。
    mime		String	"image/png"	二维码输出为图片时的MIME类型。
    size		Number	100			二维码的尺寸,单位像素。
    value		String	""			需要编码为二维码的值
    

    下面的代码即可生成一张二维码:

    <html>
    <head>
        <title>二维码入门小demo</title>
        <!--1.引入js  2. 创建一个img标签 用来存储显示二维码的图片 3.创建js对象 4.设置js对象的配置项-->
    
        <script src="qrious.js"></script>
    
    </head>
    <body>
    
    
    <img id="myqrious">
    
    </body>
    
    <script>
        var qrious = new QRious({
            element: document.getElementById("myqrious"),// 指定的是图片所在的DOM对象
            size: 250,//指定图片的像素大小
            level: 'H',//指定二维码的容错级别(H:可以恢复30%的数据)
            value: 'weixin://wxpay/bizpayurl?pr=Hujo6p6'//指定二维码图片代表的真正的值
        })
    
    </script>
    </html>
    

    还需要在同一个文件夹下导入 qrious:
    在这里插入图片描述
    运行效果:
    在这里插入图片描述

    2、微信扫码支付简介

    (1)微信扫码支付申请

         微信扫码支付是商户系统按微信支付协议生成支付二维码,用户再用微信 “扫一扫” 完成支付的模式。该模式适用于 PC 网站支付、实体店单品或订单支付、媒体广告支付等场景。

    申请步骤:

    • 第一步:注册公众号(类型须为:服务号)
          请根据营业执照类型选择以下主体注册:个体工商户| 企业/公司| 政府| 媒体| 其他类型。
    • 第二步:认证公众号
           公众号认证后才可申请微信支付,认证费:300元/次。
    • 第三步:提交资料申请微信支付
          登录公众平台,点击左侧菜单【微信支付】,开始填写资料等待审核,审核时间为1-5个工作日内。
    • 第四步:开户成功,登录商户平台进行验证
          资料审核通过后,请登录联系人邮箱查收商户号和密码,并登录商户平台填写财付通备付金打的小额资金数额,完成账户验证。
    • 第五步:在线签署协议
           本协议为线上电子协议,签署后方可进行交易及资金结算,签署完立即生效。

        本系统使用已经提供好的 “传智播客”的微信支付账号。

    (2) 开发文档

    微信支付接口调用的整体思路:
        按 API 要求组装参数,以 XML 方式发送(POST )给微信支付接口(URL),微信支付接口也是以 XML 方式给予响应。程序根据返回的结果(其中包括支付 URL )生成二维码或判断订单状态。

    在线微信支付开发文档:

    https://pay.weixin.qq.com/wiki/doc/api/index.html

        如果不能联网,可以查阅讲义配套资源 (资源\配套软件\微信扫码支付\开发文档)。
        
        接下来会讲到 ”统一下单” 和 ”查询订单” 两组 API。

    1. appid:微信公众账号或开放平台 APP 的唯一标识
    2. mch_id:商户号  (配置文件中的 partner)
    3. partnerkey:商户密钥
    4. sign:数字签名, 根据微信官方提供的密钥和一套算法生成的一个加密信息, 就是为了保证交易的安全性
    
    (3)微信支付模式介绍

    模式二:(之前有区分 模式一、模式二,实际上现在文档里只有这个模式了 2021.04.14 )
    在这里插入图片描述
    业务流程说明:

    1. 商户后台系统根据用户选购的商品生成订单。
    2. 用户确认支付后调用微信支付【统一下单API】生成预支付交易;
    3. 微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。
    4. 商户后台系统根据返回的code_url生成二维码。
    5. 用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。
    6. 微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。
    7. 用户在微信客户端输入密码,确认支付后,微信客户端提交授权。
    8. 微信支付系统根据用户授权完成支付交易。
    9. 微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
    10. 微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。
    11. 未收到支付通知的情况,商户后台系统调用【查询订单API】。
    12. 商户确认订单已支付后给用户发货。
           二维码只能用一次,扫描之后就不能再扫啦,用于线上支付。

    之前的模式一:
    在这里插入图片描述

    1. 商户后台系统根据微信支付规定格式生成二维码(规则见下文),展示给用户扫码。
    2. 用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。
    3. 微信支付系统收到客户端请求,发起对商户后台系统支付回调URL的调用。调用请求将带productid 和用户的 openid 等参数,并要求商户系统返回交数据包,详细请见"本节3.1回调数据输入参数"
    4. 商户后台系统收到微信支付系统的回调请求,根据productid生成商户系统的订单。
    5. 商户系统调用微信支付【统一下单API】请求下单,获取交易会话标识(prepay_id)
    6. 微信支付系统根据商户系统的请求生成预支付交易,并返回交易会话标识(prepay_id)。
    7. 商户后台系统得到交易会话标识 prepay_id(2小时内有效)。
    8. 商户后台系统将 prepay_id 返回给微信支付系统。返回数据见"本节3.2回调数据输出参数"
    9. 微信支付系统根据交易会话标识,发起用户端授权支付流程。
    10. 用户在微信客户端输入密码,确认支付后,微信客户端提交支付授权。
    11. 微信支付系统验证后扣款,完成支付交易。
    12. 微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
    13. 微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。
    14. 未收到支付通知的情况,商户后台系统调用【查询订单API】。
    15. 商户确认订单已支付后给用户发货。
           只是二维码生成的逻辑有差异。

    三、总结

    (1)实现登录页面,需要静态资源与后端代码配合,先引入 thymeleaf 模板引擎依赖,
    提供 /oauth/login 路径对应的控制类和方法,方法返回值对应 thymeleaf 模板前端页面 login.html。
         在继承了 WebSecurityConfigurerAdapter 的配置类的 configure(WebSecurity web)configure(HttpSecurity http) 方法中,分别声明放行地址
    和 自定义登录地址(也就是 /oauth/login )。
         还实现了 如果未登录成功,会携带这时的路径访问登录地址,比如,先访问的 http://localhost:8001/api/cart/list 查看购物车,但是此时没有携带 bearer token,登录失败,此时路径会变成 http://localhost:9001/oauth/login?FROM=http://localhost:8001/api/cart/list,到登录页面,如果此时登录成功,会跳转到 FROM 里的路径,也就是 http://localhost:8001/api/cart/list。
        
    (2)用户收件地址查询是通过 username 对 tb_address 表的查询。
        
    (3)下单操作,对应的路径是 http://localhost:8001/api/order,使用 IdWorker 对象生成订单 、订单明细 ID,这样可以避免自增 ID 带来的重复、数值超出范围的问题。到 Redis 中,以 cart_xxx(用户名 username)为 namespace ,查询记录,得到的就是用户所有勾选了的下单商品对应的 orderitems,简略来说,就像{{商品1,数量 2,价格 3,},{商品 4,数量 5 ,价格 6}}这样就可以求得总数量 和 总金额,再为订单设置时间、状态等属性,先把订单记录插入到 tb_order 表中,再遍历一次 orderitems,为订单明细设置状态等属性,再把订单明细记录到 tb_order_item 表中。
         下单后,还需要从 Redis 中删除记录;递减库存,增加用户积分(活跃度)。
         递减库存和增加活跃度都需要保证变量的原子性,
         采用数据库的行级锁控制超卖现象,存储引擎是 InnoDB,默认支持行级锁 ,只允许一个事务修改记录,只有等该事务结束后,其他事务才能操作;当语句执行结果返回 0,即 受影响行数为 0 时,回滚事务。
         在相应的 mapper 里提供方法,使用 @update 注解执行 SQL 语句。
         库存对应 tb_sku 表中的 num,活跃度对应 tb_user 表中的 points,所以需要提供相应的 feign。递减库存,传订单明细们的 skuId 和 num,可以封装成 Map,不过要注意,因为是 Feign 调用,所以 Map 的 key 和 value 应该都是 String,到具体方法再转化成其他类型;增加积分,传 username 和 points 即可。
        
    (4)goods 工程 需要像上一篇 order 工程那样,定义 feign 拦截器( 逻辑是:获取当前的 Http Headers ,并放到 Http Headers 中进后续的请求,相当于 Http Headers 的传递。各大微服务之间的认证,其实就是令牌的传递过程。令牌传递起来了,就可以获取其中的用户信息并解析,比如,TokenDecode 类中有 getUserInfo 方法,可以获取用户名 username)。同样地,applicatin.ym 不能使用 hystrix 的 多线程模式,需要使用 SEMAPHORE 模式。
        
    (5)本系统支付采用微信支付接口,按照相应规范进行开发。

    展开全文
    weixin_41750142 2021-04-12 16:33:03
  • 使用电子支付集成的付款流程 EPIC_PROC - 会计核算 -> 财务会计 -> 银行 -> 国家特定 -> 中国 -> 电子支付集成 使用此中国特定的流程可以简化待支付项目的处理,并且可以通过银行转账进行电子支付...

    使用电子支付集成的付款流程

    EPIC_PROC - 会计核算 -> 财务会计 -> 银行 -> 国家特定 -> 中国 -> 电子支付集成 

    使用此中国特定的流程可以简化待支付项目的处理,并且可以通过银行转账进行电子支付。使用该集成屏幕的用户包括处理人员(如应付账款会计)或审批人员(如会计经理)。这些用户(无论其角色为处理人员还是审批人员)均可通过这个单独的〖电子支付中心(中国)〗集成屏幕来执行下列活动:

    通过执行付款建议运行来创建待支付项目

    将项目提交到付款审批流程并根据需要分配审批人员

    批准或拒绝所提交的待审批项目或项目组

    在系统中进行付款,即创建付款指令

    向开户行发送付款

    监控已发送至银行的项目的状态

    要访问〖电子支付中心(中国)〗的各项功能,请在 SAP 轻松访问屏幕中选择  〖会计核算〗   〖财务会计〗   〖应付账款〗   〖定期处理〗   〖国家特定功能〗   〖中国〗   〖电子支付中心〗  。此外,也可以使用 EPIC_PROC 事务。

    有关可在〖电子支付中心(中国)〗屏幕中执行的各种操作的详细信息,请参阅系统文档,通过选择标签页上方的 文档 (〖文档〗) 按钮可找到系统文档。

    前提
    已在系统中创建满足下列条件的采购发票:

    付款方式为银行转账。有关详细信息,请参阅付款方式。

    使用开户行在中国的账户进行付款。

    交易货币为人民币 (CNY)。

    流程
    下图显示了在实施二级审批流程的情况下采用上述功能的付款流程示例,并附带有相关说明:

    该图形已在附随文本中作解释。

    具有二级审批流程的付款流程

    应付账款会计或其他处理人员打开〖电子支付中心(中国)〗屏幕并运行付款建议。

    系统将在付款建议运行中创建的项目显示在〖款项处理〗标签页上。

    处理人员检查待支付项目,并提交其中一部分项目供审批。

    系统将待审批项目分组,并根据审批流程的设置做出不同反应。根据设置,系统可以批准项目直接付款,也可以将项目发送给审批流程中所定义的下一位用户。在本情景中,审批流程设置指示系统自动将项目组发送给审批人员 1 进行审批。

    系统在〖款项审批〗标签页上显示该项目组已分配给审批人员 1。

    审批人员 1 检查审批组中的项目。根据公司的审批流程,审批人员可以对项目进行批准、拒绝或直接付款。在本情景中,申批人员 1 批准了整个项目组,并确认了该选择。

    系统在〖款项审批〗屏幕上显示该项目组已分配给审批人员 2。

    审批人员 2 同样也批准了整个项目组。

    系统将所有项目的状态设为〝批准支付〞。

    处理人员在〖款项处理〗标签页上看到这些项目可以进行支付。处理人员对这些项目进行支付(即指示系统创建付款指令),然后将项目发送至银行。

    系统为这些项目创建付款指令。系统根据您为付款程序进行的定制自动生成付款文件,然后使用 RFC 将该文件发送至开户行的通信客户端。

    银行收到该文件后开始处理这些项目。

    处理人员向银行查询通过付款文件发送至银行的项目的状态。

     

    银行将状态直接发送到 SAP ERP 系统,该系统在〖款项处理〗标签页上显示已更新的状态。

    结果
    任何参与付款流程的用户(如处理人员)都可以查看已发送至银行的项目状态。

    SAP 库 - 电子支付集成 官方文档(中文):

    https://help.sap.com/doc/erp2005_ehp_06/6.0.6/zh-CN/e2/f56cca0c1145dea404a1c723305455/frameset.htm

    展开全文
    dwjnhkbc123 2021-08-29 23:48:05
  • Adyen支付流程 流程图: 第一步:拉取可用付款方式列表 根据交易环境(例如金额,国家和货币)查询交易的可用付款方式。除了提供可用付款方式的列表之外,响应还返回您需要从购物者那里收集(要提交给/payments)...

    Adyen支付流程

    流程图:

    在这里插入图片描述

    第一步:拉取可用付款方式列表

    根据交易环境(例如金额,国家和货币)查询交易的可用付款方式。除了提供可用付款方式的列表之外,响应还返回您需要从购物者那里收集(要提交给/payments)的哪些输入详细信息。

    尽管我们强烈建议使用此端点来确保您始终提供最新的付款方式列表,但其用法是可选的。例如,您还可以缓存/paymentMethods响应并每周更新一次。

    请求:

    请求URL:

    /paymentMethods

    请求方式:

    POST

    请求参数:

    参数名称必填字段类型描述
    merchantAccountString商家帐户名称。 在首页的Account=>Merchant accounts菜单里面添加。
    amount对象交易的金额信息(以小单位表示)。对于BIN或卡验证请求,设置amount为0(零)。
    +currencyString三个字符的ISO货币代码,比如:CNY、USD等等。 可以在https://docs.adyen.com/development-resources/currency-codes这个界面查看支持的币种
    +valueInteger交易的金额,以小单位表示
    channelString支付交易发生的平台。此字段可用于过滤只在特定平台上可用的支付方法。可选的值有: Web iOS Android
    countryCodeString购物者的国家代码。比如:HK,US
    shopperLocaleString语言代码和国家代码的组合,以指定在支付中使用的语言。比如:en-US
    additionalDataObject此字段包含额外的数据,可能需要特定的支付请求。additionalData对象由条目组成,每个条目都包含键和值。(PS:暂时不知道用途)
    allowedPaymentMethods[String]array对购物者展示的支付方法列表 例如: “allowedPaymentMethods”:[“ideal”,“giropay”,“alipay”] (PS:这个应该是选择我们支持哪些支付展示给用户看)
    blockedPaymentMethods[String]array对购物者隐藏的支付方法列表,含义与allowedPaymentMethods相反
    orderObject包含部分付款所需的订单信息。(PS:暂时不知道用途)
    +orderDataString加密的订单数据。
    +pspReferenceString属于订单的pspReference。
    shopperReferenceString惟一标识该购物者的引用(例如,用户ID或帐户ID)。最小长度:3个字符。
    经常付款需要这个领域。
    splitCardFundingSourcesBoolean布尔值,指示信用卡支付方式是否应该分为单独的借记卡和信用卡选项。(PS:暂时不知道用途)
    storeString为其处理付款的实体商店。(PS:应该用不上)

    例子:

    {
        "amount":{
            "currency":"CNY",
            "decimalValue":9.99,  //请求里面不包含这个的
            "value":999 
        },
        "channel":"WEB",
        "countryCode":"HK",
        "merchantAccount":"BaomihuaECOM",
        "shopperLocale":"en-US",
        "shopperReference":"SparkJava Checkout Shopper",
        "splitCardFundingSources":false
    }
    

    响应:

    响应参数:

    参数名称参数类型描述
    paymentMethods[对象]array付表格所需的支付方法的详细列表。
    +brandString所选购物卡的品牌。例如:visa,mc。
    +brands[String]array可能的品牌列表。例如:visa, mc。
    +configurationObject支付方式的配置。
    +fundingSourceString付款方式的资金来源。
    +nameString此支付方法的可显示名称。
    +typeString唯一的支付方式代码
    +details[InputDetail]Array还可以递归地提供输入细节。
    ++details[SubInputDetail]Array还可以递归地提供输入细节。子类结构与details一样
    ++configurationObject配置所需输入的参数。
    ++itemSearchUrlString在选择的情况下,从其中查询项目的URL。
    ++keyString要在结果中提供的值
    ++optionalBoolean如果此输入是可选提供的,则为True。
    ++typeString所需输入的类型。
    ++valueString如果可用,可以预填充该值。
    ++items[Item]Array在选择的情况下,要从中选择的项。
    +++idString要在结果中提供的值。
    +++nameString显示名称。
    ++groupObject该支付方法所属的组。
    +++nameString组名。
    +++paymentMethodDataString如果支付方法显示为该组的一部分,则返回要使用的数据。
    +++typeString集团的唯一代码。
    storedPaymentMethods[对象]array所有存储的支付方法的列表。
    +brandString卡的品牌。
    +expiryMonthString信用卡过期的月。
    +expiryYearString信用卡过期的年。
    +holderNameString唯一的支付方式代码。
    +idString这个存储的支付方法的唯一标识符。
    +lastFourStringPAN的后四位。
    +nameString存储的支付方法的显示名称。
    +shopperEmailString购物者的电子邮件地址。
    +typeString付款方式类型。
    +supportedShopperInteractions[String]Array此存储的付款方式支持的购物者互动。

    例子:

    { 
        "paymentMethods":[ 
            { 
                "brands":[ 
                    "visa", 
                    "mc", 
                    "amex", 
                    "cup", 
                    "diners", 
                    "discover", 
                    "jcb", 
                    "maestro" 
                ], 
                "details":[ 
                    { 
                        "key":"number", 
                        "type":"text" 
                    }, 
                    { 
                        "key":"expiryMonth", 
                        "type":"text" 
                    }, 
                    { 
                        "key":"expiryYear", 
                        "type":"text" 
                    }, 
                    { 
                        "key":"cvc", 
                        "type":"text" 
                    }, 
                    { 
                        "key":"holderName", 
                        "optional":true, 
                        "type":"text" 
                    } 
                ], 
                "name":"Credit Card", 
                "type":"scheme" 
            }, 
            { 
                "name":"AliPay", 
                "type":"alipay" 
            }, 
            { 
                "name":"UnionPay", 
                "type":"unionpay" 
            }, 
            { 
                "configuration":{ 
                    "merchantId":"1000", 
                    "merchantName":"Merchant Name" 
                }, 
                "details":[ 
                    { 
                        "key":"applepay.token", 
                        "type":"applePayToken" 
                    } 
                ], 
                "name":"Apple Pay", 
                "type":"applepay" 
            }, 
            { 
                "name":"POLi", 
                "type":"poli" 
            }, 
            { 
                "brand":"svs", 
                "details":[ 
                    { 
                        "key":"number", 
                        "type":"text" 
                    }, 
                    { 
                        "key":"expiryMonth", 
                        "optional":true, 
                        "type":"text" 
                    }, 
                    { 
                        "key":"expiryYear", 
                        "optional":true, 
                        "type":"text" 
                    }, 
                    { 
                        "key":"cvc", 
                        "optional":true, 
                        "type":"text" 
                    }, 
                    { 
                        "key":"holderName", 
                        "optional":true, 
                        "type":"text" 
                    } 
                ], 
                "name":"SVS", 
                "type":"giftcard" 
            } 
        ] 
    } 
    

    第二步:付款

    发送付款参数(例如金额,国家和货币)以及从购物者那里收集的其他必需的输入详细信息

    • 对于直接流,响应包括带有付款结果的apspReference和a resultCode,例如AuthorizedRefused

    • 对于重定向或其他操作,响应包含一个action对象。

    请求:

    请求URL:

    /payments

    请求方式:

    POST

    请求参数:

    参数名称必填字段类型描述
    amount对象交易的金额信息(以小单位表示)。 对于BIN或卡验证请求,设置amount为0(零)。
    +currencyString三个字符的ISO货币代码。
    +valueInteger交易的金额,以小单位表示。
    merchantAccountString商家帐户标识符,用于处理交易。
    paymentMethod对象要使用的支付方法的类型和所需的详细信息。
    referenceString唯一标识支付的引用。 此参考是用于与您有关支付状态的所有沟通。 我们建议每次支付使用一个独特的价值; 然而,这并不是一项要求。 如果需要为一个事务提供多个引用,请使用连字符("-")分隔它们。 最大长度:80个字符。
    returnUrlString重定向时要返回的URL。格式取决于通道。该URL最大长度为1024个字符。 对于web,包括http://或https://协议 您还可以包含您自己的其他查询参数,例如,购物者ID或订单引用号。 例如:https://your-company.com/checkout?shopperOrder=12xy 对于iOS,使用自定义URL为您的应用程序。要了解更多关于设置自定义URL方案,请参考苹果开发人员文档。 例子:myapp:// 对于Android,使用一个由Activity处理的自定义URL。你可以通过一个intent filter来配置它。 例子:my-app://your.package.name
    accountInfo对象3D Secure 2的购物者账户信息。
    additionalData[对象]Array此字段包含额外的数据,可能需要特定的支付请求。 additionalData对象由条目组成,每个条目都包含键和值。
    applicationInfo对象关于你的申请的信息。 有关详细信息,请参见构建Adyen解决方案。
    billingAddress对象寄发票的地址。 对于3D Secure 2交易,方案要求所有基于浏览器和移动实现的billingAddress。 包含该对象中的所有字段
    browserInfo对象购物者的浏览器信息 对于 3D Secure,完整的对象是需要的web集成。 对于移动应用集成,包括userAgent和acceptHeader字段,以表明如果支付路由到3D Secure 1,您的集成可以支持重定向。
    captureDelayHoursInteger授权和预定自动捕获之间的延迟,以小时为单位。
    channelString支付交易发生的平台。 此字段是可选的,用于过滤只在特定平台上可用的支付方法。 如果这个值没有设置,那么我们将尝试从sdkVersion或token推断它。 可能的值: iOS Android Web
    company对象关于公司的信息。
    conversionIdString与跟踪用户支付旅程所生成的ID相对应的转换ID。
    countryCodeString购物者的国家。格式:ISO 3166-1 alpha-2例如:NL或DE
    dateOfBirthString购物者的出生日期。格式iso - 8601: YYYY-MM-DD
    dccQuoteString在外汇服务的响应中返回的外汇报价。
    deliveryAddress对象所购货物应送达的地址。
    deliveryDateString所购货物交付的日期和时间。格式ISO 8601: YYYY-MM-DDThh:mm:ss.sssTZD例如:2017 - 07 - 17 t13:42:40.428 + 01:00
    deviceFingerprintString包含购物者的设备指纹的字符串。 更多信息请参考设备指纹。
    enableOneClickBoolean当为true并且提供了shopperReference时,将询问购物者是否应该存储支付详细信息以供未来的一键支付。
    enablePayOutBooleanshopperReference设为true并提供时,付款明细将标记为付款。
    enableRecurringBoolean如果为true且shopperReference提供,则将对分期付款的付款细节进行标记。
    redirectToIssuerMethodString指定重定向到发行方时的重定向方法(GET或POST)
    redirectFromIssuerMethodString从发行者重定向回时,指定重定向方法(GET或POST)。
    metadata[String]Array元数据由条目组成,每个条目包含一个键和一个值。 限制: 每个请求最多20个键值对。 超过时,出现177错误:“元数据大小超过限制”。 每个键最多20个字符。 每个值最多80个字符。
    order对象包含部分付款所需的订单信息。
    shopperEmailString购物者的电子邮件地址。 我们建议您提供此数据,因为它用于速度欺诈检查。
    shopperIPString购物者的IP地址。 一般来说,我们建议您提供此数据,因为它用于许多风险检查(例如,尝试支付的次数或基于位置的检查)。
    shopperLocaleString语言代码和国家代码的组合,以指定在支付中使用的语言。
    shopperReferenceString惟一标识该购物者的引用(例如,用户ID或帐户ID)。 最小长度:3个字符。(PS:付款成功的additionalData返回里面会带回来)
    storePaymentMethodBoolean当true和shopperReference被提供时,支付细节将被存储。
    更多参数请查阅api文档,地址:https://docs.adyen.com/api-explorer/#/CheckoutService/v66/post/payments__reqParam_paymentMethod-VippsDetails-recurringDetailReference

    例子:

    { 
        "amount":{ 
            "currency":"CNY", 
            "decimalValue":0.1, 
            "value":10 
        }, 
        "applicationInfo":{ 
            "adyenLibrary":{ 
                "name":"adyen-java-api-library", 
                "version":"13.1.0" 
            } 
        }, 
        "channel":"WEB", 
        "countryCode":"CN", 
        "merchantAccount":"BaomihuaECOM", 
        "paymentMethod":{ 
            "type":"alipay" 
        }, 
        "reference":"9b01fb21-16fd-4e4e-b983-24eff2e7dee0", 
        "returnUrl":"http://localhost:8080/api/handleShopperRedirect?orderRef=9b01fb21-16fd-4e4e-b983-24eff2e7dee0", 
        "shopperReference":"12694261115541" 
    }
    

    响应:

    响应参数:

    参数名称参数类型描述
    action对象为完成付款而采取的行动
    additionalData【String】array包含关于付款的附加信息。 只有在您首先选择某些数据字段时,才会包含它们 去Customer Area > Account > API URLs > Additional data 设置
    amount对象交易中的授权金额。
    merchantReferenceString唯一标识支付的引用。 此参考是用于与您有关支付状态的所有沟通。 我们建议每次支付使用一个独特的价值; 然而,这并不是一项要求。 如果需要为一个事务提供多个引用,请使用连字符("-")分隔它们。 最大长度:80个字符。(订单号)
    order对象在请求中提供了订单信息的情况下,包含有关订单的更新信息。
    pspReferenceStringAdyen与事务/请求关联的16个字符的字符串引用。 这个值是全局唯一的; 报价时,与我们沟通这个要求。
    refusalReasonString如果付款的授权被拒绝或在授权期间发生错误,这个字段保存Adyen的拒绝原因映射或错误描述。 当事务失败时,授权响应包括resultCode和refusalReason值。 有关更多信息,请参见Refusal reasons.。
    refusalReasonCodeString指明拒绝理由的代码。有关更多信息,请参阅 Authorisation refusal reasons.
    resultCodeString付款的结果。 有关更多信息,请参见Result codes.

    例子:

    { 
        "3DAuthenticated":false, 
        "3DOffered":false, 
        "action":{ 
            "method":"GET", 
            "paymentMethodType":"alipay", 
            "resendInterval":0, 
            "resendMaxAttempts":0, 
            "type":"redirect", 
            "url":"https://checkoutshopper-test.adyen.com/checkoutshopper/checkoutPaymentRedirect?redirectData=X6XtfGC3%21eyJHbHVlcGFnZURhdGEiOnsiYnJhbmRDb2RlIjoiYWxpcGF5IiwibWVyY2hhbnRBY2NvdW50IjoiQmFvbWlodWFFQ09NIiwicmVkaXJlY3RQYXltZW50RGF0YSI6eyJhY3F1aXJlckFjY291bnRJZCI6MTA5NzgyLCJhbW91bnQiOnsiY3VycmVuY3kiOiJDTlkiLCJ2YWx1ZSI6MTB9LCJhcGlWZXJzaW9uIjo2NywiYXBwbGljYXRpb25JbmZvIjp7ImFkeWVuTGlicmFyeSI6eyJuYW1lIjoiYWR5ZW4tamF2YS1hcGktbGlicmFyeSIsInZlcnNpb24iOiIxMy4xLjAifX0sImJyYW5kQ29kZSI6ImFsaXBheSIsImNoZWNrb3V0Q2hhbm5lbCI6IldlYiIsImNvdW50cnlDb2RlIjoiQ04iLCJtZXJjaGFudEFjY291bnQiOiJCYW9taWh1YUVDT00iLCJtZXJjaGFudFJlZmVyZW5jZSI6IjliMDFmYjIxLTE2ZmQtNGU0ZS1iOTgzLTI0ZWZmMmU3ZGVlMCIsIm9yaWdpbmFsUHNwUmVmZXJlbmNlIjoiODgxNjE5Njc4MDQ1NzMzRCIsInBhbFJlc3VsdFBzcFJlZmVyZW5jZSI6Ijg1MzYxOTY3ODA0NTkxNUYiLCJyZXF1ZXN0QWRkaXRpb25hbERhdGEiOnsiYXBwbGljYXRpb25JbmZvLmxpYnJhcnlWZXJzaW9uIjoiMTMuMS4wIiwibWVyY2hhbnRJbnRlZ3JhdGlvbi52ZXJzaW9uIjoiNjciLCJhcHBsaWNhdGlvbkluZm8ubGlicmFyeU5hbWUiOiJhZHllbi1qYXZhLWFwaS1saWJyYXJ5IiwibWVyY2hhbnRJbnRlZ3JhdGlvbi50eXBlIjoiQ0hFQ0tPVVRfR0VORVJJQyIsInJldHVyblVybCI6Imh0dHBzOlwvXC9jaGVja291dHNob3BwZXItdGVzdC5hZHllbi5jb21cL2NoZWNrb3V0c2hvcHBlclwvY2hlY2tvdXRQYXltZW50UmV0dXJuP2dwaWQ9R1A0NjQwNkU2Q0U1MzdCNDdGIiwicGxhdGZvcm0iOiJBbGlQYXlGWFRlc3QifSwicmV0dXJuVXJsIjoiaHR0cHM6XC9cL2NoZWNrb3V0c2hvcHBlci10ZXN0LmFkeWVuLmNvbVwvY2hlY2tvdXRzaG9wcGVyXC9jaGVja291dFBheW1lbnRSZXR1cm4%2FZ3BpZD1HUDQ2NDA2RTZDRTUzN0I0N0YiLCJzZWxlY3RlZEJyYW5kIjoiYWxpcGF5Iiwic2hvcHBlclJlZmVyZW5jZSI6IkphdmEgQ2hlY2tvdXQgU2hvcHBlciIsInNraW5Db2RlIjoicHViLnYyLjgwMTYxOTQ5MzY0MTAxMzAuMWpxYVJDZ2lWU0RRNU03bEIzQTllSUZSWnpxWHhfOFlYM1ZUY3BJTlBKVSJ9LCJyZWRpcmVjdFVybCI6Imh0dHBzOlwvXC9vcGVuYXBpLmFsaXBheWRldi5jb21cL2dhdGV3YXkuZG8%2FX2lucHV0X2NoYXJzZXQ9VVRGOCZib2R5PTliMDFmYjIxLTE2ZmQtNGU0ZS1iOTgzLTI0ZWZmMmU3ZGVlMCZjdXJyZW5jeT1VU0Qmbm90aWZ5X3VybD1odHRwcyUzQSUyRiUyRnRlc3QuYWR5ZW4uY29tJTJGaHBwJTJGbm90aWZpY2F0aW9uQWxpUGF5RlhUZXN0LnNodG1sJTNGcyUzRHB1Yi52Mi44MDE2MTk0OTM2NDEwMTMwLjFqcWFSQ2dpVlNEUTVNN2xCM0E5ZUlGUlp6cVh4XzhZWDNWVGNwSU5QSlUlMjZtJTNEQmFvbWlodWFFQ09NJm91dF90cmFkZV9ubz1BbGlQYXlGWFRlc3QlM0E4NTM2MTk2NzgwNDU5MTVGJTNBMTA5NzgyJnBhcnRuZXI9MjA4ODEwMTEyMjEzNjI0MSZyZWZlcl91cmw9aHR0cHMlM0ElMkYlMkZ3d3cuYWR5ZW4uY29tJTJGJnJldHVybl91cmw9aHR0cHMlM0ElMkYlMkZjaGVja291dHNob3BwZXItdGVzdC5hZHllbi5jb20lMkZjaGVja291dHNob3BwZXIlMkZjaGVja291dFBheW1lbnRSZXR1cm4lM0ZncGlkJTNER1A0NjQwNkU2Q0U1MzdCNDdGJnJtYl9mZWU9MC4xMCZzZWNvbmRhcnlfbWVyY2hhbnRfaWQ9QmFvbWlodWFFQ09NJnNlY29uZGFyeV9tZXJjaGFudF9pbmR1c3RyeT04OTk5JnNlY29uZGFyeV9tZXJjaGFudF9uYW1lPUJhb21paHVhRUNPTSZzZXJ2aWNlPWNyZWF0ZV9mb3JleF90cmFkZSZzaWduPTM1YjNkZWExZTQyNDdlNGQ3YmNkZTRmZDY4ZDBjMWE1JnNpZ25fdHlwZT1NRDUmc3ViamVjdD05YjAxZmIyMS0xNmZkLTRlNGUtYjk4My0yNGVmZjJlN2RlZTAmc3VwcGxpZXI9QmFvbWlodWFFQ09NIiwicmV0dXJuVXJsIjoiaHR0cDpcL1wvbG9jYWxob3N0OjgwODBcL2FwaVwvaGFuZGxlU2hvcHBlclJlZGlyZWN0P29yZGVyUmVmPTliMDFmYjIxLTE2ZmQtNGU0ZS1iOTgzLTI0ZWZmMmU3ZGVlMCJ9fQ%3D%3DrcJiiOxlakrNqUCHoXmIjijmdfsJS%2FqhWvg9MFbwI7U%3D" 
        }, 
        "resultCode":"redirectshopper" 
    }
    

    第三步:继续付款

    提交有关使用创建的付款的详细信息/payments。仅当/payments请求的最终状态尚未达到时(例如,购物者被重定向到另一页以完成付款),才需要执行此步骤。

    请求:

    请求URL:

    /payments/details

    请求方式:

    POST

    请求参数:

    参数名称必填字段类型描述
    details对象使用此集合提交作为/payments调用结果返回的详细信息。
    +MDString由发卡机构返回的支付会话标识符。
    +PaReqString(3D)发卡机构的支付认证请求数据。
    +PaResString(3D)发卡机构的支付认证响应数据。
    +billingTokenString用于经常性支付的paypal生成代币。
    + cupsecureplus.smscodeString从购物者那里收集到的短信验证码。
    +facilitatorAccessTokenStringpaypal生成的第三方访问令牌。
    +oneTimePasscodeString发送到购物者的手机号码以验证付款的随机数字。
    +orderIDStringpaypal指定的订单ID。
    +payerIDStringpaypal为付款人(购物者)分配的ID。
    +payloadString作为重定向结果附加到returnURL的有效负载。
    +paymentIDStringpaypal生成的支付ID。
    +paymentStatusString从微信MiniProgram wx.requestPayment完成回调传递的值。 取值范围:以requestPayment:开头的任意值。
    +redirectResultString重定向的结果被附加到returnURL
    + threeds2.fingerprintString组件在询问流之后返回的base64编码的字符串。 它包含以下参数:threeDSCompInd。
    + threeds2.challengeResultString组件在询问流之后返回的base64编码的字符串。 包含transStatus参数。
    +threeDSResultString组件在询问流之后返回的base64编码的字符串。 包含transStatus、authorisationToken。
    paymentDataString来自/payments响应的paymentData值。如果/payment响应返回此值则为必需。在v67及以后的版本中,您将总是从组件中获得这个值。

    例子:

    { 
        "details":{ 
            "redirectResult":"X6XtfGC3!eyJyZWRpcmVjdFBheW1lbnREYXRhIjp7ImFjcXVpcmVyQWNjb3VudElkIjoxMDk3ODIsImFtb3VudCI6eyJjdXJyZW5jeSI6IkNOWSIsInZhbHVlIjoxMH0sImFwaVZlcnNpb24iOjY3LCJhcHBsaWNhdGlvbkluZm8iOnsiYWR5ZW5MaWJyYXJ5Ijp7Im5hbWUiOiJhZHllbi1qYXZhLWFwaS1saWJyYXJ5IiwidmVyc2lvbiI6IjEzLjEuMCJ9fSwiYnJhbmRDb2RlIjoiYWxpcGF5IiwiY2hlY2tvdXRDaGFubmVsIjoiV2ViIiwiY291bnRyeUNvZGUiOiJDTiIsIm1lcmNoYW50QWNjb3VudCI6IkJhb21paHVhRUNPTSIsIm1lcmNoYW50UmVmZXJlbmNlIjoiMjc1M2E3NjktZTAzZS00NjA1LThkYWUtYzk5NzExNDUzYThhIiwib3JpZ2luYWxQc3BSZWZlcmVuY2UiOiI4ODE2MTk2NzgyNjA2MjVLIiwicGFsUmVzdWx0UHNwUmVmZXJlbmNlIjoiODgzNjE5Njc4MjYwODU3RSIsInJlcXVlc3RBZGRpdGlvbmFsRGF0YSI6eyJhcHBsaWNhdGlvbkluZm8ubGlicmFyeVZlcnNpb24iOiIxMy4xLjAiLCJtZXJjaGFudEludGVncmF0aW9uLnZlcnNpb24iOiI2NyIsImFwcGxpY2F0aW9uSW5mby5saWJyYXJ5TmFtZSI6ImFkeWVuLWphdmEtYXBpLWxpYnJhcnkiLCJtZXJjaGFudEludGVncmF0aW9uLnR5cGUiOiJDSEVDS09VVF9HRU5FUklDIiwicmV0dXJuVXJsIjoiaHR0cHM6XC9cL2NoZWNrb3V0c2hvcHBlci10ZXN0LmFkeWVuLmNvbVwvY2hlY2tvdXRzaG9wcGVyXC9jaGVja291dFBheW1lbnRSZXR1cm4/Z3BpZD1HUDlBRDNFNDdGOTkxN0JBQzMiLCJwbGF0Zm9ybSI6IkFsaVBheUZYVGVzdCJ9LCJyZXR1cm5VcmwiOiJodHRwczpcL1wvY2hlY2tvdXRzaG9wcGVyLXRlc3QuYWR5ZW4uY29tXC9jaGVja291dHNob3BwZXJcL2NoZWNrb3V0UGF5bWVudFJldHVybj9ncGlkPUdQOUFEM0U0N0Y5OTE3QkFDMyIsInNlbGVjdGVkQnJhbmQiOiJhbGlwYXkiLCJzaG9wcGVyUmVmZXJlbmNlIjoiSmF2YSBDaGVja291dCBTaG9wcGVyIiwic2tpbkNvZGUiOiJwdWIudjIuODAxNjE5NDkzNjQxMDEzMC4xanFhUkNnaVZTRFE1TTdsQjNBOWVJRlJaenFYeF84WVgzVlRjcElOUEpVIn0sInJldHVyblVybFBhcmFtcyI6eyJvdXRfdHJhZGVfbm8iOiJBbGlQYXlGWFRlc3Q6ODgzNjE5Njc4MjYwODU3RToxMDk3ODIiLCJ0b3RhbF9mZWUiOiIwLjAyIiwidHJhZGVfc3RhdHVzIjoiVFJBREVfRklOSVNIRUQiLCJzaWduIjoiYzI3ZWI5Nzc1YTJiZDUyYTExMGY5ZGU5M2MxZTBjNzgiLCJ0cmFkZV9ubyI6IjIwMjEwNDI5MjIwMDEzNTg3NTA1MDEzOTc1ODAiLCJjdXJyZW5jeSI6IlVTRCIsInNpZ25fdHlwZSI6Ik1ENSJ9fQ==CSUOdt995jlxCLAua2J7ieyT5HJN9IZmpI1ny8vInzE=" 
        } 
    }
    

    响应:

    响应参数:

    参数名称参数类型描述
    action对象为完成付款而采取的行动。只有3D安全行动是需要在大多数情况下返回。
    additionalData对象包含关于付款的附加信息。 只有在您先选择某些数据字段时,才会包含它们,去设置:Customer Area > Account > API URLs > Additional data
    amountAmount交易中的授权金额。
    paymentMethodString交易中使用的支付方式。
    pspReferenceStringAdyen与事务/请求关联的16个字符的字符串引用。 这个值是全局唯一的; 报价时,与我们沟通这个要求。
    shopperLocaleString购物者的地址
    resultCodeString付款的结果。 有关更多信息,请参见Result codes.
    refusalReasonCodeString指明拒绝理由的代码。 有关更多信息,请参见Authorisation refusal reasons.
    refusalReasonString如果付款的授权被拒绝或在授权期间发生错误,这个字段保存Adyen的拒绝原因映射或错误描述。 当事务失败时,授权响应包括resultCode和refusalReason值。 有关更多信息,请参见Refusal reasons.
    merchantReferenceString在/付款请求期间使用的引用(订单号)

    例子:

    { 
        "3DAuthenticated":false, 
        "3DOffered":false, 
        "additionalData":{ 
            "Alipay.OutTradeNo":"AliPayFXTest:883619678260857E:109782", 
            "Alipay.BuyerEmail":"san***@alipay.com", 
            "Alipay.BuyerId":"2088102144158754", 
            "Alipay.TradeNo":"2021042922001358750501397580" 
        }, 
        "amount":{ 
            "currency":"CNY", 
            "decimalValue":0.1, 
            "value":10 
        }, 
        "merchantReference":"2753a769-e03e-4605-8dae-c99711453a8a", 
        "pspReference":"883619678260857E", 
        "resultCode":"authorised" 
    }
    
    展开全文
    Young_Black 2021-04-29 15:58:41
  • qq_24839631 2021-10-23 11:55:58
  • weixin_40629244 2021-02-07 22:47:54
  • qq_42223569 2021-01-14 09:40:05
  • supertwoone 2021-11-27 09:12:48
  • nanguo123 2021-08-11 16:01:28
  • weixin_44695057 2021-01-23 16:02:49
  • weixin_36145011 2021-03-13 18:48:11
  • zdw19861127 2021-04-15 17:04:50
  • weixin_36237054 2021-04-30 02:15:17
  • a898712940 2021-03-20 14:27:48
  • darksociety 2021-03-10 19:02:07
  • weixin_40629244 2021-02-10 15:29:10
  • weixin_42661167 2021-03-05 10:16:39
  • machunlin2010 2021-11-18 13:20:19
  • weixin_39609718 2021-04-21 06:54:34
  • weixin_41715077 2021-02-04 17:27:54
  • weixin_34768019 2021-07-26 02:59:32
  • weixin_39560002 2021-02-12 14:40:55
  • pdd11997110103 2021-02-02 09:37:40
  • alkie_drunk 2021-11-16 17:09:56
  • weixin_30260621 2021-04-07 08:26:44
  • leadseczgw01 2021-12-09 11:14:04
  • weixin_33204286 2021-04-10 14:07:27
  • Lookuptosky 2021-06-24 14:00:39
  • weixin_29526313 2020-12-29 07:41:46
  • Acer2016 2021-08-10 16:50:43

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 153,642
精华内容 61,456
关键字:

支付流程

友情链接: fangzhen.zip