当前位置:   article > 正文

支付宝支付的实现【沙箱】(学习笔记)_支付宝沙箱支付移动端(android原生)

支付宝沙箱支付移动端(android原生)

一、使用所需技术

https://open.alipay.com/

  1. 前端:vue + element-ui + vue-qr + axios
  2. 后端:spring boot
  3. natapp 进行内网穿透
  4. websocket 前端响应

二、沙箱环境准备

前往支付宝开放平台:https://open.alipay.com/
在这里插入图片描述在这里插入图片描述记录好APPID支付宝网关地址
公钥模式点击查看配置应用公钥
点击查看接入文档有详细教程(这里就不展开了)

手机端下载沙箱支付宝
在这里插入图片描述

二、构建spring boot项目

1. 引入依赖

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--AliPay的SDK-->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.15.14.ALL</version>
        </dependency>
        <!-- websocket依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

2.配置类

import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AlipayConfig {
    // 应用ID (填写你自己的)
    public static final String APP_ID = 
    // 商户ID (填写你自己的,但是这里可以忽略)
    public static final String sellerId = 
    // 支付宝网关
    public static final String gateway_url = "https://openapi.alipaydev.com/gateway.do";
    // 商户私钥 (填写你自己的)
    public static final String PRIVATE_KEY = 
    // 支付宝公钥 (填写你自己的)
    public static final String ALIPAY_PUBLIC_KEY = 
    // 签名方式
    public static final String SIGN_TYPE = "RSA2";
    // 字符编码格式
    public static final String CHARSET = "UTF-8";
    //返回格式
    public static final String FORMAT = "json";
    @Bean
    public AlipayClient alipayClient() {
        return new DefaultAlipayClient(gateway_url,APP_ID,PRIVATE_KEY,FORMAT,CHARSET,ALIPAY_PUBLIC_KEY,SIGN_TYPE);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

3.封装回调参数

@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class AlipayBean implements Serializable {
    private static final long serialVersionUID = 8003704888495570429L;
    // 开发者的app_id
    private String app_id;
    // 商户订单号
    private String out_trade_no;
    // 签名
    private String sign;
    // 交易状态
    private String trade_status;
    // 支付宝交易号
    private String trade_no;
    // 交易的金额
    private String total_amount;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

4.控制层(连接支付宝)

@Controller
@Slf4j
public class AliPayController {
    @Autowired
    private WebSocket webSocket;
    @Autowired
    private AlipayClient alipayClient;
    @RequestMapping("/pay")
    @ResponseBody
    public String send(HttpServletResponse httpServletResponse) throws AlipayApiException {
        AlipayTradePrecreateRequest alipayRequest = new AlipayTradePrecreateRequest();
        //该网址需通过外网访问(进行内网穿透或部署在服务器上)
        alipayRequest.setNotifyUrl("");	//这里是要填的,用内网穿透开一次换一次(反正我是这样的)
        alipayRequest.setBizContent("{" +
                "\"out_trade_no\":\"999\"," +
                "\"total_amount\":\"9999\"," +
                "\"subject\":\"测试商品\"," +
                "\"store_id\":\"测试公司\"," +
                "\"timeout_express\":\"90m\"}");	//过期时间
        AlipayTradePrecreateResponse response = alipayClient.execute(alipayRequest);
        String qr = response.getQrCode();
        return qr;		//返回支付宝二维码的地址
    }
    @RequestMapping("/call")
    public void call(HttpServletRequest request, HttpServletResponse response, AlipayBean returnPay) throws IOException {
        response.setContentType("type=text/html;charset=UTF-8");
       String orderNo = returnPay.getOut_trade_no();
       if (("TRADE_SUCCESS").equals(returnPay.getTrade_status())) {
           webSocket.sendMessage("true");
       }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

5.websocket的工具类

别问。问就是复制过来的哈哈哈,想了解可以点我

/**
 * 服务端和客户端双向数据传输
 * 可以监听到后端是否发送信息
 */
@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());
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

三、内网穿透

这里使用的是NATAPP,网址链接:https://natapp.cn/
注册并认证,可以购买2条免费的隧道
在这里插入图片描述下载他的客户端打开

natapp --authtoken=****
  • 1

在这里插入图片描述在这里插入图片描述

四、前端的搭建

1、下载好element-ui、axios、vue-qr

vue install ** -s
  • 1
<template>
	<div>
		<!-- 支付按钮,模拟支付操作 -->
		<van-button type="primary" @click="pay">支付</van-button>

		<el-dialog :title="paySucc?'支付成功':'扫码支付'" :visible.sync="dialogVisible" width="16%" 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>

	</div>
</template>

<script>
	import vueQr from 'vue-qr'
	export default {
		data() {
			return {
				dialogVisible: false,
				text: "",
				paySucc: false
			}
		},
		components: {
			vueQr
		},
		methods: {
			pay() {
				let _this = this;
				_this.paySucc = false;
				_this.dialogVisible = true;
				this.axios.request("http://localhost:8081/pay")
					.then((response) => {
						_this.text = response.data;
						_this.dialogVisible = true;
						//使用webSocket发送请求,下面会简单介绍websocket使用
						if ("WebSocket" in window) {
							// 打开一个 web socket
							var ws = new WebSocket("ws://localhost:8081/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)
			}
		}
	}
</script>

<style>
	.btn {
		margin-left: 100px;
	}
</style>


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/186206
推荐阅读
相关标签
  

闽ICP备14008679号