苍穹外卖项目解读(四) 微信小程序支付、定时任务、WebSocket

前言

HM新出springboot入门项目《苍穹外卖》,笔者打算写一个系列学习笔记,“苍穹外卖项目解读”,内容主要从HM课程,自己实践,以及踩坑填坑出发,以技术,经验为主,记录学习,也希望能给在学想学的小伙伴一个参考。

注:本文章是直接拿到项目的最终代码,然后从代码出发,快速逆向学习技术经验! 可能需要一些前置知识

觉得文章有用可以关注点赞收藏期待更新^^,期待您的评论留言

苍穹外卖项目解读(一) 完整代码本地部署运行
苍穹外卖项目解读(二) 管理端JWT令牌、AOP注解开发、分页
苍穹外卖项目解读(三) redis、cache缓存解读
苍穹外卖项目解读(四) 微信小程序支付、定时任务、WebSocket

在这里插入图片描述

微信小程序支付

微信小程序开发

1、微信小程序开发需要到微信小程序服务平台注册,分为个人、企业、媒体、政府等,提供需要的注册文件即可。不同的注册主体所获得的开发权限有所不同:个人版就无法使用微信支付功能

2、注册完成之后,对于后端开发来说,我们需要在开发管理中获取所注册小程序ID:AppID、小程序秘钥:AppSecret。对应Java配置文件中:

wechat:appid: wxffb3637a228223b8secret: 84311df9199ecacdf4f12d27b6b9522d

3、微信开发者工具,前端交互开发工具,请大家自行探索^^

4、小程序发布上线,在微信开发者工具中,上传按钮到微信服务器(此时为开发版本),在小程序网页管理端,找到上传的版本小程序,提交审核(审核版本),审核通过之后,即可发布(线上版本)

微信支付

1、已经进行了企业小程序的注册,在微信支付的商户平台接入微信支付,提交资料、签署协议、绑定场景(小程序支付,网页扫码支付,app调用支付等)。(一般开发人员不接触,都是企业注册完成之后拿到后续开发所需要的信息)

微信小程序的支付流程笔者在这里结合日常举例(现金)

我去水果店买东西,挑了一个大西瓜,给老板称重算价格(下单,图例123)。我告诉管着钱的女友买的啥,在哪买的,多大的西瓜,总共花了多少钱并向她要钱(申请微信下单接口,图例456)。女友看了看西瓜跟老板议论这瓜保熟吗xxx(密文,图例78)。我说买了吧,大夏天好热吃个瓜爽歪歪(确定支付 图例9)。女友给老板钱,老板给我西瓜我提着(支付结果,图例10 11 12)。女友走时跟老板说“这瓜保熟,瓜甜的话还来买”(回调,图例13 14)
其中我就是用户,老板水果店是商户,管钱的女友是微信后台
在程序中需要注意的点:
1、向她要钱(申请微信下单接口):准备好参数,去主动请求微信后台(生成预支付交易单)
2、跟老板议论这瓜保熟吗xxx(密文):告诉用户加密好了一些内容,供用户去确定支付
3、吃个瓜爽歪歪(确定支付):真正给钱,微信后台支付
4、回调:指明回调地址,得到结果信息

在这里插入图片描述
5调用微信下单接口 请求图
在这里插入图片描述
9用户确定支付请求图(参数来自7、8封装)
在这里插入图片描述
更多开发细节可关注文档中心

------配置项解析------wechat:appid: wxffb3637a228223b8  小程序idsecret: 84311df9199ecacdf4f12d27b6b9522d  小程序秘钥mchid : 1561414331  商户号mchSerialNo: 4B3B3DC35414AD50B1B755BAF8DE9CC7CF407606  构造请求客户端build使用 WechatPayHttpClientBuilderprivateKeyFilePath: D:\pay\apiclient_key.pem  商户私钥文件apiV3Key: CZBK51236435wxpay435434323FFDuv3  解密回调内容的keyweChatPayCertFilePath: D:\pay\wechatpay_166D96F876F45C7D07CE98952A96EC980368ACFC.pem  平台证书文件notifyUrl: https://58869fb.r2.cpolar.top/notify/paySuccess  回调地址公网iprefundNotifyUrl: https://58869fb.r2.cpolar.top/notify/refundSuccess  回调地址

定时任务

spring对定时调度的开发又很友好的开发方式,即启动类上@EnableScheduling,在定时任务上使用@Scheduled,并搭配cron表达式。下面从源码解析spring是如何进行定时调度的。

@EnableScheduling

1、ScheduledAnnotationBeanPostProcessor

