支付宝沙盒

支付宝沙箱功能的使用

支付结构图

  • 大体结构图:

hVEy0s.png

  • 详细结构图

流程图

模拟支付代码

  • 真正支付是商家app下单->商家后台产生订单信息->为订单信息创建支付接口->返回支付结果给商家app异步调动商家后台

  • 模拟: 自定义数据->为其创建支付->返回支付结果给商家app异步创建订单信息->将信息存入数据库

  • 两者区别,先创建订单再支付,还是先支付再创建订单。(这里采用第二种)

1、资源配置类

server:
  port: 8090

spring:
  datasource:
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    url: jdbc:mysql://localhost:3306/seckill?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&autoReconnect=true&failOverReadOnly=false

#没用到
  redis:
    host: 127.0.0.1
    port: 6379
#用于实现订单超时
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: test
    password: 123456
    virtual-host: /test
    listener:
      type: simple
      simple:
        acknowledge-mode: manual
        default-requeue-rejected: false

2、配置类

public class AlipayConfigInfo {

    // 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
    public static String app_id="2021000118******";
    // 商户私钥,您的PKCS8格式RSA2私钥
    public static String merchant_private_key = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCxJ3d8MYUrrJ+Bte5q8v9JOxw3YGbrkxNNufiBwb0cKjxRDg5QADl149+nn/REgWmR6dLCatVZYy2avFcuUuYd0/xdPYZskUb6YtGrghwPVzmuNAPORBnt6hBGWJRduNIBnyoONRzXugJRRFDa3Mr3l9Ca0J4+AzNdXzEYXWU5Xci3c7uruZ9XRoLBrjvmMPL71e9hnJQ5Z9qGSq92qdgh83jUE189HcmmFVqwpAaMQhEkTukuKwjy6UF6FzoYO7dH/wzQJBeFJv1ePm90dJmQLh7gvZ8TdyVrDlx0RT9vP2l1EkCTww7jaUteOPXzCdgi9PqOTbgtQNLdVeSB0R9HAgMBAAECggEBAKVc+MzGENAGz9GteIL+lsvN0HXkl824OSGpwc2lghgjWLA0lamZvAlOj3wR9FpqDph0khaG0OYijPROcHa+TS10rrJ+dtcq+P1KdvtIdVbgjegNh6vnp+iMP2razot5tRZscz5V17mLWRRw16SkyxU48jFBISUzqaOz8skSjSVw1wg1Cr0ScHU8tP9BJ+ELXs/3JDM/w8erCjaVVbpmCDmegq6Zu3WmqiLj+EEmxa3oe0pAilgKwAKs1ot0UlYLuYvuTXf3S5R42AVnmkS/bOFwgNiN+5AvwZYZZ/s/1ld9W6HvjEGQ6A2vdPwWiG4XE4jC7clFCbT7YYIyiQwWHgECgYEA2BYJ6kJyz1OnR7BeguSWl5I6gZ+H51hJsgMf28/pDYQSLly+kmdKklM8yznXI21emhDeN3xM9KGmKOqpI0CsFtbKhiNp2DKO/Fg/t2nooPNVkUget2hpxuZKZZWAVmCqRY0tZrVblQxJUd/2QCxeDJLJV84ztRdd5QCBfGIGQwECgYEA0eB494eCrDYI2hugSDb7bjeczxsEyBlgvNH+FArvqoJEJjwByaUX8U146fdmlpzirohstkMW3I75iCpZSbKFmQDTRHV2AlPCcGtle/5FJGbw4+W3ahJTU3i4zrtZup0WAhEmeqlszf8mSmtNOV20J1OIL9MgRcGdQGdaHI/2ikcCgYEAy423OV3vGS8MXZPe9B6xXYb6ZjEJrPyWL4KR+Fcaiwjmt5XWT8PNk5mloyuRZmYYv7k0G8CUHb5I8DJdsj+x3LHphgLGKks2NrBLFVRHN5cB/CGcDdnmCt/VJWx3wOa+f1ZGdoJRC07Porj/F+Szk9SSpowwWV7xrE+Vqr4MeAECgYASDVG6UMCPmXI3eGrX60rDFyt4sOU/ZNdqRlGpXatxqhS8iSrKMlYV3kkJLst3JvVkd72KC8k6nV2fNa1KZn2RRH3nhIbq+lNeIg6vlJZT5DrSD18wU3UxV8/lkD3OjFZpRRpfMJV4PnsHqaURyxqEy22KV4mOFnI1KO6aSFO3XwKBgQC7GdDHszlMyD1rSUP1RiMXoUZq/S+IY20gZbdAXdlLYtUInRLSEpyTJhIhHF0scqpQSPMbUzWEoyjV7vU7swv40oBC9oyyXOO8P6j72wmrraw8/SAtX1YZBtG6tJeMIUIenGqA68FvEiul7fCwOPO85GKtSpypoidjnxFX+Fqj0g==";
    // 支付宝公钥
    // 对应APPID下的支付宝公钥。你的公钥
    public static String alipay_public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlXQ2puhU475iJGI1WEM2ArLu1i5uhdrLa8WpHUB4pc9ZrGWAdJZd3UVr9NuBb6+4x4LZILTWHrIr/7AjaIaOb7ub4JnFNnpy61U7bXHUANV8kkjwMxPYLXdg05Yoo5MsnGyUYUmlb8Zyik6t5BktyUpcEoGAmxpAPZoLMCkKme5jbFLzv1VzWxCfGXQKsJoOHfTMG2xQXEk7MR3+8/MLVpuffqgNfdrvxpzH1vlvbVs0L3//t/eOH+lOUHhF/fM6Lcc68KBNN330TIXS8+wl+FDfQkcLL1kL7YfK6W5fSFaMzJkhuq8voyz+bW8ngaTYuh3MkK7x04+GqUsaj8TQKQIDAQAB";
    // 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    /**
     * 返回的时候此页面不会返回到用户页面,只会执行你写到控制器里的地址,用户端回调方式是get
     这里地址是采用内网映射 可以采用natapp或者ngork https://natapp.cn/
     */
    public static String return_url = "http://5t4x9a.natappfree.cc/success";
    // 页面跳转同步通知页面路径 需http://格式的完整路径,返回的路径方式时post
    public static String notify_url="http://5t4x9a.natappfree.cc/nodify";
    // 签名方式
    public static String sign_type = "RSA2";
    // 返回格式
    public static String format = "json";
    // 字符编码格式
    public static String charset = "utf-8";
    // 支付宝网关
    public static String gatewayUrl="https://openapi.alipaydev.com/gateway.do";

