支付宝API支付使用文档--java《扫一扫支付》--demo但是封装高可用--改一改配置就拿走用!超详细!!有手就行!!!--spring +vue-调用支付宝的当面付的预创建接口

支付宝API支付使用文档--java《扫一扫支付》--demo但是封装高可用--改一改配置就拿走用!超详细!!有手就行!!!(上)修改官网配置类_一单成的博客-CSDN博客

阿丹:

        上一篇文章具体的描述和讲解了官方提供的配置类,以及如何使用注册开发沙箱,本篇文章重点描述和讲解如何实现代码的编写,以及具体实现的流程,以及数据的流向。重点是将开发的过程记录,并最后封装为工具类方便大家开发。尽量做到拿取代码修改配置即可使用。

阿丹提醒:

        请在阅读本文章之前先详细查看阿丹的效果演示说明以及本文章中需要的技术栈以及核心思想。以及该技术点的特性。

 展示为网站和手机进行支付交互。演示图片中的二维码为一次性扫描的二维码。

解释说明:

        本代码或者说例子是用在当面付的预创建接口

        构建以及使用这个类:AlipayTradePrecreateRequest

开发思路:

在上次开发的时候我们发现有这两个地址没有写,并且会有疑惑我扫描二维码的页面哪里来呢?

不要着急我在后面会进行说明的。

实现思路以及流程图梳理

在文章中我就不在详解加签等操作了(之前已经完成了封装),我们主要讲解一下,专注于业务的流程以及数据流向。

 我将数据流向分为了三条线方便大家,梳理,理解

黑:

        1、用户进入结算付款页面

        2、根据用户订单信息构建PayReq实体类,携带实体类访问请求/createQR接口

        3、与服务/bindingRecord建立websocket连接(用于监听支付信息/状态)

红:

        1、/createQR接口生成支付二维码,通过返回response结果的方式来在vue页面使用弹框展示。

        2、用户使用扫一扫扫码支付

        3、用户手机请求到支付宝应用

绿:

        1、支付宝给我们的系统发送支付状态信息,请求调用了/call接口

        2、call接口向前台发送支付完成信息完成支付!!

我们开始上代码!!

后台代码:

        梳理其实实现很简单。我们需要一个生成二维码的接口、一个websocket接口、一个回调函数(获取支付状态)

相关配置以及使用沙箱说明在这里拿取!!!!!

 用于websocekt连接!!

package com.adn.controller;


import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 *  WebSocket服务
 *
 **/
//连接webSocket服务的URL
@ServerEndpoint("/bindingRecord")
@Component
@Slf4j
public class WebSocket {

    private Session session;
    private static CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>();

    /**
     * 新建webSocket配置类
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
    /**
     * 建立连接
     * @param session
     */
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        webSockets.add(this);
        log.info("【新建连接】,连接总数:{}", webSockets.size());
    }

    /**
     * 断开连接
     */
    @OnClose
    public void onClose(){
        webSockets.remove(this);
        log.info("【断开连接】,连接总数:{}", webSockets.size());
    }

    /**
     * 接收到信息
     * @param message
     */
    @OnMessage
    public void onMessage(String message){
        log.info("【收到】,客户端的信息:{},连接总数:{}", message, webSockets.size());
    }

    /**
     * 发送消息
     * @param message
     */
    public void sendMessage(String message){
        log.info("【广播发送】,信息:{},总连接数:{}", message, webSockets.size());
        for (WebSocket webSocket : webSockets) {
            try {
                webSocket.session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                log.info("【广播发送】,信息异常:{}", e.fillInStackTrace());
            }
        }
    }

}

 代码解释:

这段代码是一个WebSocket服务实现类。它使用了Spring framework提供的注解和依赖项,可以轻松地创建一个WebSocket服务器端点。

主要的注解包括:

  • @ServerEndpoint("/bindingRecord"):指定WebSocket的URL地址,客户端将通过这个地址连接到WebSocket服务器。
  • @Component:将该类声明为Spring组件,可以被Spring容器管理。
  • @OnOpen@OnClose@OnMessage:这些注解用于定义WebSocket的生命周期回调方法。
  • @Bean:这个注解用于表明serverEndpointExporter()方法返回的实例将被Spring容器管理,用于将WebSocket的相关配置发布为服务器的端点。