其中postProcessAfterInitialization方法中,主要对标注@Scheduled和聚合注解@Schedules的类成员方法进行处理,主要分为2步:
1)识别标注@Scheduled和聚合注解@Schedules的方法;
2)对注解方法调用processScheduled方法进行处理;

2、processScheduled处理过程如下

1)将调用目标方法的过程包装为ScheduledMethodRunnable类
2)构造CronTask并进行调度
3)构造FixedDelayTask并进行调度
4)构造FixedRateTask并进行调度

3、调度框架支持的Task类型
在这里插入图片描述

Spring调度框架中重要支持3种调度任务类型(继承结构如上图),具体说明如下:
1)CronTask:cron表达式调度的任务
2)FixedDelayTask:固定延迟时间执行的任务
3)FixedRateTask:固定速率执行的任务

4、3种的调度执行实现近似,以常用的cron为例

	@Nullablepublic ScheduledTask scheduleCronTask(CronTask task) {ScheduledTask scheduledTask = this.unresolvedTasks.remove(task);boolean newTask = false;if (scheduledTask == null) {scheduledTask = new ScheduledTask(task);newTask = true;}if (this.taskScheduler != null) {scheduledTask.future = this.taskScheduler.schedule(task.getRunnable(), task.getTrigger());}else {addCronTask(task);this.unresolvedTasks.put(task, scheduledTask);}return (newTask ? scheduledTask : null);}

1)将调度任务包装为ScheduledTask类型,其中封装了执行结果ScheduledFuture
2)存在任务调度器(taskScheduler)时,直接进行调度执行.
3)不存在任务调度器(taskScheduler)时,将任务暂存到addCronTask中,待调用afterPropertiesSet方法时再进行调度执行

5、任务调度器支持自定义,当无自定义调度器时,调度框架提供了默认的任务调度器;
自定义任务调度器的处理逻辑在方法finishRegistration中

上述获取任务调度器的优先级顺序为:
1)当Bean后处理器中定义了任务调度器时,优先取Bean后处理器的任务调度器
2)在BeanFactory中获取Bean类型为SchedulingConfigurer的实例,在其方法configureTasks中可以自定义任务调度器
3)获取BeanFactory中TaskScheduler类型的bean(如有)
4)获取BeanFactory中ScheduledExecutorService类型的bean(如有)
5)当上述方式获取的任务调度器都不存在时,会使用框架中默认的任务调度器,如下:

		if (this.taskScheduler == null) {this.localExecutor = Executors.newSingleThreadScheduledExecutor();this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);}

6、框架内提供的任务调度器

框架内提供的任务调度器主要包括:

1)ConcurrentTaskScheduler

2)ThreadPoolTaskScheduler
继承结构如下:
在这里插入图片描述
以上述框架默认的ConcurrentTaskScheduler进行说明,在调用调度器方法scheduleWithFixedDelay执行时,具体执行逻辑为:

public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {try {if (this.enterpriseConcurrentScheduler) {//默认falsereturn new EnterpriseConcurrentTriggerScheduler().schedule(decorateTask(task, true), trigger);}else {ErrorHandler errorHandler =(this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true));return new ReschedulingRunnable(task, trigger, this.clock, this.scheduledExecutor, errorHandler).schedule();}}catch (RejectedExecutionException ex) {throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);}}

这里主要包含2部分:
1)首先把task任务包装为DelegatingErrorHandlingRunnable类型(支持嵌入错误处理器逻辑),具体是在方法decorateTask中实现
2)调用线程池方法ReschedulingRunnable().schedule()进行调度执行this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS);

@Scheduled

fixedDealy

在上一次调用结束和下一次调用开始之间的固定时间内执行注释方法。时间单位默认为毫秒,但可以通过 timeUnit 重载。

fixedRate

以固定的调用间隔执行注释方法。时间单位默认为毫秒,但可以通过 timeUnit.Me 方法重载。

cron表达式

包括秒、分、时、月、月日和星期的触发器。
例如,"0 * * * MON-FRI “表示在工作日每分钟触发一次(在分钟的顶部,即第 0 秒)。
从左到右读取的字段解释如下。
秒 分钟 小时 日 月 星期
特殊值”-"表示禁用 cron 触发器,主要用于由 ${…} 占位符解析的外部指定值。

WebSocket

WebSocket 是一种支持双向通讯网络通信协议。
意思就是服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息
属于服务器推送技术的一种.

特点:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据(blob对象或Arraybuffer对象)

(5)收到的数据类型 可以使用binaryType 指定, 显式指定收到的二进制数据类型

(6)没有同源限制,客户端可以与任意服务器通信。

(7)协议标识符是ws(握手http)(如果加密,则为wss(tcp +TLS)),服务器网址就是 URL。