     //实例化客户端
    private static AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl,app_id,merchant_private_key,format,charset,alipay_public_key,sign_type);

}

3、实体类

//这里只记录订单信息
@Entity
@Table(name = "F_orders")
@Data
@AllArgsConstructor
public class Orders {
    public Orders(){
        Date now = new Date();
        this.createTime = now;
        this.updateTime = now;
    }

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(name = "id")
    private int id;
    @Column(name = "order_id")
    private String orderId;
    @Column(name = "user_id")
    private String userId;
    @Column(name = "order_number")
    private int orderNumber;
    @Column(name = "total_money")
    private float totalPrice;
    @Column(name = "create_time")
    private Date createTime;
    @Column(name = "update_time")
    private Date updateTime;
}

4、dto(展示层)

@ApiModel(value = "订单信息")
@Data
public class OrdersDo {

    @ApiModelProperty(value = "id",example = "12123214")
    private int id;
    @ApiModelProperty(value = "订单id",example = "924021")
    private String orderId;
    @ApiModelProperty(value = "用户id",example = "12312124")
    private String userId;
    @ApiModelProperty(value = "商品总数",example = "23")
    private int orderNumber;
    @ApiModelProperty(value = "商品总金额",example = "24231")
    private float totalPrice;
    private Date createTime;
    private Date updateTime;
}

5、类型转换

@Mapper
public interface OrdersHelper {

    OrdersHelper INSTANCE = Mappers.getMapper(OrdersHelper.class);

    Orders transformInit(@MappingTarget Orders orders , OrdersDo orderDo);
    OrdersDo transform4Update(@MappingTarget OrdersDo orderDo , Orders orders);
}

6、dao层

