【前端自动化部署】,Devops,CI/CD
DevOps
提到Jenkins
,想到的第一个概念就是 CI/CD
在这之前应该再了解一个概念。
DevOps Development
和 Operations
的组合,是一种方法论,并不特指某种技术或者工具。DevOps
是一种重视 Dev 开发人员和 Ops 运维人员之间沟通、协作的流程。通过自动化的软件交付,使软件的构建,测试,发布更加的快捷、稳定、可靠。
CI
CI
的英文名称是Continuous Integration
,中文翻译为:持续集成。
试想软件在开发过程中,需要不断的提交,合并进行单元测试和发布测试版本等等,这一过程是痛苦的。持续集成CI是在源代码变更后自动检测、拉取、构建的过程。
CD
CD 对应两个概念 持续交付Continuous Delivery
持续部署Continuous Deployment
持续交付
提交交付顾名思义是要拿出点东西的。在 CI 的自动化流程阶段后,运维团队可以快速、轻松地将应用部署到生产环境中或发布给最终使用的用户。
可以理解为是将代码集成到共有仓库(如Git)中,并自动进行构建、测试和验证,以确保团队成员的代码都能够统一的集成在一起,同时减少冲突和问题。
从前端的角度考虑,在某些情况下肯定是不能直接通过自动化的方式将最终的 build 结果直接扔到生产机的。持续交互就是可持续性交付供生产使用的的最终 build。最后通过运维或者后端小伙伴进行部署。
持续部署
作为持续交付的延伸,持续部署可以自动将应用发布到生产环境。
是在持续集成的基础上,对代码进行自动化构建、测试和发布,并可以进行快速、可靠地部署。持续部署是进一步自动化持续交付的过程,通过自动化流水线将程序代码的更改自动部署到生产环境中。
CI/CD 工具选择
- Jenkins:一个开源的、可扩展的CI/CD工具,支持多种编程语言和版本控制系统,具有丰富的插件生态系统和广泛的应用支持。
- GitHub Actions:GitHub 是一个基于 Git 的代码托管平台,也提供了 CI/CD 的功能,可以通过 GitHub Actions 实现自动化构建、测试和部署。
- GitLab CI/CD: GitLab是基于Git的代码托管平台,版本控制平台内置的CI/CD工具,与GitLab紧密集成,提供一体化的代码管理和持续交付功能。
- CircleCI:CircleCI 是一个云端的 CI/CD 工具,支持多种编程语言和版本控制系统,使用简单,适合小型团队。
- Travis CI:Travis CI 是一个云端的 CI/CD 工具,支持多种编程语言和版本控制系统,使用简单,适合小型团队。
Jenkins 安装
示例服务器为 阿里云 CentOS 服务器。安全组中增加 8080 端口 Jenkins 默认占用
Jenkins 安装大体分两种方式,一种使用 Docker 另一种则是直接安装,示例选择后者。不管使用哪种方式安装,最终使用层面都是一样的。
# 下载 Jenkins 资源
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo
# 获取并导入信任 的包制作者的秘钥
sudo rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key
# 升级 yum 源中的所有包
sudo yum upgrade
# Jenkins 依赖于 java 所以需要安装 JDK
sudo yum install java-11-openjdk
# 安装 Jenkins
sudo yum install jenkins
如果最终 Jenkins 没有找到包而导致没有安装成功,检查第一步和第二部执行结果并重新执行。
可以使用systemctl
命令管理 Jenkins 服务 systemctl
# 启动 Jenkins 服务
systemctl start jenkins
# 重启 Jenkins 服务
systemctl restart jenkins
# 停止 Jenkins 服务
systemctl stop jenkins
# 查看 Jenkins 服务状态
systemctl status jenkins
启动服务后访问服务器地址 + 8080 端口,Jenkins 默认为 8080 端口。
Jenkins 使用及 Freestyle 任务构建
首次进入使用 cat /var/lib/jenkins/secrets/initialAdminPassword
查看密码。
随后进入插件安装页面,暂时安装系统推荐插件即可。
然后创建用户
构建目标:拉取 github 代码
点击 新建 Item 创建一个 Freestyle Project
在 源码管理 处选择 git ,输入仓库地址,点击添加。
输入 github 账号和密码,这里的密码有时候可能会出现问题,可以使用 token github
如何生成 token ?
配置只是一方面,同时服务器也要具备 git 环境。 yum install git
构建目标:部署到本机
部署前端项目肯定是离不开 nginx 的。 yum install nginx
。
安装完成后同样可以使用 systemctl
命令管理 nginx 服务。
nginx 具体配置这里就不说了。本示例项目中,静态文件托管目录为 /usr/share/nginx/html/dist
。
接着来到 Jenkins 这里。想要部署前端项目还需要依赖一个 Node 环境,需要在 Manage Jenkins -> Manage Plugins 在可选插件中搜索 nodejs 选择对应插件进行安装,安装完成后需要重启才会生效。
然后到 系统管理 -> 全局工具配置 中配置 Node (吐槽:没有安装任何插件时系统管理以及其子页面全是英文,安装完插件后又变成了中文。这国际化不知道是系统原因还是它的原因)
随后去修改刚才创建的任务。在 构建环境 中会多出一个选项 Provide Node & npm bin/ folder to PATH
勾选即可。然后在 构建 中选择 增加构建步骤 -> 执行 shell 输入打包发布相关的命令。Jenkins 会逐行执行。
npm install yarn -gyarn installyarn build
# 打包 build 后的文件
tar -zcvf dist.tar.gz dist/
# 删除 build 后的文件
rm -rf dist/
# 移动 build 后的压缩包到 nginx 托管目录下
sudo mv dist.tar.gz /usr/share/nginx/html
# 进入托管目录下
cd /usr/share/nginx/html
# 解压
sudo tar -zxcf dist.tar.gz
# 删除压缩包
sudo rm -rf dist.tar.gz
由于项目构建时是在 Jenkins 的工作目录下执行脚本,会出现权限问题。导致即使使用了 sudo 还会出现类似以下错误。
We trust you have received the usual lecture from the local SystemAdministrator. It usually boils down to these three things: #1) Respect the privacy of others. #2) Think before you type. #3) With great power comes great responsibility
解决方案:在 /etc/sudoers
文件中增加 jenkins ALL=(ALL) NOPASSWD:ALL
表示在执行 sudo 时不需要输入密码。
如果不使用 sudo 则会出现以下错误。
xxxxxxx: Permission denied
解决方案:修改 /lib/systemed/system/jenkins.service
文件。将 User=jenkins
修改为 User=root
,表示给 Jenkins 赋权限。修改配置文件后记得重启服务。
构建的过程中还可能出现以下错误
ERROR: Error fetching remote repo 'origin'
解决方案:由于需要构建的代码在 github 上面,这种错误表示拉取代码失败了,重试几次就可以了。
工作目录
上面提到一个很重要的概念就是 工作目录 在上面的 shell 默认就是在这里执行的。工作目录是由两部分组成。
/var/lib/jenkins/workspace/
类似于前缀吧。web-deploy
这个其实是上面构建任务的名字。
总结:Jenkins 的执行目录是 /var/lib/jenkins/workspace/web-deploy
。也就是说输入的每一条命令都是在这里面执行的。(搞清楚定位能避免好多问题,特别是前端的部署,就是打包,移动,解压很容易搞错路径。)
构建目标:侦听 git 提交到指定分支进行构建
-
来到 Jenkins 中选择 系统管理 -> 系统配置 找到 Jenkins URL 将其复制。
-
随后在尾部添加
github-webhook/
尾部斜杠一定不要丢。整体结构大致为http://192.168.0.1:8080/github-webhook/
-
登录 github 需要集成的项目中添加 webhook。在 Payload URL 中将上述内容填入。
- 然后修改 Jenkins 任务配置 构建触发器中选择
GitHub hook trigger for GITScm polling
由于在上面的源码管理中已经指定了main
分支,此时如果这个分支的代码有改动就会触发自动构建。
构建目标:部署到目标主机
在真实的开发场景中,Jenkins 几乎不会和前端资源放到一个服务器。大多数情况下 Jenkins 所处的服务器环境就是一个工具用的服务器,放置了一些公司中常用的工具。因此构建到指定的服务器也至关重要。
-
系统管理 -> 插件管理 搜索 Publish Over SSH 进行安装。
-
然后在系统管理 -> 系统配置中找到
Publish over SSH
点击新增,再点击高级,然后选中Use password authentication, or use a different key
完成后可点击右下角Test Confirguration
进行测试。 -
继续修改构建任务。先修改原有的构建脚本。因为要发布到远程,所以原有的发布命令要进行去除。
npm install yarn -gyarn installyarn build
# 只打包,然后删除文件夹
tar -zcvf dist.tar.gz dist/rm -rf dist/
- 选择构建后操作 -> Send build artifacts over SSH
Rransfer Set Source files
:要上传到目标服务器的文件。它是一个相对路径,相对于 Jenkins 的工作目录 由于上面的 shell 执行之后在工作目录中只有一个压缩包,so 直接写一个文件名即可。Remove prefix
:去前缀。假设此时打包文件在/var/lib/jenkins/workspace/web-deploy/assets/dist.tar.gz
,那么Rransfer Set Source files
则应该为assets/dist.tar.gz
,此时Remove prefix
配置为assets/
则可以去除这个前缀,否则会在目标服务中创建 assets 。Remote directory
:远程的静态资源托管目录。由于配置服务器默认为 /,所以usr/share/nginx/html/
不用以 / 开头。Exec command
:远程机执行 shell,由于配置服务器默认为 /, 所以 工作目录也是以 / 开始。
执行成功后查看执行日志会有类似以下结果:
SSH: Connecting from host [iZuf6dwyzch3wm3imzxgqfZ]SSH: Connecting with configuration [aliyun-dev] ...SSH: EXEC: completed after 202 msSSH: Disconnecting configuration [aliyun-dev] ...
# 如果 Transferred 0 file 则需要查看配置的路径是否正确。表示文件并没有被移动到远程主机中。
SSH: Transferred 1 file(s)Finished: SUCCESS
构建目标:钉钉机器人通知
-
系统管理 -> 插件管理 搜索 DingTalk 进行安装。文档
-
钉钉群创建机器人。钉钉群 -> 只能群助手 -> 添加机器人 -> 自定义
- 定义机器人名字和关键字,创建完成后先将 webhook 中的内容复制。
- Jenkins 中 系统管理 -> 系统配置 -> 钉钉 -> 新增 配置完成后可点击右下角进行测试。
- 修改构建任务配置。
- 通知人:
atAll
勾选后 @ 不到准确的人。😂。输入框内可填写需要被 @ 人的手机号,多个换行。 - 自定义内容:支持 markdown 写法,可以使用一些环境变量。
192.168.0.1:8080/env-vars.html/
- 实现默认
@
执行人
- 构建成功
Pipline 构建
上一章节中着重介绍了如何构建 freestyle 的任务,但是 Jenkins 远不止于此。在本章开始之前强烈建议阅读文档[7],重点关注流水线相关内容。
新建任务 -> 选择流水线 其他内容可以都不用管,只关注流水线 有两种选择,演示就选择第一种。
直接在 Jenkins 中书写配置。
在项目的 Jenkinsfile
配置文件中写配置。
在正式开始之前应该了解 Jenkins Pipline 的基础概念。
pipeline { agent any // 在任何可用的代理上,执行流水线或它的任何阶段。 stages { stage('Build') { // 定义 "Build" 阶段。 steps { // 执行与 "Build" 阶段相关的步骤。 } } stage('Deploy') { // 定义 "Deploy" 阶段。 steps { // 执行与 "Deploy" 阶段相关的步骤。 } } }
}
- pipline:定义流水线整个结构,可以看做是根节点
- agent:指示 Jenkins 为整个流水线分配一个执行器,比如可以配置 Docker
- stages:对整个 CI 流的包裹,个人认为没多大用,还必须得有。
- stage:可以理解为是对某一个环节的描述。注意:参数就是描述内容,可以是任何内容。不要想歪了只能传递 Build Deploy 这些。
- steps:描述了 stage 中的步骤,可以存在多个。
了解到这里还是不够的。流水线入门[8] 流水线语法参考[9]
Pipline 复刻 Freestyle
这里先直接把配置贴出来。后续结合内容在进行分析。
// 自定义 钉钉插件 的 错误信息和成功信息
def successText = [""" ### 新的构建信息,请注意查收""",""" ${env.JOB_BASE_NAME}任务构建<font color=green>成功</font> ,点击查看[构建任务 #${env.BUILD_NUMBER}](http://106.14.185.47:8080/job/${env.JOB_BASE_NAME}/${env.BUILD_NUMBER}/)"""
]
def failureText = [""" ### 新的构建信息,请注意查收""",""" ${env.JOB_BASE_NAME}任务构建<font color=red>失败</font> ,点击查看[构建任务 #${env.BUILD_NUMBER}](http://106.14.185.47:8080/job/${env.JOB_BASE_NAME}/${env.BUILD_NUMBER}/)"""]// 1,侦听 github push 事件
properties([pipelineTriggers([githubPush()])])
pipeline
{agent any // 环境变量定义。 environment{GIT_REPO = 'http://github.com/vue-ts-vite-temp.git'}stages{// 2,拉取 github 代码,通过 GitSCM 侦听 push 事件。 stage('Pull code'){steps{checkout([$class: 'GitSCM',branches: [[name: '*/main']],extensions: [],userRemoteConfigs: [[credentialsId:'381325e4-0f9c-41ea-b5f6-02f8ea2a475a',url: env.GIT_REPO]],changelog: true,poll: true,])}}stage('Install and build'){steps{// 3,前面安装过的 nodejs 插件使用 nodejs('v14.19.0'){sh 'npm install yarn -g'sh 'yarn install'sh 'yarn build'}}}stage('Pack'){steps{sh 'tar -zcvf dist.tar.gz dist/'sh 'rm -rf dist/'}}stage('Deploy'){steps{// 4,前面下载的 Publish Over SSH 插件的使用 sshPublisher(publishers: [sshPublisherDesc(configName: 'aliyun-dev',transfers: [sshTransfer(cleanRemote: false,excludes: '',execCommand: ''' cd / usr / share / nginx /html /tar - zxvf dist.tar.gz rm -rf dist.tar.gz ''', execTimeout: 120000,flatten: false,makeEmptyDirs: false,noDefaultExcludes: false,patternSeparator: '[, ]+',remoteDirectory:'/usr/share/nginx/html/',remoteDirectorySDF: false,removePrefix: '',sourceFiles:'dist.tar.gz')],usePromotionTimestamp: false,useWorkspaceInPromotion: false,verbose: false)])}}}post{success{// 5,DingTalk 插件的使用。 dingtalk(robot: '1314',type: 'ACTION_CARD',title: 'Jenkins构建提醒',text: successText,btns: [[title: '控制台',actionUrl: 'http://106.14.185.11:8080/'],[title: '项目预览',actionUrl: 'http://github.com/'],],at: [])}failure{dingtalk(robot: '1314',type: 'ACTION_CARD',title: 'Jenkins构建提醒',text: failureText,btns: [[title: '控制台',actionUrl: 'http://106.14.185.11:8080/'],[title: '项目预览',actionUrl: 'http://github.com/'],],at: [] // 这里是手机号多个之间,隔开 )}}
}
这么多内容手写无疑是很难受的,好在 Jenkins 提供了一些帮助工具。访问地址为:Jenkins地址 + /job + 当前任务 + /pipeline-syntax/
,例如:http://localhost:8080/job/dev-deploy/pipeline-syntax/
,或者进入任务构建页面,点击流水线语法进入
进入该页面后请熟读并背诵以下三项。重点放到第一项。
回头看上面的脚本注释都带有序号。根据注释序号开始解释。
- 在片段生成器中选择
properties: Set job properties
生成代码片段。由于只是使用了git hook trigger
所以要对生成的片段稍作修改。
- 如果不是为了侦听
github push 选择 git: Git
即可,但现在应该选择checkout: Check out from version control
,随后填写信息生成代码即可。
3. 选择 nodejs: Provide Node & npm bin/folder to Path
4. 选择 sshPublisher: Send build artifacts over SSH
,像上面流水线一样配置之后直接生成代码即可。
5. DingTalk 文档
总结: 通过插件生成的代码,稍作组合就成为了完整的配置。但整体难度还是要略高于 Freestyle 任务。毕竟生成的代码有部分也不是拿来即用的,并且 Pipline 基本语法一定要有所掌握。不然生成的代码都不晓得放到哪里合适。
相关文章:

