关于express:我是如何让我的-GPT-长记性-的轻松实现有-记忆-的-GPT

我的项目地址:github.com/ltyzzzxxx/g… 最新进度:目前已实现 GPT 在线角色 DIY 性能,还在解决细节中... 欢送大家Star、提出 Issue & PR,一起高兴地用 GPT Terminal 游玩吧~ 前言明天持续来教大家如何玩转 OpenAI 接口! 自从 ChatGPT 横空出世之后,市面上就涌现了大量的类 GPT 利用(网站、公众号、小程序、App等等),它们和 ChatGPT 提供的性能简直并驾齐驱。这一切都是源于 OpenAI 为开发者们提供了 SDK 与 API 服务,使得大家可能欢乐地调用接口~ 然而,如果你不懂得如何应用它提供的服务,那么做进去的 GPT 利用与市面上的相比,可能有许多缺点。明天,我就先带大家功克第一个缺点:如何让你做的 GPT 利用长长 “忘性” !我会从实践与实战的角度,带大家制作出有 "记忆" 性能的 GPT! 接口分析咱们在发送音讯时,都是申请 OpenAI 提供的 createChatCompletion SDK 或 去调用 https://api.openai.com/v1/chat/completions API 从而获取 GPT 响应。想必大家如果看过我之前写的文章,肯定对这种形式不生疏。然而,如果你只是单纯地将以后用户的发问作为申请参数传递给接口中,GPT 只会给你返回以后问题的响应,它本身没有记录上下文的能力。因为,咱们对于 GPT 的每次申请与响应,都是独自的,并不会被 GPT 所存储。 然而,在实在的聊天场景,与你聊天的人肯定会晓得对话的上下文。要想使得 GPT 更加智能,必须得具备这一特点。难道 OpenAI 团队不晓得这一点吗?其实,解决方案还是老配方,答案还是藏在 createChatCompletion接口参数中! 大家应该还记得我在上上一篇文章中,我通过以下流程实现了角色定制: 在 Markdown 中依照模板格局,事后定义好角色信息以及具体问答 Case将其从 Markdown 格局转为了 JSON 对象数组申请 createChatCompletion 接口,参数 messages 即为转化好的对象数组这时候聪慧的大家预计曾经想到了,这些事后定义好的角色信息和问答 Case,就是 GPT 能够参考的上下文啊!这样看来,要想让 GPT “长忘性”,也能够通过这一思路实现! ...

June 23, 2023 · 2 min · jiezi

关于express:还在只用RedisTemplate访问Redis吗

开始筹备开始之前咱们须要有Redis装置,咱们采纳本机Docker运行Redis, 次要命令如下css复制代码docker pull redisdocker run --name my_redis -d -p 6379:6379 redisdocker exec -it my_redis bashredis-cli 后面两个命令是启动redis docker, 后两个是连贯到docker, 在应用redis-cli 去查看redis外面的内容,次要查看咱们存在redis外面的数据。RedisTemplate咱们先从RedisTemplate开始,这个是最好了解的一种形式,我之前在工作中也应用过这种形式,先看代码示例 咱们先定义一个POJO类less复制代码@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic class Book implements Serializable {    private Long id;    private String name;    private String author;} 一个很简略的BOOK类,三个字段: id,name和author. 再来一个RedisTemplate的Beanarduino复制代码    @Bean    public RedisTemplate<String, Book> redisTemplate(RedisConnectionFactory redisConnectionFactory) {        RedisTemplate<String, Book> template = new RedisTemplate<>();        template.setConnectionFactory(redisConnectionFactory);        return template;   } ...

May 24, 2023 · 4 min · jiezi

关于express:2023大厂算法面试真题手刷笔记含社区7大语言最佳答案No34在排序数组中查找元素的第一个和最后一个位置