public interface OrdersDao extends JpaSpecificationExecutor<Orders>, JpaRepository<Orders,Integer> {
}

7、业务层

@Service
public class OrdersService {

    @Autowired
    private OrdersDao ordersDao;

    public OrdersDo save(String id,String userId,int count,float total){
        Orders orders = new Orders();
        orders.setOrderId(id);
        orders.setUserId(userId);
        orders.setOrderNumber(count);
        orders.setTotalPrice(total);
        ordersDao.save(orders);
        return OrdersHelper.INSTANCE.transform4Update(new OrdersDo(),orders);
    }
}

8、控制层

  • 路径控制
@Controller
public class UrlController {

    @Autowired
    private OrdersService ordersService;

    //用户付款成功后回调路径
    @GetMapping("/success")
    @ResponseBody
    public String success(){
        return "成功付款";
    }

    //模拟调用商户服务器接口
    @PostMapping("/nodify")
    public void nodify(HttpServletRequest request){
        String out_trade_no = request.getParameter("out_trade_no");
        float total_amount = Float.valueOf(request.getParameter("total_amount"));
//        List<String> list = JSON.parseArray(goods_detail, String.class);
        int count = 1;
        OrdersDo ordersDo = ordersService.save(out_trade_no, "213142142121", count, total_amount);
        System.out.println(ordersDo);
    }
}

  • 调用支付宝接口