该类还包括一些实例变量和方法,用于处理WebSocket连接和消息的收发:

  • session:表示当前连接的WebSocket会话。
  • webSockets:一个用于存储所有连接到WebSocket服务器的WebSocket实例的并发集合。
  • onOpen():建立连接时调用的方法,将新的WebSocket实例添加到webSockets集合中。
  • onClose():断开连接时调用的方法,从webSockets集合中移除当前WebSocket实例。
  • onMessage():收到客户端发送的消息时调用的方法,在控制台打印消息和连接总数。
  • sendMessage():用于广播消息给所有连接的客户端,使用getBasicRemote().sendText(message)方法发送消息。

总的来说,这段代码实现了一个简单的WebSocket服务端,可以与客户端建立连接并进行消息的收发。

请求实体类!

package com.adn.common.domain.request;

import lombok.Data;

/**
 * 支付请求实体类
 * */
@Data
public class PayReq {
    //商品订单号
    private String out_trade_no;
    //订单名称
    private String subject;
    //付款金额
    private String total_amount;
    //商品订单描述
    private String body;
}

商品订单号、订单名称、付款金额、商品描述这几个参数只有商品订单描述可以选填,其他的都不能为空!!

后台请求

/createQR、/call接口书写

package com.adn.controller;

import com.adn.common.domain.request.PayReq;
import com.adn.common.domain.response.AliReturnPayBean;
import com.adn.common.result.Result;
import com.adn.common.utils.AppUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import lombok.extern.log4j.Log4j2;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@RestController
@Log4j2
public class PayController {
    @Resource
    private AlipayClient alipayClient;
    @Resource
    private AlipayTradePagePayRequest alipayTradePagePayRequest;

    @Autowired
    private AppUtil appUtil;

    @Autowired
    private WebSocket webSocket;


    @RequestMapping("/createQR")
    public Result send(@RequestBody PayReq req) {
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest(); //创建API对应的request/0/ 类
//        request.setNotifyUrl("http://cv95x3.natappfree.cc/call");
        System.out.println(req.toString());
        request.setNotifyUrl(appUtil.getNotifyurl());
        //同步回调地址
//        request.setReturnUrl("");
        request.setBizContent("{\"out_trade_no\":\""+ req.getOut_trade_no() +"\","
                + "\"total_amount\":\""+ req.getTotal_amount() +"\","
                + "\"subject\":\""+ req.getSubject() +"\","
                + "\"body\":\""+ req.getBody() +"\","
                + "\"product_code\":\"FACE_TO_FACE_PAYMENT\"}");
        AlipayTradePrecreateResponse response = null;
        try {
            response = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }
        if (response.isSuccess()) {
            System.out.println("调用成功");
            //获取二维码
            return Result.success(response.getQrCode());
        } else {
            System.out.println("调用失败");
        }
        return Result.error();
    }


    /**
     * 支付宝回调函数
     * @param request
     * @param response
     * @param returnPay
     * @throws IOException
     */
    @RequestMapping("/call")
    public void call(HttpServletRequest request, HttpServletResponse response, AliReturnPayBean returnPay) throws IOException {
        response.setContentType("type=text/html;charset=UTF-8");
        log.info("支付宝的的回调函数被调用");
        if (!appUtil.checkSign(request)) {
            log.info("验签失败");
            response.getWriter().write("failture");
            return;
        }
        if (returnPay == null) {
            log.info("支付宝的returnPay返回为空");
            response.getWriter().write("success");
            return;
        }
        log.info("支付宝的returnPay" + returnPay.toString());
        //表示支付成功状态下的操作
        if (returnPay.getTrade_status().equals("TRADE_SUCCESS")) {
            log.info("支付宝的支付状态为TRADE_SUCCESS");
            //业务逻辑处理 ,webSocket在下面会有介绍配置
            webSocket.sendMessage("true");
        }
        response.getWriter().write("success");
    }
}

代码解释:

        这就是重要的两个的请求的端口路径,那么在这里还有一个重点

这个参数就是面对面的支付的重要参数,在使用前可以去官网上先确定一下相关的状态码。

特别重点!!!