题目详情给你一个依照非递加顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始地位和完结地位。 如果数组中不存在目标值 target,返回 [-1, -1]。 你必须设计并实现工夫复杂度为 O(log n) 的算法解决此问题。 示例 1: **输出:** nums = [5,7,7,8,8,10], target = 8**输入:** [3,4]示例 2: **输出:** nums = [5,7,7,8,8,10], target = 6**输入:** [-1,-1]示例 3: **输出:** nums = [], target = 0**输入:** [-1,-1]提醒: 0 <= nums.length <= 105-109 <= nums[i] <= 109nums 是一个非递加数组-109 <= target <= 109解题思路办法1 线性查找首先,咱们从右边对nums进行线性扫描,当咱们找到一个指标实例时就会中断。如果咱们从不中断,那么指标就不存在,所以咱们能够提前返回“-1,-1”的“错误代码”。思考到咱们的确找到了一个无效的左索引,咱们能够进行第二次线性扫描,但这次从右开始。在这种状况下,遇到的指标的第一个实例将是最左边的实例(并且因为存在最右边的实例,因而也保障存在最左边的实例)。而后咱们简略地返回一个蕴含两个定位索引的列表。 class Solution { public int[] searchRange(int[] nums, int target) { int[] targetRange = {-1, -1}; // find the index of the leftmost appearance of `target`. for (int i = 0; i < nums.length; i++) { if (nums[i] == target) { targetRange[0] = i; break; } } // if the last loop did not find any index, then there is no valid range // and we return [-1, -1]. if (targetRange[0] == -1) { return targetRange; } // find the index of the rightmost appearance of `target` (by reverse // iteration). it is guaranteed to appear. for (int j = nums.length-1; j >= 0; j--) { if (nums[j] == target) { targetRange[1] = j; break; } } return targetRange; }}办法二 二分查找除了用于查找左右索引自身的子例程之外,整体算法与线性扫描办法的工作形式十分类似。,在这里,咱们应用批改后的二分查找来搜寻已排序的数组,并进行一些小的调整。,首先,因为咱们正在定位蕴含指标的最右边(或最左边)索引(而不是在咱们找到指标时返回true),所以算法一找到匹配就不会终止。,相同,咱们持续搜寻直到lo == hi并且它们蕴含能够找到指标的索引。 ...

May 18, 2023 · 7 min · jiezi

关于express:Leetcode算法刷题笔记含7大语言社区最佳答案No1两数之和

题目详情给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个整数,并返回它们的数组下标。 你能够假如每种输出只会对应一个答案。然而,数组中同一个元素在答案里不能反复呈现。 你能够按任意程序返回答案。 示例 1: **输出:** nums = [2,7,11,15], target = 9**输入:** [0,1]**解释:** 因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。示例 2: **输出:** nums = [3,2,4], target = 6**输入:** [1,2]示例 3: **输出:** nums = [3,3], target = 6**输入:** [0,1]提醒: 2 <= nums.length <= 104-109 <= nums[i] <= 109-109 <= target <= 109只会存在一个无效答案进阶: 你能够想出一个工夫复杂度小于 O(n2) 的算法吗? 解题思路办法一:暴力法暴力法很简略。遍历每个元素 x,并查找是否存在一个值与 target - x 相等的指标元素。 ...

May 11, 2023 · 2 min · jiezi

关于express:test

taeawtwetwet

April 27, 2023 · 1 min · jiezi

关于express:几个不错的idea插件让我码速又快了

前言idea能够说是java开发者应用的最多的开发工具了,一写好的idea插件不仅仅能赏心悦目,更能帮忙咱们晋升效率,有更多的工夫去摸鱼。上面就举荐一些我常常用的idea插件。Gradianto插件反对 idea的相干皮肤,是我用过比拟好用,ui格调很好的一款插件 jclasslib Bytecode viewer插件class文件反编译插件 ->jclasslib is a bytecode viewer for Java class files。 可是反编译class文件,当然这针对于老版本的idea,新版本的idea曾经主动集成该性能了。Grep Console 插件能够将控制台打印的日志分色彩显示,能够如下进行设置。 GenerateAllSetter 插件一键生成一个对象的所有set办法 。插件能够疾速生成 Java 类中的所有属性的 setter 办法,让你能够更快地为对象的各个属性增加 setter。帮忙你放慢 Java 开发工作流程,自动化生成 setter 办法的创立,进步开发效率GsonFormat 插件应用 alt+s 快捷键调起。应用 GsonFormat 插件能够大大简化在开发过程中手动创立 Java 类的工作量。生成的 Java 类将蕴含与输出的 JSON 字符串中的键和值对应的属性和办法。这使得在解决 JSON 数据时更加不便和快捷JRebel and XRebel 插件热部署插件(这个我都用多介绍了吧)。Tomcat启动相干配置(jrebel启动tomcat时须要加载的我的项目配置): CATALINA_BASE=E:\下载文件\java产品\tomcat\apache-tomcat-7.0.76-windows-x64\apache-tomcat-7.0.76热部署jar包中的jsp , js 等代码时,须要在pom文件中配置相应的打包代码。而后再rebel.xml部署jsp等页面的本地文件地址,即可实时失效。leetcode editor 插件一个连贯leetcode官网的插件。当咱们摸鱼的时候,咱们就能够每天都在idea中练习一下,还没人发现你在摸鱼,真香。maven helper 插件一个帮组你显示maven依赖树的插件。点击pom文件而后再编辑视图中左下角抉择“Dependency Aanlyzer”即可查看。 咱们能够通过他疾速查看我的项目的maven依赖关系,发现依赖抵触等。其反对树形显示依赖和列表显示,非常不便。 SequenceDiagram 插件查看办法调用时序图。应用 SequenceDiagram 插件能够不便地可视化代码中的办法调用关系,以及办法之间的时序关系,有助于开发人员更好地了解代码执行过程,有助于调试和优化代码。 Statistic 插件统计代码量多少的一个插件。Statistic 插件能够不便地理解代码的构造和应用状况,有助于开发人员更好地治理和保护代码。统计后果将显示代码中各种元素的应用状况,例如类的数量、办法的数量、变量的数量等。你还能够依照各种条件排序和过滤统计后果,以便更好地理解代码的构造和应用状况。 Translation 插件这是一款国人开发的插件,每当你查看源码的doc文档时,看到满屏的英文您累嘛?说实话对我这种英文渣来说,这是在是一件苦楚的事件,然而该插件拯救了我。感激作者。以上就是我举荐的几款idea插卡,各位看官按需获取。 ...

April 18, 2023 · 1 min · jiezi

关于express:FastDFS收藏起来现在开始用Minio吧

一、Minio介绍MinIO是寰球当先的对象存储先锋,目前在全世界有数百万的用户。 高性能 ,在规范硬件上,读/写速度上高达183GB/秒和171GB/秒,领有更高的吞吐量和更低的提早可扩展性 ,为对象存储带来了简略的缩放模型,通过增加更多集群能够扩大空间简略 ,极简主义是MinIO的指导性设计准则,即可在几分钟内装置和配置与Amazon S3兼容 ,亚马逊云的 S3 API(接口协议)是在寰球范畴内达到共识的对象存储的协定,是全世界内大家都认可的规范数据安全 ,应用纠删码来爱护数据免受硬件故障和无声数据损坏 纠删码纠删码是一种复原失落和损坏数据的数学算法, Minio默认采纳 Reed-Solomon code将数据拆分成N/2个数据块和N/2个奇偶校验块。这就意味着如果是16块盘,一个对象会被分成8个数据块、8个奇偶校验块,你能够失落任意8块盘(不论其是寄存的数据块还是校验块),你仍能够从剩下的盘中的数据进行复原。docs.minio.org.cn/docs/master…Minio和FastDFS的比照 装置难度文档性能容器化反对SDK反对 二、Minio装置 为了疾速搞定Minio的部署工作。咱们通过Docker-Compose来一键疾速部署操作1.装置DockerCompose 装置DockerCompose的前提是先装置一个Docker环境,如果还没装置的参考波哥的博客地址:blog.csdn.net/qq_38526573… Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您能够应用 YML 文件来配置应用程序须要的所有服务。而后,应用一个命令,就能够从 YML 文件配置中创立并启动所有服务。 一键启动所有的服务 DockerCompose的应用步骤 创立对应的DockerFile文件创立yml文件,在yml文件中编排咱们的服务通过 docker-compose up命令 一键运行咱们的容器 官网地址:docs.docker.com/compose下载地址:curl -L https://get.daocloud.io/docker/compose/releases/download/1.25...uname -s-uname -m > /usr/local/bin/docker-compose复制代码批改文件夹权限chmod +x /usr/local/bin/docker-compose复制代码建设软连贯ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose复制代码查看是否装置胜利docker-compose --version复制代码2.装置Minio集群官网举荐 docker-compose.yaml:稍加批改,内容如下:version: '3.7' 所有容器通用的设置和配置x-minio-common: &minio-common image: minio/minio command: server --console-address ":9001" http://minio{1...4}/data expose: - "9000"# environment: # MINIO_ROOT_USER: minioadmin# MINIO_ROOT_PASSWORD: minioadminhealthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]interval: 30stimeout: 20sretries: 3启动4个docker容器运行minio服务器实例应用nginx反向代理9000端口,负载平衡, 你能够通过9001、9002、9003、9004端口拜访它们的web consoleservices: minio1: <<: *minio-commonhostname: minio1ports: - "9001:9001"volumes: - ./data/data1:/dataminio2: ...

April 18, 2023 · 2 min · jiezi

关于express:Java项目是不是分布式真有那么重要吗

大略不晓得从什么时候,「微服务」「分布式」这两个词又再次频繁呈现在我的眼帘里。「微服务」「分布式」在我刚毕业的时候还是比拟关注的,那时候还入门了一把SpringCloud,写了一篇很长的文章,还是很顶的,有不少的大号都给我转载了,在知乎又取得了很多的赞。那时候感觉懂「分布式」「微服务」是要害,什么SSM/SSH这不是谁都会吗,靠SSH/SSM我怎么有竞争力找工作啊。起初工作当前,对这块技术栈就没怎么深刻去看过了,毕竟我不是在公司里搞RPC框架组件的,把工夫都专一于本人的业务零碎里去了。工作了之后,有的共事跳槽去了阿里/字节,我看他们简历也没写本人懂「微服务」「分布式」,也没见他们在简历上有Dubbo和SpringCloud这种技术栈,但这也没影响他们跳去字节和阿里这种公司。同理,我在去年跳槽的时候,我的简历也没有这块内容。面试下来,也仅仅只有一个面试官随口提了下我懂不懂SpringCloud的原理。我跟他说我对这块理解不深,只晓得大抵的过程,他也没尴尬我,间接就跳过了。而我当初工作的内容也没有大量波及到Dubbo/SpringCloud这种技术栈的组件去应用,所以跟大家比起来,我这块技术栈还是很单薄。可能等我下次跳槽的时候,这块货色我还是写不上简历去。回到正题上吧,最近「微服务」「分布式」这两个词又再次频繁呈现在我的眼帘里,最次要的可能是我做了个开源我的项目「Austin」,有挺多人问我这个我的项目是不是分布式的。开源我的项目音讯推送平台austin仓库地址: 音讯推送平台推送下发【邮件】【短信】【微信服务号】【微信小程序】【企业微信】【钉钉】等音讯类型。 gitee.com/zhongfuchen…github.com/ZhongFuChen… 能够明确地通知大家,它并不是「分布式」「微服务」的我的项目。目前到此为止,它外围就只有一个发送的接口,而且只能通过HTTP的形式去调用。那他能做成一个「分布式」我的项目吗?答案也是能够的,只有把「服务治理」相干的组件引入就能够问题了。当初是我的项目是离开module模块的,austin-web(治理后盾)/austin-cron(定时工作)/austin-api和austin-api-impl(接入层)/austin-handler(下发逻辑解决层)这几个都能够独自抽出来部署。 (实际上在线上环境里,也是这么干的)独自部署了当前,再通过「服务治理」的组件进行治理,那零碎就是「分布式」的架构了。听着听不难,对不对?实际上也的确不难。既然如此,为什么我始终都没去变动我的零碎呢?最外围的点在于:我认为以我这类零碎来说,性能的完整性比「分布式」这种架构模式更加重要。又因为我的工作历程导致我始终在生产环境下就没有很多条件去深刻接触这些「服务治理」的组件,我对它们是不相熟的。而且我集体对此类框架又没有很浓重的趣味,我喜爱把重点放在存储的组件上(更违心把工夫花在Redis/MySQL/HBase/Elasticsearch这些)最近,我看股东群有好多都是在备战校招的,也见证了整个校招环境的确是越来越卷了,在这我给个小tips吧。其实吧,我感觉作为应届生在面试的时候是不太须要过于在意「分布式」。以我做面试官的角度而言,在正式工作之前,能有啥场景给你深刻去做「分布式」零碎。除非你简历真的写了挺多的分布式内容,不然我是不会把「分布式」作为面试校招生的重点(如果你都真的懂了,那的确是能够拉开差距的,前提是你的基础知识体现都不错)。如果你没写,那我真的就不会去问这块内容。简历上写的技术栈最好是本人比拟相熟的,只是用过但不懂原理的能够去掉,简历上的技术栈并不是越多越好祝福备战的小伙伴都能早日上岸!

March 28, 2023 · 1 min · jiezi

关于express:任务编排CompletableFuture从入门到精通

前言最近遇到了一个业务场景,波及到多数据源之间的申请的流程编排,正好看到了一篇某团介绍CompletableFuture原理和应用的技术文章,次要还是波及应用层面。网上很多文章波及原理的局部讲的不是特地具体且比拟形象。因为波及到多线程的工具必须要了解原理,不然一旦遇到问题排查起来就只能凭玄学,正好借此梳理一下CompletableFuture的工作原理背景咱们把Runnable了解为最根本的线程工作,只具备在线程下执行一段逻辑的能力。为了获取执行的返回值,发明了Callable和与其配合应用的Future。为了将工作之间进行逻辑编排,就诞生了CompletableFuture。对于如何了解工作的逻辑编排,举一个简略的例子: 关上电脑-更新零碎这两个操作是有先后顺序的,然而泡茶和这两个操作没有先后顺序,是能够并行的,而开始办公必须要期待其余操作完结之后能力进行,这就造成了工作编排的执行链。在IO密集型零碎中,相似的场景有很多。因为不同数据集的查问依赖主键不同,A数据集的查问主键是B数据集的一个字段这种状况很常见,通常还须要并发查问多个数据集的数据,所以对于多线程的执行编排是有需要的。一种解决办法是CountDownLatch,让线程执行到某个中央后进行期待,直到依赖的工作执行完结。对于一些简略的执行链是能够满足的,然而当编排逻辑简单起来,CountDownLatch会导致代码难以保护和调试。所以诞生了CompletableFuture用来形容和保护工作之间的依赖关系以进行工作编排。在理论利用中,有以下两类场景是适宜应用工作编排的: 多数据源申请的流程编排 非阻塞化网关等NIO场景 应用形式创立与执行同步办法和FutureTask相似,CompletableFuture也通过get()办法获取执行后果。然而不同的是,CompletableFuture自身能够不承载可执行的工作(相比FutureTask则必须承载一个可执行的工作Callable),通过一个用于标记执行胜利并设置返回值的函数,在应用上也更为灵便,如下: CompletableFuture<String> demo = new CompletableFuture<>();demo.complete("success");System.out.println(demo.get());复制代码 执行后果:success 和Future相似,get()函数也是同步阻塞的,调用get函数后线程会阻塞直到调用complete办法标记工作曾经执行胜利。除了手动触发工作的实现,也能够让创建对象的同时就标记工作实现: CompletableFuture<String> demo = CompletableFuture.completedFuture("success");System.out.println(demo.get());复制代码 执行后果:success 异步办法相比于同步办法,异步执行更为常见。比方上面这个例子: CompletableFuture<String> demo = CompletableFuture.supplyAsync(() -> { System.out.println("do something by thread" + Thread.currentThread().getName()); return "success"; }); System.out.println(demo.get());复制代码 执行后果:do something by threadForkJoinPool.commonPool-worker-9success supplyAsync办法接管一个Supplier对象,逻辑函数交给线程池中的线程异步执行 默认会应用ForkJoinPool的公共线程池来执行代码(不举荐),当然也能够指定线程池,如下: ExecutorService executor = Executors.newFixedThreadPool(4);CompletableFuture<String> demo = CompletableFuture.supplyAsync(() -> { System.out.println("do something by thread" + Thread.currentThread().getName()); return "success";}, executor);System.out.println(demo.get());复制代码 执行后果:do something by threadpool-1-thread-1success 如果不须要执行后果,也能够用runAsync办法: CompletableFuture.runAsync(() -> { System.out.println("do something by thread" + Thread.currentThread().getName());});复制代码 ...

March 28, 2023 · 4 min · jiezi

关于express:GPT4免费无限制使用教程

你还在为开明Chat GPT账号苦恼吗你还在为不能拜访的问题苦恼吗你还在为拜访次数及速度苦恼吗明天举荐的这个工具对于这些问题都不是问题,基于GPT-4(官网是这样介绍的,然而有人通过对话让它答复模型,它的答复却不是,运行中也有肯定的错误率,理论大家须要自行判断),分分钟即可体验,不须要注册账号,没有Q的问题,没有拜访次数的限度。专为开发者设计,针对你的代码逐行剖析,优化代码,书写代码。以下是援用官网的一句话: Write, edit, and chat about your code with GPT-4 in a new type of editor 应用非常简单,进入官网的首页点击下载,装置软件,软件不大很快就能装置实现。装置实现后的工具页面,和vscode开发工具很像。 上面介绍一下次要的四个性能,点击右上角的机器人按钮能够呈现这个弹窗。 也能够通过选中代码进行聊天和改写。 生成代码输出你要生成代码形容,回车即可,比方我要写一个五子棋小游戏,如下图所示其响应速度十分快。 每次的答复长度是有限度的,对于没有书写实现或者答复实现的状况输出持续即可。对于比拟长的代码可能生成的代码运行会有问题,针对有问题的中央能够持续提醒它优化改过。 文字聊天产品的次要指标是程序软件方面,然而问其余的问题我试过也是可行的,就和一般的chatGPT没有什么区别。 选中代码聊天对选中的代码进行发问,解析其含意,是否有优化的空间,改写为其余语音等等。总之就是针对你选中的代码你能够问任何问题。 改写代码对选中的代码进行改写编辑,比方减少正文,改进优化,批改代码语言或者正文语言等。批改完了会有提醒是否承受本次的批改,就像合并代码一样。 最初最初附上官网的地址:www.cursor.so 。整个工具非常简洁,运行速度非常高效。是程序开发者的利器,很合乎公众程序开发者的习惯。这个界面的操作和一般的开发工具一样,不晓得你是在写代码呢,还是在写代码呢~[偷笑]看完本文如果感觉有用,记得点个赞反对,珍藏起来说不定哪天就用上啦~

March 22, 2023 · 1 min · jiezi

关于express:大屏开发你需要知道哪些

大屏 大屏是什么呢?再我前几年刚接触这个词得时候很新鲜,全名叫态势感知大屏,大屏得特点是炫酷、难看,给用户满满得科技感。 听一位前辈说当年再招标会上,再都用exel、word做界面图表文档得时候,有一家公司把可视化态势感知大屏展现进去了,间接秒杀其余厂家。 那么当咱们开发一款大屏点的时候须要留神什么呢? 适配 再适配得技术概念上分为真适配、伪适配。 那么什么叫做真适配、伪适配呢? 伪适配 伪适配就是利用csstransform: scale(1); 达到一个界面适配。 长处: 适配比拟快,就应用失常px开发就好了,监听下分辨率做一个scale缩放。 毛病: png、canvas 等要转成svg,不然就会含糊、不清晰。 真适配 真适配就是利用vw、vh、rem、%,达到一个界面得真适配。 vw 100vw 等于以后窗口屏幕得宽度;vh 100vh 等于以后窗口屏幕得高度;rem 次要依据根元素body得font-size:12px, 1rem 等于12px, 而后跟用窗口得大小赋值给body对应得fontSize; 长处: 再开发阶段须要间接应用对应得尺寸单位,或者利用postcss-px-to-viewport、postcss-pxtorem等postcss插件达到一个px得转换。(集体倡议再开发阶段间接应用适配单位,插件还是有或多或少得问题)。 毛病: 要针对性进行每个元素进行单位适配,略微有些老本(能够利用vscode插件间接实现转化); vscode插件:【px2vw】 针对css、less、sass 能够实现单位转化,然而他不反对.vue文件中style的转换。vscode插件:【px2xx】这个插件能满足咱们开发单位转换。 真适配又分为 高度适配、宽度适配。 宽度适配就是依据用户得屏幕窗口宽度发生变化做到一个界面适配,比方全副都应用vw。高度适配是依据用户屏幕窗口发生变化达到一个界面适配,比方应用vh; 其实集体认为没必要做高度适配、都依据宽度vw达到一个界面适配就好了,次要是因为做高度适配得话应用vh,再小点得屏幕上 很容易就产生文本重叠、界面不美观、因为文字大小再浏览器最小是12px嘛。大屏界面布局 其实个别大屏布局会又一个header(主题目、工夫展现)、side (副标题:屏幕的两侧可能会分为4块4个维度去展现以后屏的一些信息)、main(大屏主视图)、footer(底部)。 咱们再搭建容器应用的都是定位那么肯定要分清定位权重。上面是一个常见布局权重散布: header 应该是position: absolute;top: 0; height: 60px(须要实现对应设计搞单位转换): z-index:2; 权重是2; side 应该是position: absolute; top: 60px(header的高度); leftSide 应该是position: absolute; top: 0; left: 0; z-index: 2; 权重2 leftTopSide 应该是 position: absolute; top: 10px(间距); z-index: 3; 权重3leftBottomSide 应该是 position: absolute; bottom: 10px(间距); z-index: 3;权重3 ...

March 22, 2023 · 2 min · jiezi

关于express:赶走烦人的ifelse使用状态模式推动业务生命周期的流转

1.业务背景本文借助海内互金业务的借款流程开展。业务外围是借款的生命周期,相当于是电商中的订单一样。一笔借款的整个生命周期蕴含了提交,审批,确认,放款,还款。一笔借款的状态对应已上的操作,同样就很多了。如图是一笔借款的生命周期: 对于这么多状态,业务代码上有很多判断分支,什么状况下能够做什么操作,这是强校验的。业务初期疾速上线,if else能够疾速地将业务串联起来,在各个业务解决的节点判断并执行业务逻辑。 if (LoanStatusConstant.CREATED.equals(oldStatus) ||     LoanStatusConstant.NEED_MORE_INFO.equals(oldStatus)) {     log.info("---> Loan to Submitted"); }  if (LoanStatusConstant.APPROVED.equals(loan.getStatus())) {     log.info("---> Loan confirmed"); }  if (!LoanStatusConstant.APPROVED.equals(loanStatus)) {     log.info("---> Loan approved,to Fund"); } //.......复制代码2.业务代码的“坏滋味”随着经营推广的力度加大,用户一拥而上,风控环境更加严苛,整个产品线也陆续退出了更多的流程去迭代产品,让危险和收益能趋于均衡。这时候在开发代码上的体现就是代码库急剧收缩,业务扩张天然会扩招,新共事也会在已有的代码上打补丁,在这些补丁式的需要下,已经的if else会指数级的凌乱,一个简略的需要都可能挑战现有的状态分支。这种“坏滋味”不加以干涉,整个我的项目的生命力间接走向晚年。 //审核 public void approve(@RequestBody LoanSubmitDTO submitDTO) {     final Loan loan = loanMapper.selectOne(new LambdaQueryWrapper<Loan>().eq(Loan::getRefId, submitDTO.getLoanRefId()));     if (Objects.isNull(loan)){         throw new BaseBizException("loan Not exists");    }     if (!SUBMITTED.getCode().equals(loan.getStatus())){         throw new BaseBizException("loan status incorrect");    }      loan.setStatus(APPROVED.getCode());     loanMapper.updateById(loan); } //确认 public LoanDTO submit(LoanSubmitDTO submitDTO) {     final Loan loan = loanMapper.selectOne(new LambdaQueryWrapper<Loan>().eq(Loan::getRefId, submitDTO.getLoanRefId()));     if (Objects.isNull(loan)){         throw new BaseBizException("loan Not exists");    }     if (!CREATED.getCode().equals(loan.getStatus())){         throw new BaseBizException("loan status incorrect");    }      loan.setStatus(SUBMITTED.getCode());     loanMapper.updateById(loan);     riskService.callRisk(submitDTO);      return BeanConvertUtil.map(loan,LoanDTO.class); }复制代码随着我的项目一直收缩,为了对贷款状态进行校验,if else会充斥业务层的各个中央,此时,一旦产品上对业务流程进行调整,状态也会随着批改。比方新增了风控确认机制,用户能够补充信息再提交,对于满足肯定条件的贷款能够让用户补充肯定的风控信息再提交,那么此时对于借款提交流程的前置状态就要发生变化了: //提交 public LoanDTO submit(LoanSubmitDTO submitDTO) {     final Loan loan = loanMapper.selectOne(new LambdaQueryWrapper<Loan>().eq(Loan::getRefId, submitDTO.getLoanRefId()));     if (Objects.isNull(loan)){         throw new BaseBizException("loan Not exists");    }     //判断条件发生变化。     if (!CREATED.getCode().equals(loan.getStatus())&&!NEED_MORE_INFO.getCode().equals(loan.getStatus())){         throw new BaseBizException("loan status incorrect");    }      loan.setStatus(SUBMITTED.getCode());     loanMapper.updateById(loan);     riskService.callRisk(submitDTO);      return BeanConvertUtil.map(loan,LoanDTO.class); }复制代码我的项目迭代过程中每一次上线前测试同学都会进行严格地测试。以上这种变动可能会批改多个中央的代码,测试同学就不得不进行大面积的回归测试,上线危险会大大增加;而咱们开发同学这种新逻辑上线就硬改原有代码的行为,违反了开闭准则,随着业务的迭代,我的项目代码的可读性会越来越差(if-else越来越多,测试用例不清晰),可能很多人感觉就改了个判断语句没什么大不了的,但实际上很多生产事变都是因为这种频繁的小改变导致的。如何去躲避已上这种 “坏滋味” 呢?3.OCP准则(凋谢关闭准则)3.1 定义咱们先来看看什么是【凋谢关闭准则】: ...

March 20, 2023 · 9 min · jiezi

关于express:SpringBoot项目jarwar包启动解析

一、jar包和war包的区别1.1 war包 war包是Java Web应用程序的一种打包形式合乎Servlet规范,它是Web Archive的缩写,次要用于存储Web应用程序相干的文件,包含Java类文件、JSP、HTML、CSS、JavaScript、图片等资源文件。war包须要部署到web服务器中(Tomcat、Apache、IIS) 1.2 jar包 jar包是类的归档文件,次要用于存储Java类文件和相干资源文件。它通常被用于封装Java应用程序或Java类库,不便程序的部署和公布jar包能够被JVM间接加载和运行。 1.3 次要区别: jar包次要用于存储Java类文件和相干资源文件,而war包次要用于存储Web应用程序相干的文件。jar包能够被JVM间接加载和运行,而war包须要被Web服务器加载和运行。jar包通常用于封装Java应用程序或Java类库,而war包用于封装Java Web应用程序。 二、SpringBoot应用war包启动war包启动:须要先启动内部的Web服务器,实现Servlet3.0标准中疏导利用启动类,而后将war包放入Web服务器下,Web服务器通过回调疏导利用启动类办法启动利用。2.1 Servlet3.0标准中疏导利用启动的阐明 在Servlet容器(Tomcat、Jetty等)启动利用时,会扫描利用jar包中 ServletContainerInitializer 的实现类。框架必须在jar包的 META-INF/services 的文件夹中提供一个名为 javax.servlet.ServletContainerInitializer 的文件,文件内容要写明 ServletContainerInitializer 的实现类的全限定名。这个 ServletContainerInitializer 是一个接口,实现它的类必须实现一个办法:onStartUp能够在这个 ServletContainerInitializer 的实现类上标注 @HandlesTypes 注解,在利用启动的时候自行加载一些附加的类,这些类会以字节码的汇合模式传入 onStartup 办法的第一个参数中。 public interface ServletContainerInitializer { void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException;}复制代码2.2 SpringBootServletInitializer的作用和原理Spirng中SpringServletContainerInitializer实现了Servlet的标准 @HandlesTypes(WebApplicationInitializer.class)public class SpringServletContainerInitializer implements ServletContainerInitializer { @Overridepublic void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { // SpringServletContainerInitializer会加载所有的WebApplicationInitializer类型的一般实现类 List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>(); if (webAppInitializerClasses != null) { for (Class<?> waiClass : webAppInitializerClasses) { // 如果不是接口,不是抽象类 if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) { try { // 创立该类的实例 initializers.add((WebApplicationInitializer) waiClass.newInstance()); } catch (Throwable ex) { throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex); } } } } if (initializers.isEmpty()) { servletContext.log("No Spring WebApplicationInitializer types detected on classpath"); return; } servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath"); AnnotationAwareOrderComparator.sort(initializers); // 启动Web利用onStartup办法 for (WebApplicationInitializer initializer : initializers) { initializer.onStartup(servletContext); }}}复制代码@HandlesTypes应用BCEL的ClassParser在字节码层面读取了/WEB-INF/classes和jar中class文件的超类名和实现的接口名,判断是否与记录的注解类名雷同,若雷同再通过org.apache.catalina.util.Introspection类加载为Class对象保存起来,最初传入onStartup办法参数中SpringServletContainerInitializer类上标注了@HandlesTypes(WebApplicationInitializer.class),所以会导入WebApplicationInitializer实现类SpringBoot中SpringBootServletInitializer是WebApplicationInitializer的抽象类,实现了onStartup办法@Overridepublic void onStartup(ServletContext servletContext) throws ServletException { ...

March 20, 2023 · 4 min · jiezi

关于express:使用expressws启动WebSocket服务实现双向通讯功能

成果动态图咱们应用WebSocket写一个这样的小demo: 演示网址:http://ashuai.work:8888/#/WebSocket (点击跳转观看成果)前端代码仓库地址:https://github.com/shuirongshuifu/elementSrcCodeStudy后端代码仓库地址:https://github.com/shuirongshuifu/express-ws-serverWebSocket相干常识温习什么是WebSocket,解决了什么问题WebSocket是html5推出的新个性,新性能,是一种新的网络通讯协定WebSocket解决了http只能单向申请的缺点(http只能由客户端向服务端发申请)应用WebSocket协定能够做到,客户端和服务端互相发送音讯http和WebSocket二者长相区别:http://ashuai.work:6789/url和ws://ashuai.work:6789/url(就最后面的协定变了)WebSocket利用场景对于实时性要求比拟高的性能需要,如: 聊天室性能实时股票行情性能体育竞赛直播性能最新天气最新消息(订阅公布,小红点未读音讯)多人协同编辑文档(及时更新)监控性能(监控地位、监控相干数据搭配可视化图表)在线客服根本WebSocket的八股文概念没啥意思,大家可移步到MDN官网文档瞅瞅这里咱们通过一个例子去学习,高深莫测哎 举个WebSocket理论例子例子需要可创立WebSocket服务,并敞开之实现客户端能够向服务端发送申请实现服务端能够向客户端推送音讯存储后端推送的每一条音讯类编程,便于前端多个中央复用......后端用express-ws开启WebSocket服务这里咱们应用npm上的一个比拟优良的包:express-ws,地址如下:https://www.npmjs.com/package/express-ws/v/5.0.2 当然,前提是咱们须要搭建一个express环境,这里咱们不赘述,间接上代码: 代码中,曾经有相干正文啦...app.js文件中应用express-ws包注入.ws接口办法 const express = require('express') // 引入express插件包并生成一个实例appconst app = express()// 引入express-ws的WebSocket性能,并混入app,相当于为 app实例增加 .ws 办法const expressWs = require('express-ws')(app) const Router = require('./router') // 引入分模块治理的路由app.use(Router) // 路由分模块app.listen(10000, (req,res) => { // 在10000端口上启动后端服务 console.log('后端服务端口地址为: http://localhost:10000');})router.js中应用route.ws创立WebSocket接口服务 /** * route.ws('/url',(ws, req)=>{ }) * 建设WebSocket服务,并指定对应接口url,及相应回调 * ws为实例化的对象,req即为申请 * * ws.send办法用来向客户端发送信息 * ws.on办法用于监听事件(如监听message事件,或监听close事件) * */route.ws('/mySocketUrl', (ws, req) => { // console.log('连贯胜利', ws) ws.send('来自服务端推送的音讯') ws.on('message', function (msg) { ws.send(`收到客户端的音讯为:${msg},再返回去`) }) // 应用定时器不停的向客户端推动音讯 let timer = setInterval(() => { ws.send(`服务端定时推送音讯: ${getNowTime()}`) }, 1000) ws.on('close', function (e) { // console.log('连贯敞开') clearInterval(timer) timer = null })})有的道友说,这样看着也不不便,有没有残缺的后端代码啊,我想运行起来,更加直观,不便,那必须有哎 ...

March 18, 2023 · 2 min · jiezi

关于express:Java中如何解析SQL语句格式化SQL语句生成SQL语句

昨天在群里看到有小伙伴问,Java里如何解析SQL语句而后格式化SQL,是否有现成类库能够应用?之前TJ没有做过这类需要,所以去钻研了一下,并找到了一个不过的解决方案,明天举荐给大家,如果您正要做相似内容,那就拿来试试,如果临时没需要,就先理解珍藏(技多不压身)。JSqlParserJSqlParser是一个用Java编写的SQL解析器,能够将SQL语句解析为Java对象,从而使开发人员可能轻松地剖析、批改和重构SQL查问。比方,这样的一句SQL语句SELECT 1 FROM dual WHERE a = bSELECT 1 FROM dual WHERE a = bJSqlParser能够将其解析为如下对象构造 SQL Text └─Statements: net.sf.jsqlparser.statement.select.Select └─selectBody: net.sf.jsqlparser.statement.select.PlainSelect ├─selectItems -> Collection<SelectExpressionItem> │ └─selectItems: net.sf.jsqlparser.statement.select.SelectExpressionItem │ └─LongValue: 1 ├─Table: dual └─where: net.sf.jsqlparser.expression.operators.relational.EqualsTo ├─Column: a └─Column: b复制代码而后咱们就能够通过其提供的API来拜访这句SQL语句中的各个因素:Statement statement = CCJSqlParserUtil.parse(sqlStr);if (statement instanceof Select) { Select select = (Select) statement;PlainSelect plainSelect = (PlainSelect) select.getSelectBody();SelectExpressionItem selectExpressionItem = (SelectExpressionItem) plainSelect.getSelectItems().get(0);Table table = (Table) plainSelect.getFromItem();EqualsTo equalsTo = (EqualsTo) plainSelect.getWhere();Column a = (Column) equalsTo.getLeftExpression();Column b = (Column) equalsTo.getRightExpression();}复制代码目前,JSqlParser反对了大部分次要的关系型数据库,包含: ...

March 10, 2023 · 1 min · jiezi

关于express:面试官什么是双亲委派模型

加入过校招面试的同学,应该对这个问题不生疏。个别发问 JVM 知识点的时候,就会顺带问你双亲委派模型(顺当的翻译。。。)。就算是不筹备面试,学习双亲委派模型对于咱们也十分有帮忙。咱们比拟相熟的 Tomcat 服务器为了实现 Web 利用的隔离,就自定义了类加载并突破了双亲委派模型。这篇文章我会先介绍类加载器,再介绍双亲委派模型,这样有助于咱们更好地了解。目录概览: 回顾一下类加载过程开始介绍类加载器和双亲委派模型之前,简略回顾一下类加载过程。 类加载过程:加载->连贯->初始化。连贯过程又可分为三步:验证->筹备->解析。 加载是类加载过程的第一步,次要实现上面 3 件事件: 通过全类名获取定义此类的二进制字节流将字节流所代表的动态存储构造转换为办法区的运行时数据结构在内存中生成一个代表该类的 Class 对象,作为办法区这些数据的拜访入口 类加载器类加载器介绍类加载器从 JDK 1.0 就呈现了,最后只是为了满足 Java Applet(曾经被淘汰) 的须要。起初,缓缓成为 Java 程序中的一个重要组成部分,赋予了 Java 类能够被动静加载到 JVM 中并执行的能力。依据官网 API 文档的介绍: A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a "class file" of that name from a file system.Every Class object contains a reference to the ClassLoader that defined it.Class objects for array classes are not created by class loaders, but are created automatically as required by the Java runtime. The class loader for an array class, as returned by Class.getClassLoader() is the same as the class loader for its element type; if the element type is a primitive type, then the array class has no class loader. ...

March 10, 2023 · 4 min · jiezi

关于express:Java为什么不支持多继承

首先,思考这么一种场景,如果当初A类继承了B类和C类,并且B类和C类中,都存在test()办法,那么当A类对象调用test()办法时,该调用B类的test()呢?还是C类的test()呢?是没有答案的,所以Java中不容许多继承。然而,Java中接口是能够多继承的,比方:public interface A { void test();} public interface B { void test();} public interface C extends A, B{ }复制代码为什么接口能够?因为都是A、B、C都是接口,就算A、B两个接口中都定义了test办法,因为接口中只是申明了办法,并没有真正实现办法,所以对于C接口而言并不会照成困扰,对于C接口而言它只是继承了同一个test()办法的申明而已,在应用时须要C接口的实现类来实现这个test()办法就能够了。public class C1 implements C{ public void test() { System.out.println("hello Hoeller");}}复制代码那么接口中不是有default办法吗?那不是也能够在接口中来实现办法吗?咱们间接来测试一下:public interface A { default void test() { System.out.println("a");}} public interface B { default void test() { System.out.println("b");}} public interface C extends A, B{ }复制代码此时C接口会编译报错,报错信息为: com.hoeller.C inherits unrelated defaults for test() from types com.hoeller.A and com.hoeller.B 翻不翻译都无所谓了,反正就是报错了,示意C接口不能同时继承两个接口中default办法test()。如果你问,那为什么C++中能够反对多继承,那得解释菱形继承、虚继承,本文就不剖析了(因为我也不晓得)。

March 10, 2023 · 1 min · jiezi

关于express:既然有Map了为什么还要有Redis

一、同样是缓存,用map不行吗? Redis能够存储几十个G的数据,Map行吗?Redis的缓存能够进行本地长久化,Map行吗?Redis能够作为分布式缓存,Map只能在同一个JVM中进行缓存;Redis反对每秒百万级的并发,Map行吗?Redis有过期机制,Map有吗?Redis有丰盛的API,反对十分多的利用场景,Map行吗? 二、Redis为什么是单线程的? 代码更清晰,解决逻辑更简略;不必思考各种锁的问题,不存在加锁和开释锁的操作,没有因为可能呈现死锁而导致的性能问题;不存在多线程切换而耗费CPU;无奈施展多核CPU的劣势,但能够采纳多开几个Redis实例来欠缺; 三、Redis真的是单线程的吗? Redis6.0之前是单线程的,Redis6.0之后开始反对多线程;Redis外部应用了基于epoll的多路服用,也能够多部署几个Redis服务器解决单线程的问题;Redis次要的性能瓶颈是内存和网络;内存好说,加内存条就行了,而网络才是大麻烦,所以Redis6内存好说,加内存条就行了;而网络才是大麻烦,所以Redis6.0引入了多线程的概念,Redis6.0在网络IO解决方面引入了多线程,如网络数据的读写和协定解析等,须要留神的是,执行命令的外围模块还是单线程的。 四、Redis优缺点1、长处 Redis是KV数据库,MySQL是关系型数据库,Redis速度更快;Redis数据操作次要在内存中,MySQL次要将数据存储在硬盘,Redis速度更快;Redis同样反对长久化(RDB+AOF),Redis反对将数据异步将内存的数据长久化到硬盘上,防止Redis宕机呈现数据失落的问题;Redis性能极高,读的速度是110000次/秒,写的速度是81000次/秒;Redis数据类型丰盛,不仅反对KV键值对,还反对list、set、zset、hash等数据结构的存储;Redis反对数据的备份,即master-slave模式的数据备份;Redis反对简略的事务,操作满足原子性;Redis反对读写拆散,分担读的压力;Redis反对哨兵模式,实现故障的主动转移;单线程操作,防止了频繁的上下文切换;采纳了非阻塞I/O多路复用机制,性能卓越; 2、毛病 数据存储在内存,容易造成数据失落;存储容量受内存的限度,只能存储大量的罕用数据;缓存和数据库双写一致性问题;用于缓存时,容易呈现内存穿透、缓存击穿、缓存雪崩的问题;批改配置文件后,须要进行重启,将硬盘中的数据同步到内存中,耗费的工夫较长,而且数据同步的工夫里Redis不能提供服务; 五、Redis常见业务场景 Redis是基于内存的nosql数据库,能够通过新建线程的模式进行长久化,不影响Redis单线程的读写操作通过list取最新的N条数据模仿相似于token这种须要设置过期工夫的场景公布订阅音讯零碎定时器、计数器缓存减速、分布式会话、排行榜、分布式计数器、分布式锁;Redis反对事务、长久化、LUA脚本、公布/订阅、缓存淘汰、流技术等个性; 六、Redis常见数据类型 1、String(1)String简介String 是最根本的 key-value 构造,key 是惟一标识,value 是具体的值,value其实不仅是字符串, 也能够是数字(整数或浮点数),value 最多能够包容的数据长度是 512M。(2)利用场景① 作为缓存数据库在Java管理系统体系中,大多数都是用MySQL存储数据,redis作为缓存,因为Redis具备撑持高并发的个性,通常能起到减速读写和升高数据库服务器压力的作用,大多数申请都会先申请Redis,如果Redis中没有数据,再申请MySQL数据库,而后再缓存到Redis中,以备下次应用。 ② 计数器Redis字符串中有一个命令INCR key,incr命令会对值进行自增操作,比方CSDN的文章浏览,视频的播放量,都能够通过Redis来计数,每浏览一次就+1,同时将这些数据异步存储到MySQL数据库中,升高MySQL服务器的写入压力。③ 共享session在分布式系统中,用户每次申请个别会拜访不同的服务器 ,这就会导致session不同步的问题,这时,个别会应用Redis来解决这个问题,将session存入Redis,应用的时候从Redis中取出就能够了。④ 分布式锁 setnx key value,加锁del key,开释锁 (3)key操作命令 (4)set key valueSET key value [NX | XX] [GET] [EX seconds | PX milliseconds | EXAT unix-time-seconds | PXAT unix-time-milliseconds | KEEPTTL] EX seconds,设置过期工夫,单位秒PX milliseconds,设置过期工夫,单位毫秒EXAT timestamp-seconds,设置过期工夫,以秒为单位的UNIX工夫戳PXAT timestamp-milliseconds,设置过期工夫,以毫秒为单位的UNIX工夫戳NX,键不存在的时候设置键值XX,键存在的时候设置键值KEEPTTL,保留设置前指定键的生存工夫GET,返回指定键本来的值,若键不存在返回nil 备注:命令不辨别大小写,而key是辨别大小写的。help @类型:查看以后类型相干的操作命令。Since the SET command options can replace SETNX, SETEX, PSETEX, GETSET, it is possible that in future versions of Redis these commands will be deprecated and finally removed。(5)同时设置多个键值(6)获取指定区间范畴内的值getrange、setrange。(7)数值增减 ...

March 10, 2023 · 2 min · jiezi

关于express:为啥一个-main-方法就能启动项目

在 Spring Boot 呈现之前,咱们要运行一个 Java Web 利用,首先须要有一个 Web 容器(例如 Tomcat 或 Jetty),而后将咱们的 Web 利用打包后放到容器的相应目录下,最初再启动容器。在 IDE 中也须要对 Web 容器进行一些配置,才可能运行或者 Debug。而应用 Spring Boot 咱们只须要像运行一般 JavaSE 程序一样,run 一下 main() 办法就能够启动一个 Web 利用了。这是怎么做到的呢?明天咱们就一探到底,剖析一下 Spring Boot 的启动流程。概览回看咱们写的第一个 Spring Boot 示例,咱们发现,只须要上面几行代码咱们就能够跑起一个 Web 服务器:@SpringBootApplicationpublic class HelloApplication { public static void main(String[] args) { SpringApplication.run(HelloApplication.class, args);}} 复制代码去掉类的申明和办法定义这些样板代码,外围代码就只有一个 @SpringBootApplication 注解和 SpringApplication.run(HelloApplication.class, args) 了。而咱们晓得注解相当于是一种配置,那么这个 run() 办法必然就是 Spring Boot 的启动入口了。接下来,咱们沿着 run() 办法来顺藤摸瓜。进入 SpringApplication 类,来看看 run() 办法的具体实现:public class SpringApplication { ......public ConfigurableApplicationContext run(String... args) { // 1 利用启动计时开始 StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 2 申明上下文 DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; // 3 设置 java.awt.headless 属性 configureHeadlessProperty(); // 4 启动监听器 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { // 5 初始化默认利用参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 6 筹备应用环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); // 7 打印 Banner(Spring Boot 的 LOGO) Banner printedBanner = printBanner(environment); // 8 创立上下文实例 context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); // 9 构建上下文 prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); // 10 刷新上下文 refreshContext(context); // 11 刷新上下文后处理 afterRefresh(context, applicationArguments); // 12 利用启动计时完结 stopWatch.stop(); if (this.logStartupInfo) { // 13 打印启动工夫日志 new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } // 14 公布上下文启动实现事件 listeners.started(context); // 15 调用 runners callRunners(context, applicationArguments); } catch (Throwable ex) { // 16 利用启动产生异样后的解决 handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { // 17 公布上下文就绪事件 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context;}......} ...

March 7, 2023 · 5 min · jiezi

关于express:从源码角度查看SpringBoot是怎样获取到Bean的

背景:咱们都晓得在SpringBoot启动类上增加@SpringBootApplication注解后执行main办法就能够主动启动服务 Spring会主动帮咱们找到须要治理的Bean的呢探索: 经典的八股文AbstractApplicationContext#refresh()办法 置信大家曾经比拟相熟了 进入invokeBeanFactoryPostProcessors()调用BeanFactory后置处理器办法 进入PostProcessorRegistrationDelegate的invokeBeanDefinitionRegistryPostProcessors办法 留神此办法执行后registry参数(BeanDefinitionRegistry)中的beanDefinitionMap会扫描到须要的bean信息 阐明此办法才是真正起到扫描作用的中央 重点!!! 持续进 兄弟们 往里进 ConfigurationClassPostProcessor#processConfigBeanDefinitions 两张图都是此办法 ps:代码太长 其中的这个parser.parse()就是真正解析的办法 ConfigurationClassParser#doProcessConfigurationClass到了 很近了 你要问我 我只能说 快到顶了 认真的同学应该曾经看进去了 图上的这个Set会获取@ComponentScan类扫描注解 而这个入参即为咱们的启动类Class 其中启动注解@SpringBootApplication中正蕴含了@CompentScan这个注解 所以此时这个Set中获取到了咱们的启动类 红线标注的这个中央持续走哦 componentScanAnnotationParser#parse中的scanner.doScan(StringUtils.toStringArray(basePackages)) 这里阐明一下这个basePackages因为咱们没有指定 所以默认是启动类所在的包门路 ps:这也是须要将启动类放到最外层包的起因 放外面的话无奈扫描到对应Bean ClassPathBeanDefinitionScanner#doScan 持续往里 还是那句 红线标注的中央 ClassPathScanningCandidateComponentProvider#scanCandidateComponents 好了 到站 请各位乘客下车吧 这个办法就是实在找到底层bean的中央 原理很简略 参数basePackage为咱们的包根门路 即启动类所在的门路 假如为com/juejin/drink 那么此办法会递归调用扫描com/juejin/drink下的所有类和目录 如果是须要注册的bean 那么放入new的LinkedHashSet中返回 通过如上步骤 程序会返回到PostProcessorRegistrationDelegate的invokeBeanDefinitionRegistryPostProcessors办法继续执行 但此时咱们的目标达到了 实际上SpringBoot就是通过@SpringBootApplication的@CompentScan注解 拿到启动类的包门路 最终去递归调用 获取到哪些是咱们标注了@Compent这些须要注册进容器的 此步骤是refresh办法的invokeBeanFactoryPostProcessors()中执行的 结语:本文只是简略的叙述了下Spring是如何将咱们的Bean加载到beanDefinitionMap中的 比较简单 不波及其余简单逻辑

February 27, 2023 · 1 min · jiezi

关于express:CompletableFuture实现异步编排

前言 为什么须要异步执行? 场景:电商零碎中获取一个残缺的商品信息可能分为以下几步:①获取商品根本信息 ②获取商品图片信息 ③获取商品促销流动信息 ④获取商品各种类的根本信息 等操作,如果应用串行形式去执行这些操作,假如每个操作执行1s,那么用户看到残缺的商品详情就须要4s的工夫,如果应用并行形式执行这些操作,可能只须要1s就能够实现。所以这就是异步执行的益处。 JDK5的Future接口 Future接口用于代表异步计算的后果,通过Future接口提供的办法能够查看异步计算是否执行实现,或者期待执行后果并获取执行后果,同时还能够勾销执行。列举Future接口的办法: get():获取工作执行后果,如果工作还没实现则会阻塞期待直到工作执行实现。如果工作被勾销则会抛出CancellationException异样,如果工作执行过程产生异样则会抛出ExecutionException异样,如果阻塞期待过程中被中断则会抛出InterruptedException异样。get(long timeout,Timeunit unit):带超时工夫的get()办法,如果阻塞期待过程中超时则会抛出TimeoutException异样。cancel():用于勾销异步工作的执行。如果异步工作曾经实现或者曾经被勾销,或者因为某些起因不能取消,则会返回false。如果工作还没有被执行,则会返回true并且异步工作不会被执行。如果工作曾经开始执行了然而还没有执行实现,若mayInterruptIfRunning为true,则会立刻中断执行工作的线程并返回true,若mayInterruptIfRunning为false,则会返回true且不会中断工作执行线程。isCanceled():判断工作是否被勾销,如果工作在完结(失常执行完结或者执行异样完结)前被勾销则返回true,否则返回false。isDone():判断工作是否曾经实现,如果实现则返回true,否则返回false。须要留神的是:工作执行过程中产生异样、工作被勾销也属于工作已实现,也会返回true。 应用Future接口和Callable接口实现异步执行:public static void main(String[] args) { // 疾速创立线程池ExecutorService executorService = Executors.newFixedThreadPool(4);// 获取商品根本信息(能够应用Lambda表达式简化Callable接口,这里为了便于察看不应用)Future<String> future1 = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { return "获取到商品根本信息"; }});// 获取商品图片信息Future<String> future2 = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { return "获取商品图片信息"; }});// 获取商品促销信息Future<String> future3 = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { return "获取商品促销信息"; }});// 获取商品各种类根本信息Future<String> future4 = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { return "获取商品各种类根本信息"; }}); // 获取后果try { System.out.println(future1.get()); System.out.println(future2.get()); System.out.println(future3.get()); System.out.println(future4.get());} catch (InterruptedException | ExecutionException e) { e.printStackTrace();}finally { executorService.shutdown();}}复制代码 ...

February 1, 2023 · 3 min · jiezi

关于express:express-router的初次使用

首先说下需要,mockApi指的就是模仿后盾,咱们在前台收回的申请能够不禁后盾来接管而是由咱们本人编写的模仿后盾来承受来初步验证前台的正确性也防止了前后台进度不一导致的开发上的工夫延误。 在之前的我的项目中,咱们所应用的mockApi的原理是拦挡由前台向后盾发动的申请,以做到不让后盾进行解决而是由咱们的mockApi进行解决。 而咱们当初用的是另一种解决办法——通过配置后缀来扭转其申请的地址,并且express router能够做到间接在前台接管url申请并进行自定义解决返回数据或是报错。 比方咱们能够设置为申请以api/结尾去申请后盾,以mockApi/结尾的申请去申请mockapi。 上面来说一下具体操作:此mockapi相当于是一个独立的node我的项目,能够npm run tart启动主体代码: import express, {Express, Request, Response} from 'express';import dotenv from 'dotenv';import bodyParser from 'body-parser';import md5 from 'md5';import {base64encode} from 'nodejs-base64';import {OaController} from './controller/oa.controller';const fs = require('fs');// 获取.env文件中的配置信息dotenv.config();// 初始化express, 端口,json 解析器const app: Express = express();const port = process.env.PORT;//咱们能够间接在此文件中书写接口并做出相应解决//辨认get办法,url:/api/hrm/resful/app.get('/', (req: Request, res: Response) => { res.send('Express + TypeScript Server');});//实体化rouerconst router = express.Router();//调用静态方法,解决对应的url并返回mock数据OaController.registerRouter(router);//设定url前缀app.use('/api/hrm/resful', router);app.listen(port, () => { console.log(`⚡️[server]: Server is running at http://localhost:${port}`);});从这里咱们能够看出这个我的项目很简略,咱们能够通过.env文件来配制我的项目启动的端口从而失常启动我的项目;.env: PORT=8088//静态方法,通过传入的express中的router来实现express解决url的性能import {Router, Request, Response} from 'express';export class OaController { private static instance: OaController; static registerRouter(router: Router): OaController { if (!OaController.instance) { OaController.instance = new OaController(); } router.post('/page, (res, req) => { OaController.instance.getHrmUserInfoWithPage(res, req); }); return OaController.instance; } //解决page申请,设定其响应 private page(res: Request, req: Response) { req.send({ code: 400, message: 'Internal Error' }) }}由此咱们能够看出通过express构建的mockApi更贴近于理论后盾,咱们能够对其进行更多的操作,如依据传入的数据进行更为实在的错误处理而不是简略的进行断言。 ...

November 1, 2022 · 1 min · jiezi

关于express:学习express从这里开始

一、express 是什么?Express 是一个简洁而灵便的 node.js Web利用框架,能够疾速地搭建一个性能残缺的网站。 二、装置express并创立我的项目通过 express-generator 创立带有根本配置的 express 我的项目,包含 路由(routes)、package.json、view(hbs模板)等,能够间接编写业务代码了。 # 1、装置工具npm install -g express-generator# 2、创立我的项目:learn-expressexpress --view=hbs ~/learn-express && cd ~/learn-express# 3、初始化我的项目npm install# 4、启动npm start# 5、拜访:http://localhost:3000/三、新增页面应用下面新建我的项目 learn-express,因为 routes、views 曾经配置结束,间接新建一个页面并用 http 的 get 办法获取,步骤如下: 采纳 vs code 关上下面我的项目。vs code 下载新建 routes/test.js 文件 var express = require('express');var router = express.Router();/* GET test page. */router.get('/', function(req, res, next) { res.render('test', { title:'测试页面' });});module.exports = router;新建 views/test.hbs 文件 <h1>{{title}}</h1>批改 app.js ,减少路由,找到对应中央减少上面内容 var testRouter = require('./routes/test');app.use('/test', testRouter);重启服务,即可通过 http://localhost:3000/test 拜访新增的页面。四、POST 提交页面应用 form 表单 提交数据,后端解决表单提交的数据。 ...

November 24, 2021 · 1 min · jiezi

关于express:express实现通过浏览器url地址访问音乐资源

成果实现某些音乐网站会提供一些音乐外链,以供用户拜访,听或下载music。不过可能明天这个外链还能用,今天就不能用了,“过期了”之类的。这篇文章记录了,应用nodejs框架express,实现一个简略的“mp3音乐资源服务器”性能。咱们先看一下效果图 浏览器url拜访到资源当前,Ctrl+S能够间接下载哦效果图有音乐资源返回音乐资源 没音乐资源返回文字提醒 代码实现app.js文件// 引入express插件包并生成一个实例appconst express = require('express')const app = express()// 应用body-parser中间件解析post申请主体app.use(express.urlencoded({ extended: false }))app.use(express.json())const Router = require('./router') // 引入分模块治理的路由// 路由分模块app.use(Router) // 在10000端口上启动后端服务app.listen(10000, (req,res) => { console.log('后端服务端口地址为:http://localhost:10000');})router.js文件次要看这个代码 const express = require('express') // 引入expressconst route = express.Router() // 实例化一个路由对象// 引入文件读取模块const fs = require('fs')// 动静路由传参形式,通过params获取动静参数route.get('/musicSrc/:fileName', (req, res) => { // console.log('获取文件名参数', req.params.fileName); // 拼接成残缺的文件名,这里假如对立应用mp3格局的音乐文件 let fileName = req.params.fileName // 破茧.mp3 try { // 存储一份音乐的门路,这里咱们在music文件夹外面寄存音乐资源 let mp3Url = './music/' + fileName // fs.statSync判断目录文件是否存在,不存在就会抛出异样,所以须要try catch捕捉一下 let stat = fs.statSync(mp3Url) // 设置申请头 res.writeHead(200, { // 有的话,就把对应的资源以流的模式返回去 'Content-Type': 'audio/mp3', // 类型为音频mp3格局 'Content-Length': stat.size, // 指定一下文件大小 "Accept-Ranges": "bytes" // 不加的话,前端google浏览器中音频无奈拖动 }) //创立可读流 let readStream = fs.createReadStream(mp3Url) // 将读取的后果以管道pipe流的形式返回给前端 readStream.pipe(res); } catch (error) { // 读取不到相应文件,就间接返回找不到即可 res.send('暂无此音乐数据') }})module.exports = route // 裸露给app.js方便管理目录结构图次要看左侧的music文件夹 ...

November 1, 2021 · 1 min · jiezi

关于express:expresswinston-库的学习笔记

库地址 express-winston 为 express.js 应用程序的申请和谬误记录提供中间件。 它应用“白名单”从申请和(0.2.x 中新增的)响应对象中抉择属性。 要应用 express-winston,您须要将以下内容增加到您的应用程序中: 在 package.json 中: { "dependencies": { "...": "...", "winston": "^3.0.0", "express-winston": "^4.0.4", "...": "..." }}server.js: var winston = require('winston'), expressWinston = require('express-winston');Request Logging应用 expressWinston.logger(options) 创立一个中间件来记录您的 HTTP 申请。 var router = require('./my-express-router'); app.use(expressWinston.logger({ transports: [ new winston.transports.Console() ], format: winston.format.combine( winston.format.colorize(), winston.format.json() ), meta: true, // optional: control whether you want to log the meta data about the request (default to true) msg: "HTTP {{req.method}} {{req.url}}", // optional: customize the default logging message. E.g. "{{res.statusCode}} {{req.method}} {{res.responseTime}}ms {{req.url}}" expressFormat: true, // Use the default Express/morgan request formatting. Enabling this will override any msg if true. Will only output colors with colorize set to true colorize: false, // Color the text and status code, using the Express/morgan color palette (text: gray, status: default green, 3XX cyan, 4XX yellow, 5XX red). ignoreRoute: function (req, res) { return false; } // optional: allows to skip some log messages based on request and/or response })); app.use(router); // notice how the router goes after the logger.参数定义: ...

October 27, 2021 · 5 min · jiezi

关于express:express-vue-搭建项目

创立目录为了方便管理我的项目,创立根目录,外部分成两局部,server 和 viewserver 用来搭建 express 框架view 用来搭建 vue 框架搭建 express 框架全局装置 express 脚手架,并检测是否装置胜利npm install express-generator -g检测是否装置胜利express --version在 server 文件夹中创立 express 我的项目express 项目名称目录构造 bin 目录下的 www 文件用来启动我的项目public 目录用来寄存动态文件router 目录用来寄存路由文件,对应资源和引入门路的问题view 目录用来寄存模板引擎文件app.js 文件是整个我的项目的入口文件 装置依赖、启动我的项目npm installnpm start默认拜访 localhost:3000如果呈现上面的内容,阐明启动胜利 初始化的脚手架中,router 目录下存在 user.js,用来退出本人的接口内容router.get('/', function(req, res, next) { res.send('respond with a resource');});在根目录 app.js 中,无关 user.js 的配置为var usersRouter = require('./routes/users');app.use('/users', usersRouter);此时在浏览器中拜访路由 users,如果呈现 respond with a resource 阐明脚手架搭建胜利 搭建 vue 框架全局装置脚手架npm install -g @vue/cli检测是否装置胜利vue -V在 view 文件夹中创立 vue 我的项目vue create 项目名称目录构造 ...

September 15, 2021 · 2 min · jiezi

关于express:express中使用nodexlsx插件下载excel表格

node-xlsx是一个轻量级的excel插件,下载导出excel根本的性能这个插件都能实现,本文记录一下express框架中应用node-xlsx插件下载excel表格的步骤。状况一、读取本地文件并返回前端excel流文件这种状况实用于下载excel模板场景,毕竟模板是固定的内容,咱们在代码的文件夹中寄存一个固定的excel模板,读取并返回即可。第一步,必定是要下载安装这个插件npm i node-xlsx第二步,在对应代码中引入这个插件const xlsx = require('node-xlsx')第三步,就是在对应的路由url中写对应代码,代码如下:// excel导出下载模板接口route.get("/exportExcel", (req, res) => { // 首先,读取本地excel模板文件,并解析成node-xlsx插件须要的数据格式, // (比方我的表格文件在代码中的excel文件夹下)要引入fs文件模块能力读取哦 const dataByParse = xlsx.parse(fs.readFileSync('./excel/统计模板.xlsx')); /* 打印进去的数据是一个数组,数组中的每一项(每一个对象)都是一个sheet数据,name属性指定的是每一个sheet的名字 data属性是一个数组,数组中寄存的是表格对应每个sheet的数据,data数组中的第一项是“表头”的数据,也能够了解为是 第一行的数据,前面的每一项就是对应每一行“表体”的数据,具体格局,后续也会举例。 */ console.log("解析数据格式",dataByParse); // 最初一步,应用xlsx插件自带的build办法将解析后的数据转换成为excel表格(buffer模式的流文件) // 以流文件的模式返回给前端,前端接管解析下载即可 res.send(xlsx.build(dataByParse))})node-xlsx须要的数据格式举例子比方这样的数据格式,咱们看一下数据结构 let excelData = [ // 第一个sheet内容 { name:"我是sheet1", // 给第一个sheet指名字 data:[ // 留神,这里是一个二维数组 ["姓名","年龄","他乡","备注"], // 第一行 ["孙悟空","500","花果山","人送外号斗战败佛"], // 第二行 ["猪八戒","88","高老庄","天蓬元帅"], // 第三行 ] }, // 第二个sheet内容 { name:"我是sheet2", // 给第二个sheet指名字 data:[ ["城市","国家","人口","经济程度"], // 同上 ["上海","中国","14亿","越来越好"], ["伦敦","英国","7000万","还行"], ["华盛顿","美国","3.4亿","凑活"] ] } ]上述数据格式对应效果图很显然,数据结构和对应导出的excel后果都是对应的 ...

September 1, 2021 · 1 min · jiezi

关于express:express基本使用

1.express基于nodejs平台、疾速、凋谢、极简的Web开发框架,官网地址(中文版),官网地址 1.根本应用下载expressnpm install express --save引入express模块 let express = require('express');构建服务实例 // 构建服务实例 相当于 http.createServer();let app = express();接管服务端申请 // 当服务端收到 get申请 / 的时候,执行回调函数app.get('/',(req,res) => { res.send('Hello World');})绑定端口 // 绑定端口 相当于http.listen()app.listen(3000,()=> { console.log('server is running...');})残缺代码 let express = require('express');// 构建服务实例 相当于 http.createServer();let app = express();// 公开指定目录,则能够通过/public间接进行拜访其文件夹内的内容,能够写多个,灵便应用app.use('/public/',express.static('./public/'));// 当服务端收到 get申请 / 的时候,执行回调函数app.get('/',(req,res) => { // 在express中能够间接通过req.query来获取查问字符串参数 console.log(res.query); res.send('Hello World');})// 绑定端口 相当于http.listen()app.listen(3000,()=> { console.log('server is running...');})如果拜访其余的门路下的内容,express框架默认会解决为404,并显示相干的提示信息。如果要写多个门路下申请的解决,则能够写多个app.get(),不用像nodejs原生写http服务一样本人判断。同时如果要对某个门路下的资源进行凋谢,能够采取以下的代码进行配置 // 公开指定目录,则能够通过/public间接进行拜访其文件夹内的内容,能够写多个,灵便应用// 第一个参数配置客户端能怎么样进行拜访,第二个参数是服务器端绝对于以后文件的文件门路app.use('/public/',express.static('./public/'));

March 11, 2021 · 1 min · jiezi

关于express:vuepress打包项目如何在express框架渲染

如果要在 express 我的项目上加一个 vuepress 写的文档应如何渲染? Vuepress 是 Vue 驱动的动态网站生成器1、.vuepress/config.js 批改 base 配置指定动态资源目录,如:test目录 base: "/test/",2、打包去缓存配置 package.json "scripts": { "build": "vuepress build docs --no-cache"},3、把打包目录 dist 复制到 express 我的项目 public 目录下 4、路由配置 router.get('/test', function(req, res, next) { res.render('test');});视图目录:views/test.html 5、把 dist 目录下的 index.html 重命名为 test.html 而后剪切替换 views/test.html 即可 拜访:http://localhost/test 欢送关注:技术开发分享录

March 10, 2021 · 1 min · jiezi

关于express:第四代Express框架koa简介

简介相熟Spring MVC的敌人应该都分明Spring MVC是基于servlet的代码框架,这是最传统的web框架。而后在Spring5中引入了Spring WebFlux,这是基于reactive-netty的异步IO框架。 同样的,nodejs在最后的Express 3根底上倒退起来了异步的koa框架。koa应用了promises和aysnc来防止JS中的回调天堂,并且简化了错误处理。 明天咱们要来介绍一下这个优良的nodejs框架koa。 koa和expresskoa不再应用nodejs的req和res,而是封装了本人的ctx.request和ctx.response。 express能够看做是nodejs的一个利用框架,而koa则能够看成是nodejs 的http模块的形象。 和express提供了Middleware,Routing,Templating,Sending Files和JSONP等个性不同的是,koa的性能很繁多,如果你想应用其余的一些性能比方routing,sending files等性能,能够应用koa的第三方中间件。 koa并不是来替换express的,就像spring webFlux并不是用来替换spring MVC的。koa只是用Promises改写了控制流,并且防止了回调天堂,并提供了更好的异样解决机制。 koa应用介绍koa须要node v7.6.0+版本来反对ES2015和async function。 咱们看一个最最简略的koa利用: const Koa = require('koa');const app = module.exports = new Koa();app.use(async function(ctx) { ctx.body = 'Hello World';});if (!module.parent) app.listen(3000);koa应用程序就是一个蕴含了很多个中间件的对象,这些中间件将会依照相似stack的执行程序一个相应request。 中间件的级联关系koa.use中传入的是一个function,咱们也能够称之为中间件。 koa能够use很多个中间件,举个例子: const Koa = require('koa');const app = new Koa();app.use(async (ctx, next) => { await next(); console.log('log3');});app.use(async (ctx, next) => { await next(); console.log('log2');});app.use(async ctx => { console.log('log3');});app.listen(3000);下面的例子中,咱们调用了屡次next,只有咱们调用next,调用链就会传递到下一个中间件进行解决,始终到某个中间件不再调用next为止。 ...

November 30, 2020 · 2 min · jiezi

关于express:express中异步函数异常捕获

在express中时应用 Async/await 编写异步代码时,每个 async 函数都要包裹在try/catch中,代码量多了看着冗余不优雅,express又不像koa的异步机制能够订阅全局的error事件,为了解决这个问题,须要写个捕捉异步函数异样的中间件。 uncaughtException开始能想到的必定是try/catch了,然而也想过是否应用nodejs提供的uncaughtException事件,在全局捕捉异样,例如上面的代码: process.on("uncaughtException", (err) => console.log("uncaught Exception"));const asyncError=()=>{ throw new Error("some Error");}asyncError();asyncError办法外面抛出的异样会被 uncaughtException订阅,然而在异步函数中,并没走到 uncaughtException,还是会抛出异样: process.on("uncaughtException", (err) => console.log("uncaught Exception"));const asyncError=()=>{ throw new Error("some Error");}(async ()=>{ // 抛出异样 asyncError();})()而且Promise.reject也没走到uncaughtException外面: const asyncError=()=>{ return Promise.reject("some error")}(async ()=>{ // 抛出异样 await asyncError();})()所以在express中应用nodejs提供的uncaughtException解决异步谬误不太适合,一方面没法捕捉和定位上下文谬误,另一方面也没法将谬误异样提供给中间件函数解决 解决思路要解决express中的异步函数谬误,最好的办法当然是编写解决异样的中间件了,try/catch开路,包裹中间件办法,catch到的异样间接交给next函数解决,代码如下: const asyncHandler = fn =>{ return (req,res,next)=>{ try{ fn(req,res,next) }catch(next) }}module.exports = asyncHandler;接下来,在异步函数中引入中间件解决: app.use(asyncHandler(async(req, res, next) => { await authenticate(req); next();}));app.get('/async', asyncHandler(async(req, res) => { const result = await request('http://example.com'); res.end(result);}));应用asyncHandler办法包裹的async/await函数,如果呈现谬误就会被Error-handling中间件捕捉了 ...

November 27, 2020 · 1 min · jiezi

关于express:express-学习笔记慕课

(本人温习用)一、 创立脚手架sudo npm i express-generator -gmkdir express-clicd express-cliexpress express-testnpm intsallnpm start 二、第二步(不晓得什么题目了) nodemon监听代码文件变动,随时重启cross-env 不用放心平台设置或应用环境变量npm i nodemon cross-env --save-dev bin:编译的可执行文件www 为了提供一个http的服务。 publick 、views 前端用。 // package.json "dev": "cross-env NODE_ENV=dev nodemon ./bin/www"三、介绍express的入口文件 各个插件的作用。 var cookieParser = require('cookie-parser'); 解析cookievar logger = require('morgan'); 记录日志用 app 本次http 申请的实例 var express = require('express');var router = express.Router();/* GET home page. */router.get('/', function(req, res, next) { res.render('index', { title: 'Express' });});module.exports = router;四、演示如何解决路由新建路由文件user.js, var express = require('express');var router = express.Router();/* GET users listing. */router.post('/login', function (req, res, next) { const { username, password } = req.body; res.json({ error: 0, data: { username, password } })});module.exports = router;poatman 申请形式: ...

November 10, 2020 · 1 min · jiezi

关于express:三步法解析Express源码

关注公众号“执鸢者”,获取大量教学视频及私人总结面筋并进入业余交换群.在抖音上有幸看到一个程序员讲述如何浏览源代码,次要分为三步:领悟思维、把握设计、领会细节。 领悟思维:只需领会作者设计框架的初衷和目标把握设计:只需领会代码的接口和抽象类以及宏观的设计领会细节:是基于顶层的形象接口设计,逐步开展代码的画卷基于上述三步法,急不可待的拿Express开刀了。本次源码解析有什么不到位的中央各位读者能够在上面留言,咱们一起交换。 一、领悟思维在Express中文网上,介绍Express是基于Node.js平台,疾速、凋谢、极简的Web开发框架。在这句话外面能够失去解读出以下几点含意: Express是基于Node.js平台,并且具备疾速、极简的特点,阐明其初衷就是为了通过扩大Node的性能来进步开发效率。凋谢的特点阐明该框架不会对开发者过多的限度,能够自在的施展设想进行性能的扩大。Express是Web开发框架,阐明作者的定位就是为了更加不便的帮忙咱们解决HTTP的申请和响应。二、把握设计了解了作者设计的思维,上面从源码目录、外围设计原理及形象接口三个层面来对Express进行整体的把握。2.1 源码目录如下所示是Express的源码目录,相比拟来说还是比较简单的。├─application.js---创立Express利用后可间接调用的api均在此处(外围)<br/>├─express.js---入口文件,创立一个Express利用<br/>├─request.js---丰盛了http中request实例上的性能<br/>├─response.js---丰盛了http中response实例上的性能<br/>├─utils.js---工具函数<br/>├─view.js---与模板渲染相干的内容<br/>├─router---与路由相干的内容(外围)<br/>| ├─index.js<br/>| ├─layer.js<br/>| └route.js<br/>├─middleware---与中间件相干的内容<br/>| ├─init.js---会将新减少在request和response新减少的性能挂载到原始申请的request和response的原型上<br/>| └query.js---将申请url中的query局部增加到request的query属性上<br/> 2.2 形象接口对源码的目录构造有了肯定理解,上面利用UML类图对该零碎各个模块的依赖关系进一步理解,为后续源码剖析打好根底。 2.3 设计原理这一部分是整个Express框架的外围,下图是整个框架的运行流程,一看是不是很懵逼,为了搞清楚这一部分,须要明确四个概念:Application、Router、Layer、Route。 为了明确上述四个概念,先引入一段代码const express = require('./express');const res = require('./response');const app = express();app.get('/test1', (req, res, next) => { console.log('one'); next();}, (req, res) => { console.log('two'); res.end('two');})app.get('/test2', (req, res, next) => { console.log('three'); next();}, (req, res) => { console.log('four'); res.end('four');})app.listen(3000);Application示意一个Express利用,通过express()即可进行创立。Router<路由零碎,用于调度整个零碎的运行,在上述代码中该路由零碎蕴含app.get('/test1',……)和app.get('/test2',……)两大部分Layer代表一层,对于上述代码中app.get('/test1',……)和app.get('/test2',……)都能够成为一个LayerRoute 一个Layer中会有多个处理函数的状况,这多个处理函数形成了Route,而Route中的每一个函数又成为Route中的Layer。对于上述代码中,app.get('/test1',……)中的两个函数形成一个Route,每个函数又是Route中的Layer。理解完上述概念后,联合该幅图,就大略能对整个流程有了直观感触。首先启动服务,而后客户端发动了http://localhost:3000/test2的申请,该过程应该如何运行呢? 启动服务时会顺次执行程序,将该路由零碎中的门路、申请办法、处理函数进行存储(这些信息依据肯定构造存储在Router、Layer和Route中)对相应的地址进行监听,期待申请达到。申请达到,首先依据申请的path去从上到下进行匹配,门路匹配正确则进入该Layer,否则跳出该Layer。若匹配到该Layer,则进行申请形式的匹配,若匹配形式匹配正确,则执行该对应Route中的函数。上述解释的比较简单,后续会在细节局部进一步论述。 三、领会细节通过上述对Express设计原理的剖析,上面将从两个方面做进一步的源码解读,上面流程图是一个常见的Express我的项目的过程,首先会进行app实例初始化、而后调用一系列中间件,最初建设监听。对于整个工程的运行来说,次要分为两个阶段:初始化阶段、申请解决阶段,上面将以app.get()为例来论述一下该外围细节。 3.1 初始化阶段上面利用app.get()这个路由来理解一下工程的初始化阶段。 首先来看一下app.get()的内容(源代码中app.get()是通过遍历methods的形式产生) app.get = function(path){ // …… this.lazyrouter(); var route = this._router.route(path); route.get.apply(route, slice.call(arguments, 1)); return this;};在app.lazyrouter()会实现router的实例化过程 ...

October 17, 2020 · 3 min · jiezi

关于express:建立一个PDF转docx的在线服务

首先,构建一个typeScript的express利用: package.json { "name": "pdf2docx", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "nodemon ./src/index.ts", "build": "tsc --project ./", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "codetyphon", "license": "ISC", "dependencies": { "@types/multer": "^1.4.4", "cors": "^2.8.5", "express": "^4.17.1", "multer": "^1.4.2", "winax": "^1.20.0" }, "devDependencies": { "@types/cors": "^2.8.7", "@types/express": "^4.17.8", "@types/node": "^14.11.2", "nodemon": "^2.0.4", "ts-node": "^9.0.0", "tslint": "^6.1.3", "typescript": "^4.0.3" }}tsconfig.json { "compilerOptions": { "target": "es6", "module": "commonjs", "rootDir": "./src", "outDir": "./build", "esModuleInterop": true, "strict": true }}srcindex.ts ...

October 14, 2020 · 3 min · jiezi