Spring boot整合支付宝沙盒

1.这里没有介绍对支付宝沙盒的密钥和公钥的配置,如没配置请先配置后在看此博客, 有很多不足之处,请多多包涵


2.我使用的是扫码支付,也是就是生成二维码,当然不止有这个, 还有另外几种的支付能力,如:网站的,app的, 我使用的是当面付时创建二维码

3.SDK我使用的是alipay-easysdk

alipay-easysdk文档: https://github.com/alipay/alipay-easysdk/blob/066388d02c6f55fe0919d75b386456d80801fec2/APIDoc.md

4.开发工具IDEA, jdk1.8, 和一个内网穿透工具natapp

5.前端使用的是vue, 利用webscoket来传输支付是否完成

好了这就是基本的介绍,结果图如下:



让我们开始实现这个功能吧! 这里省略了spring boot的搭建,直接进入maven依赖的导入

配置

1.pom.xml依赖的导入

<!--支付宝沙盒的依赖--><dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-easysdk</artifactId><version>2.2.0</version></dependency><!-- 二维码zxing --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.4.0</version></dependency><dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.4.0</version></dependency><!--  WebSocekt--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.7</version></dependency>

一些spring boot的依赖就省略了, 这里就贴出了生成二维码的,和支付宝沙盒sdk. websoket

2.application.yml 支付宝的配置

alipay:#商户IDappId:#自己的支付宝私钥privateKey:#自己的公钥publicKey:#支付宝网关gateway: openapi.alipaydev.com#支付完成后需要返回的url映射地址returnUrl:#异步支付通知notifyUrl:

3.支付宝的初始配置类

他主要的作用是读取application.yml文件中关于alipay的属性值, 实现了ApplicationRunner接口方法

@Component
public class 你的类名 implements ApplicationRunner {//应用id@Value("${alipay.appId}")private String appId;//私钥@Value("${alipay.privateKey}")private String privateKey;//公钥@Value("${alipay.publicKey}")private String publicKey;//支付宝的网关@Value("${alipay.gateway}")private String gateway;//支付成功后的接口回调地址@Value("${alipay.notifyUrl}")private String notifyUrl;/*** Spring boot项目启动时初始化支付宝沙盒配置** @param args* @throws Exception*/@Overridepublic void run(ApplicationArguments args) throws Exception {Factory.setOptions(getOptions());System.out.println("********支付宝SDK初始化完成!******");}public Config getOptions() {Config config = new Config();config.protocol = "https";config.gatewayHost = this.gateway;config.signType = "RSA2";//支付宝config.appId = this.appId;config.merchantPrivateKey = this.privateKey;config.alipayPublicKey = this.publicKey;config.notifyUrl = notifyUrl;return config;}
}

到这里代表你的支付宝已经配置差不多了, 运行spring boot时会在终端出现********支付宝SDK初始化完成!******就代表没问题了

支付能力Payment

我使用的是alipay-easysdk,他的官方文档写的也很清楚:https://github.com/alipay/alipay-easysdk/blob/066388d02c6f55fe0919d75b386456d80801fec2/APIDoc.md, 可参考Payment章节

我主要介绍的是交易预创建,生成正扫二维吗,如下表格

  • API声明

precreate(subject: string, outTradeNo: string, totalAmount: string)

  • 入参:
字段名 类型 必填 说明
subject string 订单标题
outTradeNo string 交易创建时传入的商户订单号
totalAmount string 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
  • 出参

    我们只需要要拿到qrcode这个参数, 这是生成二维码的主要数据

    其他详细出参请参考:https://opendocs.alipay.com/apis/api_1/alipay.trade.precreate

支付能力就介绍完了, 下面就是实现了

创建一个类,用于支付宝的支付业务层的实现