@Controller
public class AlipayController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public static void returnResponse (HttpServletResponse response,String form){
        try {
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().write(form);
            response.getWriter().flush();
            response.getWriter().close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    //创建订单整合Rabbitmq实现订单超时关闭交易
    @GetMapping("/createGrade")
    public void createGrade(HttpServletResponse response)  {
      try {
          SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
          String format = sdf.format(new Date());
          Message message = new Message(("关闭交易当前时间:"+format).getBytes(StandardCharsets.UTF_8));
          AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        String outTradeNo = "33"; // 商户订单号,商户网站订单系统中唯一订单号,必填
        String totalAmount = "99.9"; // 付款金额,必填
        String subject = "羽绒服"; // 订单名称,必填
        String body = "冬日神器"; // 商品描述,可空
        String buyer_id = "ggbwwk8873@sandbox.com";
        request.setBizContent("{\"out_trade_no\":\"" + outTradeNo + "\","
                + "\"total_amount\":\"" + totalAmount + "\","
                + "\"subject\":\"" + subject + "\","
                + "\"body\":\"" + body + "\","
                + "\"buyer_id\":\"" + buyer_id + "\","
                +"      \"goods_detail\":[{" +
                "        \"goods_id\":\"123214421311\"," +
                "\"goods_name\":\"ipad\"," +
                "\"quantity\":1," +
                "\"price\":2000," +
                "\"goods_category\":\"34543238\"," +
                "\"categories_tree\":\"124868003|126232002|126252004\"," +
                "\"body\":\"特价手机\"," +
                "\"show_url\":\"http://www.alipay.com/xxx.jpg\"" +
                "        }],"
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
        // 在公共参数中设置回跳和通知地址
        //用户支付成功返回地址
        request.setReturnUrl(return_url);
        //商家接收地址
        request.setNotifyUrl(notify_url);
          AlipayTradePagePayResponse payResponse = alipayClient.pageExecute(request);
          rabbitTemplate.convertAndSend("direct.delay.exchange","DelayKey",message);
          String form = payResponse.getBody();
         returnResponse(response,form);
    } catch (AlipayApiException  e) {
        e.printStackTrace();
    }
    }

    //查询订单信息
    @GetMapping("/query")
    public void queryTrace(HttpServletResponse response) throws Exception {
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        request.setBizContent("{" +
                "\"out_trade_no\":\"33\"," +
                "      \"query_options\":[" +
                "        \"trade_settle_info\"" +
                "      ]" +
                "  }");
        AlipayTradeQueryResponse tradeQueryResponse = alipayClient.execute(request);
        String body = tradeQueryResponse.getBody();
        returnResponse(response,body);
    }

    //撤销订单
    @GetMapping("/cancelTrade")
    public void cancelTrade(HttpServletResponse response) throws Exception{
        AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();
        request.setBizContent("{" +
                "\"out_trade_no\":\"33\"," +
                "\"trade_no\":\"\"" +
                "}");
        AlipayTradeCancelResponse tradeCancelResponse = alipayClient.execute(request);
        String body = tradeCancelResponse.getBody();
       returnResponse(response,body);
        if (tradeCancelResponse.isSuccess()){
            System.out.println("删除订单或者修改订单状态");
        }
    }

    //交易退款 
    @GetMapping("/refundTrade")
    public void refundTrade(HttpServletResponse response) throws Exception{
        while (true){
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            String refund_amount = "50";
            request.setBizContent("{" +
                    "\"out_trade_no\":\"33\"," +
                    "\"trade_no\":\"\"," +
                    "\"refund_amount\":50," +
                    "\"refund_reason\":\"正常退款\"," +
                    "\"out_request_no\":\"HZ01RF001\"," +
                    "      \"refund_royalty_parameters\":[{" +
                    "        \"royalty_type\":\"transfer\"," +
                    "\"trans_out\":\"mswwrs2745@sandbox.com\"," +
                    "\"trans_out_type\":\"loginName\"," +
                    "\"trans_in_type\":\"loginName\"," +
                    "\"trans_in\":\"ggbwwk8873@sandbox.com\"," +
                    "\"amount\":0.1," +
                    "\"desc\":\"分账给ggbwwk8873@sandbox.com\"" +
                    "        }]" +
                    "  }");
            AlipayTradeRefundResponse alipayTradeRefundResponse = alipayClient.execute(request);
            String form = alipayTradeRefundResponse.getBody();
            returnResponse(response,form);
            if (alipayTradeRefundResponse.isSuccess()){
                System.out.println("退款金额:"+refund_amount);
                break;
            }
            Thread.sleep(5000);
        }
    }


    //查询订单下载地址
    @GetMapping("/orderQuery")
    public void orderQuery(HttpServletResponse response) throws AlipayApiException {
        AlipayDataDataserviceBillDownloadurlQueryRequest request = new AlipayDataDataserviceBillDownloadurlQueryRequest();
        request.setBizContent("{" +
                "\"bill_type\":\"trade\"," +
                "\"bill_date\":\"2021-08-25\"" +
                "  }");
        AlipayDataDataserviceBillDownloadurlQueryResponse queryResponse = alipayClient.execute(request);
        String form = queryResponse.getBody();
        System.out.println(form);
        returnResponse(response,form);
        if (queryResponse.isSuccess()){
            System.out.println("查询成功");
        }
    }

}

9、RabbitMq

  • 配置
@Configuration
public class RabbitMQConfig {

    private static String direct_queue = "direct.pay.queue";
    private static String exchange = "direct.pay.exchange";
    private static String dead_exchange = "dead_exchange";
    private static String routing_key = "routing_key";

    @Bean
    public Queue directQueue(){
        Map<String,Object> args = new HashMap<>(3);
        args.put("x-dead-letter-exchange",dead_exchange);
        args.put("x-dead-letter-routing-key","DelayKey");
        //10秒过期
        args.put("x-message-ttl",10000);
        //队列名 是否持久化 是否独占队列 是否自动删除 其他规则
        return new Queue(direct_queue,true,false,false,args);
    }

    @Bean
    public DirectExchange directExchange(){
        return new DirectExchange(exchange);
    }


    @Bean
    public Binding binding(){
        return BindingBuilder.bind(directQueue()).to(directExchange()).with(routing_key);
    }
}
  • 消费
@Component
public class DelayConsumer {
    
    //延时队列实现订单超时关闭支付
    @RabbitListener(bindings = {@QueueBinding(value = @Queue(value = "direct.delay.queue"),exchange = @Exchange(value = "direct.delay.exchange"),key = {"DelayKey"})})
    public void counsumer(Channel channel, Message message) throws Exception {
        System.out.println(message.getBody());
        AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
        request.setBizContent("{" +
                "\"out_trade_no\":\"33\"" +
                "  }");
        AlipayTradeCloseResponse response = alipayClient.execute(request);
        System.out.println("成功");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = sdf.format(new Date());
        System.out.println("关闭订单当前时间:"+format);
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }
}
  • 延时队列结构图

hZohan.png

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值