在这里写的路径call其实就是我们之前提到的!配置文件中没有写的!!同步通知地址!!

在我们写过了这个路径的时候要配置中的回调路径地址写上!!!

同时要注意这个地址一定是外网能够访问的!!如果是在本地的开发环境,那就需要去百度一下内网穿透了,要注意这里的配置,在上线(部署服务器之后!!)要将路径的地址改为对应服务器的ip地址。

前台vue页面!!!!

封装的请求:

import request from '@/utils/request'

export function getpay(data) {
  return request({
    url: '/createQR',
    method: 'post',
    data: data
  })
}

 在main.js导入依赖

下载依赖

npm install vue-qr

导入使用依赖 

import vueQr from 'vue-qr'
Vue.component('vueQr', vueQr)

vue完整页面

<template>
  <div>
    <el-form ref="form" :model="payform" label-width="80px">
      <el-form-item label="商户订单号">
        <el-input v-model="payform.out_trade_no"></el-input>
      </el-form-item>
      <el-form-item label="订单名称">
        <el-input v-model="payform.subject"></el-input>
      </el-form-item>
      <el-form-item label="付款金额">
        <el-input v-model="payform.total_amount"></el-input>
      </el-form-item>
      <el-form-item label="商品描述">
        <el-input v-model="payform.body"></el-input>
      </el-form-item>
      <!-- 支付按钮,模拟支付操作 -->
      <van-button type="primary" @click="pay">支付</van-button>

      <el-dialog :title="paySucc?'支付成功':'扫码支付'" :visible.sync="dialogVisible" width="20%" center>
        <!-- 生成二维码图片 -->
        <vueQr :text="text" :size="200" v-if="!paySucc"></vueQr>
        <!-- 使用websocket监控是否扫描,扫描成功显示成功并退出界面 -->
        <span class="iconfont icon-success" style="position: relative;font-size: 100px;color:#42B983;margin-left: 50px;top:-10px;" v-else></span>
      </el-dialog>
    </el-form>
<!--    <el-dialog-->
<!--      title="提示"-->
<!--      :visible.sync="dialogVisible"-->
<!--      width="80%"-->
<!--      hidden="80%"-->
<!--      :before-close="handleClose">-->

<!--      <span slot="footer" class="dialog-footer">-->
<!--    <el-button @click="dialogVisible = false">取 消</el-button>-->
<!--    <el-button type="primary" @click="dialogVisible = false">确 定</el-button>-->
<!--  </span>-->
<!--    </el-dialog>-->
<!--    <div v-html="this.htmlstr"></div>-->
<!--  </div>-->
  </div>
</template>

<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等),
//例如:import 《组件名称》 from '《组件路径》,
  import { getpay } from '@/api/pay'
  import axios  from 'axios'
  import vueQr from 'vue-qr'