【前端自动化部署】,Devops,CI/CD
DevOps 提到Jenkins,想到的第一个概念就是 CI/CD 在这之前应该再了解一个概念。 DevOps Development 和 Operations 的组合,是一种方法论,并不特指某种技术或者工具。DevOps 是一种重视 Dev 开发人员和 Ops 运维人员之间沟通、协作的流程。…...

【C语言】探讨蕴藏在表达式求解中的因素
🚩纸上得来终觉浅, 绝知此事要躬行。 🌟主页:June-Frost 🚀专栏:C语言 🔥该篇将探讨 操作符 和 类型转换 对表达式求解的影响。 目录: 隐式类型转换算术转换操作符的属性❤️ 结语 隐…...
【Flutter】Flutter 使用 video_player 播放视频
【Flutter】Flutter 使用 video_player 播放视频 文章目录 一、前言二、video_player 简介三、安装和配置四、基本使用五、完整示例 六、高级功能七、总结 一、前言 大家好,我是小雨青年,今天我要和大家分享一款非常实用的 Flutter 包——video_player。…...
如何使用 ChatGPT 快速制作播客和其他长篇内容
使用ChatGPT快速制作播客和其他长篇内容是一个高效且具有一定创造性的过程。以下是一些详细的步骤和技巧,以帮助你充分利用ChatGPT来制作高质量的内容。 一、准备阶段 确定主题或话题:在开始制作之前,你需要明确你的播客或长篇内容将聚焦的主…...