@Service
public class PayService {@Autowired//订单编号生成的工具类private UtilsCode utilsCode;public String payQr(Order1 order, String userId) throws Exception {String serialNumaber = utilsCode.orderUUID();Integer number = order.getNumber();Integer goodsId = order.getGoodsId();//重点异步:  使用的notify接口    在natapp上拿到链接, 到这上面, 支付完记得看终端 200正常//  userId 因为webscoket需要获得到用户的session才能发送消息, //number 是商品数量 goodsId 是商品id, 用于修改 数据库中的数据, 可以根据自己的需求进行修改String notify = "http://qjaxf4.natappfree.cc/back/v1/"+notify?userId="+userId+"&number="+number+"&goodsId="+goodsId;AlipayTradePrecreateResponse response = Factory.Payment.FaceToFace()//异步, 用于查看是否支付成功.asyncNotify(notify)/*  标题           订单号,          订单金额string 类型        */.preCreate("标题, 可以随便写", serialNumaber, String.valueOf(order.getMoney()));//这是我们需要拿到的数据return response.getQrCode();}/* 测试public String payQr() throws Exception {String serialNumaber = utilsCode.orderUUID();//重点异步:      在natapp上拿到链接, 到这上面, 支付完记得看终端 200正常//  userId 因为webscoket需要获得到用户的session才能发送消息, String notify = "http://qjaxf4.natappfree.cc/back/v1/notify?userId="+userId+"&number="+number+"&goodsId="+goodsId;AlipayTradePrecreateResponse response = Factory.Payment.FaceToFace()//异步, 用于查看是否支付成功.asyncNotify(notify).preCreate("标题, 可以随便写", serialNumaber, "123");//这是我们需要拿到的数据return response.getQrCode();}*/}@Component
public class UtilsCode {//生成唯一订单号public String orderUUID() {//生成8位数的随机数   import org.apache.commons.lang3.RandomStringUtils;String randomString = RandomStringUtils.randomNumeric(8);String orderIdStr = "wch-" + datestr() + "-" + randomString;//返回完整的字符串return orderIdStr;}
}

编写前端控制器