WebSocket对象
WebSocket对象提供了用于创建和管理WebSocket 连接,以及可以通过该连接发送和接收数据的 API。

使用 WebSocket() 构造函数来构造一个 WebSocket 。

前后端都需要实现websocket的open close message方法

@Component
@ServerEndpoint("/ws/{sid}") //此处类似controller的方式,由前端访问到
public class WebSocketServer {//存放会话对象 建立websocket连接的对象,此处的Session为websocke包下private static Map<String, Session> sessionMap = new HashMap();/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("sid") String sid) {System.out.println("客户端:" + sid + "建立连接");sessionMap.put(sid, session);}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, @PathParam("sid") String sid) {System.out.println("收到来自客户端:" + sid + "的信息:" + message);}/*** 连接关闭调用的方法** @param sid*/@OnClosepublic void onClose(@PathParam("sid") String sid) {System.out.println("连接断开:" + sid);sessionMap.remove(sid);}/*** 群发** @param message*/public void sendToAllClient(String message) {Collection<Session> sessions = sessionMap.values();for (Session session : sessions) {try {//服务器向客户端发送消息session.getBasicRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}}
<script type="text/javascript">var websocket = null;var clientId = Math.random().toString(36).substr(2);//判断当前浏览器是否支持WebSocketif('WebSocket' in window){//连接WebSocket节点 建立服务端连接websocket = new WebSocket("ws://localhost:8080/ws/"+clientId); }else{alert('Not support websocket')}//连接发生错误的回调方法websocket.onerror = function(){setMessageInnerHTML("error");};//连接成功建立的回调方法websocket.onopen = function(){setMessageInnerHTML("连接成功");}//接收到消息的回调方法websocket.onmessage = function(event){setMessageInnerHTML(event.data);}//连接关闭的回调方法websocket.onclose = function(){setMessageInnerHTML("close");}//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function(){websocket.close();}//将消息显示在网页上function setMessageInnerHTML(innerHTML){document.getElementById('message').innerHTML += innerHTML + '<br/>';}//发送消息function send(){var message = document.getElementById('text').value;websocket.send(message);}//关闭连接function closeWebSocket() {websocket.close();}
</script>

reference:
https://blog.csdn.net/supzhili/article/details/131324690
https://baijiahao.baidu.com/s?id=1706643919026404240&wfr=spider&for=pc

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/30477.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习基础知识扫盲

深度学习 监督学习&#xff08;Supervised learning&#xff09;监督学习分类 无监督学习&#xff08;Non-supervised learning&#xff09;无监督学习的算法无监督学习使用场景 术语特征值特征向量特征工程&#xff08;Feature engineering&#xff09;特征缩放Sigmod functio…

大学生创业运营校园跑腿小程序怎么样?

校园跑腿小程序是一种基于移动互联网的服务平台&#xff0c;旨在为大学生提供便捷的跑腿服务。它可以连接大学生用户和需要代办事务的人群&#xff0c;实现多方共赢的局面。接下来&#xff0c;我将从需求背景、市场前景、功能特点等方面进行分析。 首先&#xff0c;校园跑腿小程…

使用mybatis-plus的updateById方法更新一个numeric(1)类型字段,sql成功执行,但是updates为0,更新失败的解决办法

使用mybatis-plus的updateById方法更新一个numeric(1)类型字段&#xff0c;sql成功执行&#xff0c;但是updates为0&#xff0c;更新失败的解决办法&#xff1a; 背景&#xff1a;我有一张表&#xff0c;有个启用禁用功能&#xff0c;没有放在编辑页面一起编辑保存&#xff0c;…

最强自动化测试框架Playwright-操作指南(3)-PO模式

playwright支持PO模式 创建页面对象 class SearchPage:def __init__(self, page):self.page pageself.search_term_input page.get_by_role("searchbox", name"输入搜索词")def navigate(self):self.page.goto("https://bing.com")def searc…

MySQL5.7数据库、Navicat Premium1.6可视化工具安装教程【详细教程】

文章目录 一、MySQL、Navicat、注册机地址二、安装&#xff08;一&#xff09;、MySQL安装&#xff08;二&#xff09;、Navicat Premium安装&#xff08;三&#xff09;、集活Navicat Premium 三、遇到的问题1、Are you sure your navicat has not beenpatched/modified befor…

【高频面试题】微服务篇

文章目录 Spring Cloud1.Spring Cloud 5大组件有哪些&#xff1f;2.服务注册和发现是什么意思&#xff1f;Spring Cloud 如何实现服务注册发现&#xff1f;3.负载均衡如何实现的 ?4.什么是服务雪崩&#xff0c;怎么解决这个问题&#xff1f;5.微服务是怎么监控的 业务相关6.项…

Nginx安装以及LVS-DR集群搭建

Nginx安装 1.环境准备 yum insatall -y make gcc gcc-c pcre-devel #pcre-devel -- pcre库 #安装openssl-devel yum install -y openssl-devel 2.tar安装包 3.解压软件包并创建软连接 tar -xf nginx-1.22.0.tar.gz -C /usr/local/ ln -s /usr/local/nginx-1.22.0/ /usr/local…

数组对象去重的几种方法

场景&#xff1a; let arrObj [{ name: "小红", id: 1 },{ name: "小橙", id: 1 },{ name: "小黄", id: 4 },{ name: "小绿", id: 3 },{ name: "小青", id: 1 },{ name: "小蓝", id: 4 } ]; 方法一&#xff1a;…

【React学习】—函数式组件(四)

【React学习】—函数式组件&#xff08;四&#xff09; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><ti…

HECI-Securtiy 防火墙路由技术

目录 一、防火墙路由基本原理 1.路由分类 2.路由优先级 3.路由查询先后顺序 4.静态路由基本原理 &#xff08;1&#xff09;指定出接口场景 &#xff08;2&#xff09;指定下一跳地址场景 5.静态路由与多出口 &#xff08;1&#xff09;主备备份 &#xff08;2&#…

robotframework+selenium 进行webui页面自动化测试

robotframework其实就是一个自动化的框架&#xff0c;想要进行什么样的自动化测试&#xff0c;就需要在这框架上添加相应的库文件&#xff0c;而用于webui页面自动化测试的就是selenium库. 关于robotframework框架的搭建我这里就不说了&#xff0c;今天就给大家根据一个登录的实…

OBS视频视频人物实时扣图方法(四种方式)

图片擦除一些杂乱图像 参考&#xff1a;https://www.bilibili.com/video/BV1va411G7be https://github.com/Sanster/lama-cleaner第一种&#xff1a;色度键选项 第二种&#xff1a;浏览器建立窗口选项 参考视频&#xff1a;https://www.bilibili.com/video/BV1WS4y1C7QY http…

【SpringBoot框架篇】33.优雅集成i18n实现国际化信息返回

文章目录 1.简介2.MessageSource配置和工具类封装2.1.配置MessageSource相关配置2.2.配置工具类2.3.测试返回国际级文本信息 3.不优雅的web调用示例(看看就行&#xff0c;别用)4.优雅使用示例4.1.错误响应消息枚举类4.2.ThreadLocal工具类配置4.2.1.ThreadLocal工具类数据封装4…

(四)Node.js - npm与包

1. 什么是包 Node.js中的第三方模块又叫做包。 不同于Node.js中的内置模块与自定义模块&#xff0c;包是由第三方个人或团队开发出来的&#xff0c;免费供所有人使用。 由于Node.js的内置模块进提供了一些底层的API&#xff0c;导致在基于内置模块进行项目开发时&#xff0c…

USB(二):Type-C

一、引脚定义 Type-C口有 4对TX/RX差分线&#xff0c;2对USB D/D-&#xff0c;1对SBU&#xff0c;2个CC&#xff0c;4个VBUS和4个地线Type-C母座视图&#xff1a; Type-C公头视图&#xff1a; 二、关键名词 DFP(Downstream Facing Port)&#xff1a; 下行端口&#xff0c…

Direct path read LOB

Table full scan &#xff1a; wait event Direct path read because of LOB "Direct path read" Wait Event During LOB Access (Doc ID 2287482.1)​编辑To Bottom In this Document Symptoms Changes Cause Solution References APPLIES TO: Oracle Database …

win11虚拟机安装

win11虚拟机安装 下载虚拟机客户端安装客户端创建虚拟机下载 ISO切换root账号GNOME桌面 下载虚拟机客户端 版本是16.2.3 链接&#xff1a;https://pan.baidu.com/s/13c6XVWFbeQKbCnrlfxD8cA 提取码&#xff1a;qxdc 安装客户端 安装向导 点击下一步 接收条款&#xff0c;点…

爬虫012_字典高级操作_查询_修改_添加_删除和清空_遍历---python工作笔记031

然后来看字典高级,首先 打印某个元素 然后打印的时候注意,如果直接打印的值,在字典中没有就报错 这里要注意不能用点访问

【多维定向滤波器组和表面波】表面变换:用于高效表示多维 s 的多分辨率变换(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Unity 基础函数

Mathf&#xff1a; //1.π-PI print(Mathf.PI); //2.取绝对值-Abs print(Mathf.Abs(-10)); print(Mathf.Abs(-20)); print(Mathf.Abs(1)); //3.向上取整-Ce il To In t float f 1.3f; int i (int)f; …