seo网站建设视频教程,建设网站需要什么步骤,中国互联网协会理事长,让路由器做网站服务器前言
HM新出springboot入门项目《苍穹外卖》#xff0c;笔者打算写一个系列学习笔记#xff0c;“苍穹外卖项目解读”#xff0c;内容主要从HM课程#xff0c;自己实践#xff0c;以及踩坑填坑出发#xff0c;以技术#xff0c;经验为主#xff0c;记录学习#xff0…前言
HM新出springboot入门项目《苍穹外卖》笔者打算写一个系列学习笔记“苍穹外卖项目解读”内容主要从HM课程自己实践以及踩坑填坑出发以技术经验为主记录学习也希望能给在学想学的小伙伴一个参考。 注:本文章是直接拿到项目的最终代码,然后从代码出发,快速逆向学习技术经验! 可能需要一些前置知识 觉得文章有用可以关注点赞收藏期待更新^^期待您的评论留言 苍穹外卖项目解读(一) 完整代码本地部署运行 苍穹外卖项目解读(二) 管理端JWT令牌、AOP注解开发、分页 苍穹外卖项目解读(三) redis、cache缓存解读 苍穹外卖项目解读(四) 微信小程序支付、定时任务、WebSocket 微信小程序支付
微信小程序开发
1、微信小程序开发需要到微信小程序服务平台注册分为个人、企业、媒体、政府等提供需要的注册文件即可。不同的注册主体所获得的开发权限有所不同个人版就无法使用微信支付功能
2、注册完成之后对于后端开发来说我们需要在开发管理中获取所注册小程序IDAppID、小程序秘钥AppSecret。对应Java配置文件中
wechat:appid: wxffb3637a228223b8secret: 84311df9199ecacdf4f12d27b6b9522d3、微信开发者工具前端交互开发工具请大家自行探索^^
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种调度任务类型继承结构如上图具体说明如下 1CronTaskcron表达式调度的任务 2FixedDelayTask固定延迟时间执行的任务 3FixedRateTask固定速率执行的任务 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、框架内提供的任务调度器
框架内提供的任务调度器主要包括
1ConcurrentTaskScheduler
2ThreadPoolTaskScheduler 继承结构如下 以上述框架默认的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如果加密则为wsstcp 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 MapString, 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) {CollectionSession sessions sessionMap.values();for (Session session : sessions) {try {//服务器向客户端发送消息session.getBasicRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}}script typetext/javascriptvar 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();}
/scriptreference https://blog.csdn.net/supzhili/article/details/131324690 https://baijiahao.baidu.com/s?id1706643919026404240wfrspiderforpc