  /*** 支付宝沙盒接口的调用,生成二维码*/@Autowiredprivate PayService payService;//produces = MediaType.IMAGE_JPEG_VALUE必须加上去@PostMapping(value="pay",  produces = MediaType.IMAGE_JPEG_VALUE)/*如果你想测试,可以把方法里的参数给去掉, 对应的你调用的方法也可以去掉如public BufferedImage  pay() throws Exception {String result = this.payService.payQr();BufferedImage bufferedImage = QrCodeUtils.createQr(result);return bufferedImage;}*/public BufferedImage  pay(@RequestBody Order1 order, String userId) throws Exception {String result = this.payService.payQr(order, userId);BufferedImage bufferedImage = QrCodeUtils.createQr(result);return bufferedImage;}/*** 生成BuffereImage, 加载配置类* @return*/@Beanpublic BufferedImageHttpMessageConverter addConverter(){return new BufferedImageHttpMessageConverter();}//异步,支付是否成功@Autowiredprivate WebScoketAlipay webScoketAlipay;/*** 异步通知处理*/@PostMapping("/notify")public void asyncNotify(@RequestBody String notifyData, String userId, /*可根据自己的需求删掉*/String goodsId,String number) throws IOException {if (notifyData != null) {webScoketAlipay.sendMessageToFinduserId("支付成功", userId);//如测试下面可以不用, 可根据自己的需求Slideshow slideshow = new Slideshow();slideshow.setShowDay(Integer.parseInt(number));slideshow.setImgId(Integer.parseInt(goodsId));this.slideshowService.topUpSildeShow(slideshow);}}

二维码的生成

需要使用到zxing这个sdk, 直接上关键代码, 如需要图片请自行百度

public class QrCodeUtils {private static final String CHARSET = "utf-8";public static final String FORMAT = "JPG";// 二维码尺寸private static final int QRCODE_SIZE = 350;// LOGO宽度private static final int LOGO_WIDTH = 60;// LOGO高度private static final int LOGO_HEIGHT = 60;public static BufferedImage createQr(String contenxt) {BufferedImage img = null;try {BitMatrix bitMatrix = new MultiFormatWriter().encode(contenxt, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE);img=   MatrixToImageWriter.toBufferedImage(bitMatrix);} catch (WriterException e) {e.printStackTrace();}return img;}
}

好了这样就完成一半了, 可以用postman测试下,你就会发现生成的二维码图片了, 下面就是我们的前端了

webscoket的配置与使用

配置

@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

使用

@Component
@ServerEndpoint("/notfiyPay/{id}")
public class WebScoketAlipay {private static int onlineCount = 0;/*** concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。*/private static ConcurrentHashMap<String, WebScoketAlipay> webSocketMap = new ConcurrentHashMap<>();/*** 与某个客户端的连接会话,需要通过它来给客户端发送数据*/private Session session;/*** 接收userId*/private String id = "";/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("id") String id) {this.session = session;this.id = id;//从map数据中取出key,判断是否存在if (webSocketMap.containsKey(id)) {//不能够二次登录webSocketMap.remove(id);webSocketMap.put(id, this);} else {webSocketMap.put(id, this);//加入set中addOnlineCount();//在线数加1}System.out.println("用户连接:" + id + ",当前在线人数为:" + getOnlineCount());//sendMessage("连接成功");}/*** 连接关闭调用的方法*/@OnClosepublic void onClose() {if (webSocketMap.containsKey(id)) {webSocketMap.remove(id);//从set中删除subOnlineCount();}System.out.println("用户退出:" + id + ",当前在线人数为:" + getOnlineCount());}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) {System.out.println("用户消息:" + this.id + ",报文:" + message);//可以群发消息//消息保存到数据库、redisif (StringUtils.isNotBlank(message)) {try {//解析发送的报文JSONObject jsonObject = JSON.parseObject(message);//追加发送人(防止串改)jsonObject.put("fromUserId", this.id);String toUserId = jsonObject.getString("toUserId");String text = jsonObject.getString("contentText");//判断发送方是否在线if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {//发送消息webSocketMap.get(toUserId).sendMessage(text);} else {System.out.println("请求的userId:" + toUserId + "不在该服务器上");//否则不在这个服务器上,发送到mysql或者redis}} catch (Exception e) {e.printStackTrace();}}}/*** @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {System.out.println("用户错误:" + this.id + ",原因:" + error.getMessage());error.printStackTrace();}/*** 实现服务器主动推送*/public void sendMessageToFinduserId(String message, String userId) {try {//websocket session发送文本消息方法:getAsyncRemote()
//            for(WebScoketAlipay map: webSocketMap.values()){//                map.session.getAsyncRemote().sendText(message);
//            }webSocketMap.get(userId).session.getAsyncRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}public void sendMessage(String message){try {this.session.getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {++WebScoketAlipay.onlineCount;}public static synchronized void subOnlineCount() {WebScoketAlipay.onlineCount--;}
}

好了,后端基本就已经完成了

前端vue界面

<template><el-dialog title="续费" :visible.sync="open" width="500px" @close="closeDialog()"  :close-on-click-modal="false"><el-form ref="form" :model="order" label-width="80px"><div  style="display: flex"><div style="border-right: 1px dashed #D5D7D9"><el-form-item label="商家名称:" style="width: 220px; font-size: 16px;"><span>{{edit.shopName}}</span></el-form-item><el-form-item label="剩余时间:"><span>{{edit.remain}}</span></el-form-item><el-form-item label="使用情况"><span>{{edit.imgCase}}</span></el-form-item></div><div><el-form-item label="审批进度:"><span>{{edit.useImg}}</span></el-form-item><el-form-item label="结束时间"><span style="">{{edit.imgData}}</span></el-form-item><el-form-item label="广告图片:"><img v-if="edit.homeImg" :src="edit.homeImg" style="width:130px; height: 70px;"></el-form-item></div></div><!-- 重点看这些    --><el-form-item label="天数充值"><el-input-number v-model="order.number"controls-position="right" :min="0" :max="1860" style="width: 370px"></el-input-number><el-radio-group v-model="order.number"><el-radio-button :label="31">1个月</el-radio-button><el-radio-button :label="62">2个月</el-radio-button><el-radio-button :label="93">3个月</el-radio-button><el-radio-button :label="124">4个月</el-radio-button><el-radio-button :label="372">1年</el-radio-button></el-radio-group></el-form-item><el-form-item label="支付方式"><el-radio-group v-model="radio"><el-radio :label="1" @change="wallet('form')">余额</el-radio><el-radio :label="2" @change="alipay()">支付宝支付</el-radio><el-radio :label="3" @change="wechat()">微信支付(功能待开发)</el-radio></el-radio-group></el-form-item><el-form-item v-if="payUrl != ''" label="扫码支付"><img  :src="payUrl" style="width:120px; height: 120px;"><span style="color: red">总计需支付{{order.money}}(元)</span></el-form-item></el-form></el-dialog>
</template><script>
export default {name: "topUp",data(){return{ edit: {imgId: "",homeImg: "",imgUrl: "",shopId: "",useImg: "",ImgCase: "",showDay: "",remain: ""    },// 表单参数 edit可以删掉order:{title: "",goodsId:"",number: 1,   //数量       money: "",   //总计多少元price: 0.5},payUrl: "",radio: 0,// 是否显示弹出层open: false,}},methods:{// 窗口初始化方法,nextTick方法可以添加逻辑,如打开窗口时查询数据填充init(id){this.$nextTick(() => {let vm = thisthis.$post(vm.API.API_URL_FINDBYIDSLIDESHOW+id).then(res =>{if(res.errorCode == 0){vm.edit = res.datavm.edit.showDay = 0vm.edit.homeImg =  vm.API.BASE_SERVER_URL + res.data.homeImg}})this.open = true})},//系统余额钱包支付wallet(form){this.payUrl = ''},//支付宝支付 重点alipay(){let vm = thisthis.order.goodsId = this.edit.imgIdthis.order.title = this.edit.shopNamethis.order.money = this.order.number * this.order.price //id根据自己系统啊!!!!  测试的话记得随便写个值let id =  JSON.parse(window.sessionStorage.getItem('accese-usename')).userIdconsole.log(id)//请求后端   返回图片   {responseType: 'arraybuffer'}参数必须要axios.post("http://localhost:4099/back/v1/pay?userId="+id, vm.order,{responseType: 'arraybuffer'}).then(res =>{//将图片以base64显示let bytes = new Uint8Array(res.data);let data = "";let len = bytes.byteLength;for (let i = 0; i < len; i++) {data += String.fromCharCode(bytes[i]);}vm.payUrl = "data:image/jpg;base64," + window.btoa(data);})this.initWebSocket(id) },//关闭对话框清除数closeDialog(){this.edit = this.$options.data().editthis.order = this.$options.data().orderthis.payUrl = ''this.radio = 0},//websocket和axiose的轮询 来查看支付信息是否成功initWebSocket(id){if(typeof WebSocket == "undefined"){alert("浏览器不支持WebSocket")//如浏览器不支持}else{//填自己的webscoket地址let socketUrl = "http://localhost:4099/notfiyPay/"+id;socketUrl = socketUrl.replace("https", "ws").replace("http", "ws");this.websocket = new WebSocket(socketUrl);this.websocket.onopen = this.websocketonopen;this.websocket.onerror = this.websocketonerror;this.websocket.onmessage = this.websocketonmessage;this.websocket.onclose = this.websocketclose();}},websocketonopen(){console.log("连接成功")},websocketonerror(e){console.log("连接发生错误")},websocketonmessage(e){this.$notify({title: "消息",message: e.data})if(e.data == "支付成功"){this.open = falsethis.payUrl = ''//支付成功关闭websocket,this.websocket.close()}},websocketclose(){console.log("连接关闭")}}}
</script>
<style  scoped>
.el-form-item {margin: 1px;
}
</style>

spring boot支付宝沙盒扫二维码支付相关推荐

  1. 微信支付宝合并为一个二维码支付的实现

    背景说明 我们是一个位于三线城市的购物中心,虽然已经开业多年,但是受益于良好的招商和日常运营,客流量在同城同类型项目中一直比较稳定.在节假日出场车流高峰期的时候,由于人工收费的效率问题,会导致车辆积压 ...

  2. ASP.NET MVC 支付宝当面付(沙箱环境)-即扫二维码支付1(填坑)

    1,环境 我用的是 vs2017    创建一个 mvc项目  新建一个文件夹将 SDK 文件放进去 sdk地址 :https://support.open.alipay.com/docs/doc.h ...

  3. Spring Boot项目使用Graphics2D 生成二维码海报图片流返回给前端

    这里写自定义目录标题 前言 生成图片最后效果(省略公司logo) 代码 开发中遇到的坑 1.通过Postman能够获取出海报图片,但是前端获取是获取不到 前言 需求是生成二维码分享海报,作为学生加入班 ...

  4. 央行叫停支付宝虚拟信用卡及二维码支付

    3月14日上午消息,央行下发紧急文件叫停支付宝.腾讯的虚拟信用卡产品,同时叫停的还有条码(二维码)支付等面对面支付服务. 央行通知表示,线下条码(二维码)支付突破了传统手艺终端的业务模式,其风险控制水 ...

  5. Java 支付宝当面付生成二维码支付实现

    参考官方APIalipay.trade.precreate(统一收单线下交易预创建) maven依赖: <!-- 支付宝支付sdk --><dependency><gro ...

  6. 支付宝当面付(扫二维码)

    //沙箱版客户扫二维码支付public String test_trade_pay(Map<String, Object> map){AlipayClient alipayClient = ...

  7. 银联二维码支付与微信支付相比,哪个好用?

    2019独角兽企业重金招聘Python工程师标准>>> 近日,中国银联联合40多家商业银行正式推出了二维码支付产品.扫码支付你应该早就不陌生了.现在即使是摆在街边的水果摊也有二维码让 ...

  8. 梦行扫码付(收银台条码支付 微信钱包条码支付 支付宝二维码支付 手机APP钱包支付 PHP扫码支付 )

    适用于:各行各业(如,超市 餐厅 收费站 等各类收费处) 平台管理员篇 扫码付管理 (收银台条码支付) 全站收款账号 (微信钱包条码支付) 全站收款记录 (支付宝二维码支付) 商家篇 我的扫码付 (支 ...

  9. 2021年春节过年支付宝集福神器,支付宝额外福卡二维码扫福器

    下载地址:https://www.lanzoui.com/b01br9o6j 2021年春节过年支付宝集福神器,支付宝额外福卡二维码扫福器,一年一度的集福工具又来啦! 如有杀毒软件误报,请添加信任即可 ...

最新文章

  1. vconsole插件_手机前端开发调试利器 – vConsole
  2. mysql innodb myisam 插入数据_mysql innodb换成myisam后插入数据变快?
  3. redis 3.x windows 集群搭建
  4. PHP算法数组横置处理代码优化
  5. java collator_Java Collator compare(String, String)用法及代码示例
  6. 小程序开发之图片转Base64(C#、.Net)
  7. 解决WebGL加载倾斜摄影模型出现An eror occurred while rendering.Rendering has stopped.问题
  8. AI未来 - 李开复 - 未来8成的工作受影响 - 读后感
  9. Android 创建服务器 NanoHttpd
  10. ffmpeg水平翻转视频,附批量处理脚本
  11. Tutorial 05: Synching Video
  12. Unity 横向滚动ScrollView
  13. 视觉SLAM——特征点法与直接法对比以及主流开源方案对比 ORB LSD SVO DSO
  14. Metamask不能访问以太坊账户?隐私模式!
  15. 移动网站性能优化:网页加载技术概览
  16. 偏向锁、轻量锁、重量锁的理解
  17. Unity协程实现场景中鼠标按住的物体跟随鼠标移动
  18. 获得任意风格的图片效果?深度学习算法一键P图!
  19. 关于1998年,2008年的全球/东南亚-金融/经济危机的10年魔咒反思
  20. 工作四年的数据分析师的解惑-数据分析师的日常、晋升通道。

热门文章

  1. 被动式pocscan扫描神器搭建
  2. D-MNSV6-X8|D-MNSV7-X16磁导航传感器RS232/RS485(MODBUS-RTU)通讯协议说明
  3. PyTorch中文文档阅读笔记-day1
  4. Python四大主流网络编程框架
  5. c语言编程读取bmp文件数据,c语言读取BMP图片的RGB数据
  6. 「自然语言处理(NLP)论文解读」中文命名实体识别(Lattice-LSTM模型优化)
  7. 数据结构:树与二叉树(一) 树的基本知识
  8. 最新kali之netsniff-ng
  9. ActiveX 控件打包
  10. 04741自考计算机网络原理最详细汇总