export default {
    //import引入的组件需要注入到对象中才能使用"
    components: {

    },
    props: {},
    data() {
      //这里存放数据"

      return {
        text: "",
        paySucc: false,
        dialogVisible:false,
        payform:{
          out_trade_no:'',
          subject:'',
          total_amount:'',
          body:'',
        },
        htmlstr:''
      };
    },
    //计算属性 类似于data概念",
    computed: {},
    //监控data中的数据变化",
    watch: {},
    //方法集合",
    methods: {
      handleClose(done) {
        this.$confirm('确认关闭?')
          .then(_ => {
            done();
          })
          .catch(_ => {
          });
      },
      paymany() {
        getpay(this.pay).then(
          res => {
            console.log(res)
            this.htmlstr = res.data
            this.dialogVisible = true
          }
        )
      },
      pay() {
        let _this = this;
        _this.paySucc = false;
        _this.dialogVisible = true;
        console.log(this.payform)
        getpay(this.payform).then(
          response=>{
            console.log(response)
            _this.text = response.data;
            _this.dialogVisible = true;
            //使用webSocket发送请求,下面会简单介绍websocket使用
            if ("WebSocket" in window) {
              // 打开一个 web socket
              var ws = new WebSocket("ws://服务器的ip:10001/bindingRecord");

              ws.onopen = function() {
                // Web Socket 已连接上,使用 send() 方法发送数据
                // ws.send("data");
                // alert("数据发送中...");
              };

              ws.onmessage = function(evt) {
                var received_msg = evt.data;
                // alert("数据已接收..." + evt.data);
                if (Boolean(evt.data)) {
                  _this.paySucc = true;
                  setTimeout(() => {
                    _this.dialogVisible = false;
                  }, 3 * 1000);
                }
                ws.close();

              };

              ws.onclose = function() {
                // // 关闭 websocket
                console.log("连接已关闭...");
              };
            } else {
              // 浏览器不支持 WebSocket
              alert("您的浏览器不支持 WebSocket!");
            }
          }).catch((err) => {
          console.log(err)
        })
      },
      back(dataUrl, id) {
        console.log(dataUrl, id)
      }
    },
    //生命周期 - 创建完成(可以访问当前this实例)",
    created() {
      alert("预支付效果演示!请注意本页面所有支付均为支付宝开发沙盒,如果支付了,钱可没到阿丹这里!!!")
      this.axios = axios; // 初始化 axios
    },
    //生命周期 - 挂载完成(可以访问DOM元素)",
    mounted() {
    },
    beforeCreate() {
    }, //生命周期 - 创建之前",
    beforeMount() {
    }, //生命周期 - 挂载之前",
    beforeUpdate() {
    }, //生命周期 - 更新之前",
    updated() {
    }, //生命周期 - 更新之后",
    beforeDestroy() {
    }, //生命周期 - 销毁之前",
    destroyed() {
    }, //生命周期 - 销毁完成",
    activated() {
    } //如果页面有keep-alive缓存功能,这个函数会触发",
  };
</script>
<style scoped>

</style>

注意:

        别忘记配置路由!!!并且我使用的是npm来管理依赖的,一定要注意!!

然后就完成了快自己动手尝试一下吧!!!!!

没看错!return_url就是空着了,大家可以写一个空“”来代替,好了大家快自己尝试一下吧!!!!

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 建议使用以下步骤来编写一个使用playwright-javademo:1. 添加playwright-java的依赖;2. 创建一个playwright实例;3. 选择一个浏览器;4. 创建一个浏览器上下文;5. 在上下文中打开一个新页面;6. 在页面上执你想要做的任务;7. 关闭页面和浏览器上下文;8. 关闭playwright实例。 ### 回答2: Playwright-Java是一款用于自动化测试Web应用的框架,它提供了丰富的API和方法来模拟用户在浏览器中的操作。下面是一个使用Playwright-Java编写的示例代码: ```java import com.microsoft.playwright.*; public class PlaywrightDemo { public static void main(String[] args) { try (Playwright playwright = Playwright.create()) { Browser browser = playwright.chromium().launch(); BrowserContext context = browser.newContext(); Page page = context.newPage(); page.navigate("https://www.example.com/"); page.waitForLoadState(); page.click("a#link"); page.waitForLoadState(); System.out.println("Current Page Title: " + page.title()); String pageTitle = page.evaluate("document.title"); System.out.println("Page Title using JavaScript: " + pageTitle); browser.close(); } } } ``` 在这个示例中,我们首先使用 `Playwright.create()` 来创建一个Playwright实例,然后使用 `playwright.chromium().launch()` 启动一个Chromium浏览器实例。 接下来,我们使用 `browser.newContext()` 创建一个BrowserContext,它可以看作是一个浏览器的实例,然后使用 `context.newPage()` 创建一个Page对象,表示一个具体的浏览器页面。 我们使用 `page.navigate()` 方法加载一个网页,并使用 `page.waitForLoadState()` 等待页面加载完成。然后,我们使用 `page.click()` 方法点击页面上的一个链接,并再次使用 `page.waitForLoadState()` 等待链接页面加载完成。 接下来,我们打印出当前页面的标题,使用 `page.title()` 方法。然后,我们使用 `page.evaluate()` 方法执JavaScript代码,获取页面标题,并打印出来。 最后,我们使用 `browser.close()` 关闭浏览器实例。 这只是Playwright-Java的一个简单示例,它演示了如何使用Playwright-Java来自动化测试一个Web应用。使用Playwright-Java,你可以执更多复杂的操作,如表单交互、页面滚动、鼠标操作等。希望这个示例对你有所帮助。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值