JavaScript基础语法02——JS书写位置
哈喽,大家好,我是雷工! 今天继续学习JavaScript基础语法,JS的书写位置,俗话说:好记性不如烂笔头,边学边记,方便回顾。 1、行内JavaScript 代码写在标签内部 示例: <…...
LInux快捷命令
切换到行头:ctrla 或者 ctrlhome 切换到行尾:ctrale 或者 ctrlend 光标向左切换一个单词:ctrl← 光标向右切换一个单词:ctrl→ 历史命令搜索:history 历史命令匹配第一条执行:!x (x表示历史命令…...

jvm的内存划分区域
jvm划分5个区域: java虚拟机栈、本地方法栈、堆、程序计数器、方法区。 各个区各自的作用: 1.本地方法栈:用于管理本地方法的调用,里面并没有我们写的代码逻辑,其由native修饰,由 C 语言实现。 2.程序计数…...

什么是数据中心IP,优缺点是什么?
如果根据拥有者或者说发送地址来分类的话,可以将代理分为三类:数据中心ip,住宅ip,移动ip 本文我们来了解数据中心ip的原理以及他们的优势劣势,才能选择适合自己的代理。 一、什么是数据中心ip代理? 数据中心ip是由数据中心拥有…...

模块化与组件化:开发中的双剑合璧
引言:模块化与组件化的重要性 在现代软件开发中,随着项目规模的增长和技术的复杂性增加,如何有效地组织和管理代码变得越来越重要。模块化与组件化作为两种主要的代码组织方法,为开发者提供了有效的工具,帮助他们创建…...

【C++初阶】list的常见使用操作
👦个人主页:Weraphael ✍🏻作者简介:目前学习C和算法 ✈️专栏:C航路 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞…...

排序之插入排序
文章目录 前言一、直接插入排序1、基本思想2、直接插入排序的代码实现3、直接插入排序总结 二、希尔排序1、希尔排序基本思想2、希尔排序的代码实现3、希尔排序时间复杂度 前言 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大…...

c# - - - 安装.net core sdk
如图,安装的是.Net Core 2.2版本 查看安装成功...

Golang Gorm 高级查询之where + find
插入测试数据 package mainimport ("fmt""gorm.io/driver/mysql""gorm.io/gorm" )type Student struct {ID int64Name string gorm:"size:6"Age intEmail *string }func (*Student) TableName() string {return "student&q…...
【LeetCode】30 天 Pandas 挑战
一、笔记 1.对某列进行筛选 df[(df[column1]条件1) | (df[column2]条件2) & (df[column3]条件3)][[columns]]真题: (一)条件筛选——1.大的国家(一)条件筛选——2.可回收且低脂的产品(一)…...
头歌MYSQL——课后作业2 数据表中数据的插入、修改和删除
第1关:数据表中插入一条记录,对指定字段赋值 任务描述 本关任务:在library数据库的reader数据表中插入一条数据 姓名xm为林团团,电话号码dhhm为13507311234,其余字段取默认值 显示数据表的所有数据 为了完成本关任务,…...

Maven的profiles多环境配置
一个项目通常都会有多个不同的运行环境,例如开发环境,测试环境、生产环境等。而不同环境的构建过程很可能是不同的,例如数据源配置、插件、以及依赖的版本等。每次将项目部署到不同的环境时,都需要修改相应的配置,这样…...
go 协程
golang中的并发是函数相互独立运行的能力。Goroutines是并发运行的函数。Golang提供了 如何实现go协程 只需要在函数前面加上go即可 go task()package mainimport ("fmt""time" )func show(msg string) {for i : 0; i < 5; i {fmt.Printf("msg: …...

【python爬虫案例】用python爬豆瓣读书TOP250排行榜!
文章目录 一、爬虫对象-豆瓣读书TOP250二、python爬虫代码讲解三、讲解视频四、完整源码 一、爬虫对象-豆瓣读书TOP250 您好,我是 马哥python说 ,一名10年程序猿。 今天我们分享一期python爬虫案例讲解。爬取对象是,豆瓣读书TOP250排行榜数…...
Qt中 gui 模块和 widgets 模块的区别
1. gui 模块提供了基本的图形系统抽象层,包括QPaintDevice、QPainter等类,这些类构成了Qt的绘图基础。 2. widgets 模块在 gui 模块的基础上,提供了完整的桌面级用户界面控件,如按钮、列表、滑块等。这些控件继承自更基础的图形类。 3. gui 模块是更底层的图形功能,widgets模…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...

在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...