Hi there 👋

🤔 我是一名后端程序猿,主要专注于 Java Web 应用程序开发,平时也会使用 Vue 写写前端。对于编码和思考如何把代码转化为高效、可靠的软件充满热情。
📫 除了编程之外,我对开源项目非常感兴趣,虽然没有参与过开源项目的贡献和维护,但一直在努力学习和积累经验,希望有一天能够为开源项目做出自己的贡献。同时,在工作中充分利用开源社区资源,提高编码技能和解决问题的能力。
🌱 目前我居住在一个美丽的城市,这里有着浓郁的文化氛围和美食文化,也有着现代化的技术环境和创新精神。我感到非常幸运能够在这里工作和生活,享受着快乐而充实的时光。

Git Worktree Cheatsheet (Worktree 速查表)

docs: https://git-scm.com/docs/git-worktree 01 基本用法 git worktree add <path> [<branch>] # 在指定路径创建一个新的工作区,可选地检出指定分支 git worktree list # 列出所有工作区及其状态 git worktree prune # 清理无效的工作区引用 02 工作区管理 git worktree remove <path> # 移除指定的工作区(需要先清理工作区内的未提交更改) git worktree move <source> <destination> # 移动或重命名现有工作区 git worktree lock <path> # 锁定工作区,防止误操作 git worktree unlock <path> # 解锁工作区 03 分支操作 git worktree add -b <new-branch> <path> # 基于当前分支创建新的分支并检出到新工作区 git checkout -b <new-branch> --work-tree=<path> # 在现有工作区中创建并切换到新分支 git branch -D <branch> --work-tree=<path> # 删除指定工作区中的分支(需确保工作区干净) 04 高级使用 git worktree add --detach <path> # 创建一个分离头指针的工作区 git worktree add --no-checkout <path> # 创建工作区但不检出文件 git worktree add -f <path> # 强制创建工作区,即使目标目录非空 git worktree add --track <path> <remote>/<branch> # 克隆远程分支并跟踪 05 最佳实践 使用有意义的路径名称来标识每个工作区的目的。 定期运行 git worktree prune 来清除不再存在的工作区引用。 在多个工作区之间切换时,确保没有未提交的更改。 对于长期存在的特性分支,可以考虑使用独立的工作区。 使用 --detach 创建分离头指针的工作区来进行实验性开发,完成后可以通过创建新分支来保存更改。 在团队环境中使用工作区时,确保团队成员了解工作区的存在,并在共享仓库前解决任何冲突。 如果工作区位于不同的物理位置,使用 --no-checkout 选项以避免不必要的文件复制。 当需要同时处理多个特性或任务时,利用工作区提高效率。 对于大型项目,考虑将不同模块或组件放在不同的工作区中开发。 使用 git worktree lock 和 git worktree unlock 来保护重要工作区免受意外操作的影响。 示例:从当前分支检出新的 worktree,修复 bug,提交,然后清除工作区 ...

November 28, 2024 · 2 min · 306 words · Spring

使用 Java 把 RGB 转为 CMYK

00 前言 最近接到了一个需求,要把 RGB 的图片转为 CMYK 的颜色模式,用于印刷。 网上对于 RGB 转为 CMYK 的资料较少,Java 也没有内置的方法。主流方法有两种,一种是手搓强转,另一种则是借助 ICC 文件来转换。 该需求对于分辨率、物理尺寸有一定的要求,且原途径就是通过 PS 处理的,正好用同样的 ICC 文件转换,能达到相对一致的颜色要求。 01 色彩空间转换 1.1 关键概念 RGB 模式是以色光三原色为基础建立的色彩模式,红、绿、蓝,是电脑、手机、投影仪、电视等屏幕显示的最佳颜色模式。 CMYK(青色、品红色、黄色、黑色)是印刷材料的色彩空间。CMY 是 3 种印刷油墨名称的首字母:青色 Cyan、洋红色 Magenta、黄色 Yellow,由于目前制造工艺还不能造出高纯度的油墨,CMY 相加实际得到的是深灰色或深褐色,故加入纯黑色。 ICC Profile 色彩特性文件,是一组用来描述色彩空间的特性的数据集合,因由国际色彩联盟(ICC)主持制定其规范而得名。RGB 转为 CMYK 就是把 RGB 值转为 CMYK 值。 像素(Pixel)是指构成图片的小色点。 分辨率(单位 DPI)是指每英寸(Inch)上的像素数量,++1 英寸 = 2.54 厘米++。 像素相同时,分辨率越高则像素密度越大,实际打印尺寸越小,图像也越细腻。 1.2 转换步骤 首先,引入 JAI(Java Advanced Imaging),最新版 1.1.3,这个库好几年没更新了: <dependency> <groupId>javax.media.jai</groupId> <artifactId>com.springsource.javax.media.jai.codec</artifactId> <version>1.1.3</version> </dependency> <!-- 这个库只用到了 TIFF 的静态变量,可以不引入 --> <dependency> <groupId>com.github.jai-imageio</groupId> <artifactId>jai-imageio-core</artifactId> <version>1.4.0</version> </dependency> 然后,加载 ICC 文件,这里选择 JapanColor2001Coated.icc(按需选择即可),安装 PS 就有,在 C:\Program Files (x86)\Common Files\Adobe\Color\Profiles\Recommended 目录下,路径不一样找不到的搜一下就可以。 ...

August 1, 2024 · 4 min · 756 words · Spring

SpringBoot 关于文件的上传与下载

碎碎念 在 Springboot 中,跨服务的文件传输需要考虑性能、一致性、安全性等问题。 对于 Excel 文件的上传下载,是否在对外服务层进行解析和封装会更好呢? 对于其他类型的文件,可以考虑独立出一个文件服务,以实现服务解耦和更好的水平扩展。 01 SpringBoot 图片上传 普通文件上传 普通的文件上传,直接使用 MultipartFile 类型声明参数即可: @RestController public class FileUploadController { @PostMapping("/upload") public ResponseEntity<String> handleFileUpload( @RequestParam("file") MultipartFile file, @RequestParam("param1") String param1, @RequestParam("param2") String param2) { if (file.isEmpty()) { return ResponseEntity.badRequest().body("请选择文件上传"); } // 这里可以添加文件上传的业务逻辑,比如保存文件到服务器 return ResponseEntity.ok("文件上传成功"); } } 如果是多文件上传,则使用 MultipartFile[] 数组。 如果参数过多,可以使用 @SpringQueryMap 把参数放在类里面,这是 OpenFeign 提供的类似 @QueryMap 功能,支持把 Query 参数封装到对象中: ...

April 6, 2024 · 3 min · 550 words · Spring

Git 常用命令

01 储藏功能(Stash) git stash list [<log-options>] git stash push(原 git stash save) 1.1 git stash 保存部分文件 git stash是git stash push命令省略写法 git stash push指令本身就支持指定文件。 $ git stash push <file1> <file2> <file3> [file4 ...] $ git stash push -m "测试" src/java/**/*.java Help.java OK.java 1.2 git stash -u 保存未跟踪文件 $ git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] [-u|--include-untracked] * [-a|--all] [<message>] 02 恢复功能(Reset) 2.1 git reset 取消 Add 误 add 多个文件,只撤销部分文件 $ git reset HEAD /path/to/dir/or/file $ git reset HEAD szy-admin/src/test/com/szy/web/SysUserServiceTest.java Unstaged changes after reset: M szy-analysis/src/main/resources/mapper/analysis/fbt/FbtRequestLogMapper.xml M szy-system/src/main/resources/mapper/system/SysUserMapper.xml 2.2 git reset 取消 commit # 取消提交,回复修改的文件 $ git reset --soft HEAD^ # 取消提交,丢弃修改 $ git reset --hard HEAD^ # 回退上上上一个版本 $ git reset --soft HEAD~3 03 标签(Tag) 3.1 查询 # 列出所有 $ git tag # 搜索符合模式的Tag $ git tag -l 'v0.1.*'' 3.2 打标签 # 轻量标签 $ git tag v0.1.2 # 附带说明的标签 $ git tag -a v0.1.2 -m "0.1.2 测试版本" # 打在指定 commit 上,只需在上面两个命令后加上 commit id $ git tag v0.1 88772sa00 3.3 删除标签 $ git tag -d v0.1.2 3.4 推送标签 # 将v0.1.2 Tag提交到git服务器 $ git push origin v0.1.2 # 将本地所有Tag一次性提交到git服务器 $ git push origin --tags 3.5 获取最新 tag Shell sort 排序 获取当前分支标签:--merged BRANCH_NAME/commitId,不指定默认 HDEA(默认当前分支) Shell 排序:sort -t:指定分隔符 -n:依照数值的大小排序 -r:以相反的顺序来排序 -k:指定需要排序的列 $ git tag --merged test | sort -t. -n | tail -n 1 git 自带 --srot=<key> 参数 version:refname:tag 被当成版本号排序,同 <v:refname> $ git tag --sort=version:refname --merged | tail -n 1 04 分支操作 4.1 分支基本操作 # 查看本地分支 > git branch # 查看远程分支 > git branch -r # 创建分支但不切换 > git branch <branch-name> # 切换到指定分支 > git checkout <branch-name> # 创建并切换到新分支(以当前所在分支为基础) > git checkout -b <branch-name> # git 2.23+ > git switch -c <branch-name> # 删除本地分支 > git branch -d <branch-name> # 强制删除本地分支(即使有未合并的更改) > git branch -D <branch-name> # 重命名本地分支 > git branch -m <new-branch-name> # 从指定分支新建分支并切换(或 switch -c) > git checkout -b <branch-name> a123213cid Switched to a new branch <branch-name> # 注意:这里不能指定分支名称,否则会把新分支关联到该分支,相当于该分支的别名 # 等于是直接在操作原分支,如果指定的是 master,会直接操作 master > git switch -c hotfix/hello origin/master branch 'hotfix/hello' set up to track 'origin/master'. Switched to a new branch 'hotfix/hello' 4.2 分支合并 合并提交,并生成一个合并提交 不能保持 master 分支干净,但是保持了所有的 commit history,大多数情况下都是不好的,个别情况挺好 $ git merge <branch-name> 压缩合并,多个提交合并成一个提交 以保持 master 分支干净,但是 master 中 author 都是 maintainer,而不是原 owner $ git merge <branch-name> --squash # 这时候,修改的文件在当前分支都变成未提交 # 下一步,提交这些记录,生成一个新的提交(可能要解决冲突) $ git commit -m "feat: xxx" 变基合并,可以尽可能保持 master 分支干净整洁,并且易于识别 author 变基:在要合并的分支 git rebase -i 要合并进去的目标分支 合并:在目标分支合并 git merge 要合并的分支 变基其实就是找到两个分支共同的祖先,然后在当前分支上合并从共同祖先到现在的所有 commit ce6ecf4 - (HEAD -> master, test) add sth.3 (8 minutes ago) \<zqq> (test commit, master merged) 82f08db - add sth.2 (29 minutes ago) \<zqq> (test commit) 3d9a1f4 - add sth. (35 minutes ago) \<zqq> (test commit) f620135 - init (37 minutes ago) \<zqq> References [1] 魔地主. Git tag 给当前分支打标签. https://blog.csdn.net/u013802160/article/details/55103186 , 2017-02-14. ...

December 5, 2023 · 3 min · 432 words · Spring

Tomcat 停止后无法启动,“Tomcat appears to still be running with PID ...”

问题是什么呢? 在停止 Tomcat 后,无法再次启动。 尝试使用 catalina.sh 启动时出现如下警告: [R@K tomcat/bin]$ ./catalina.sh start Using CATALINA_BASE: /app/tomcat Using CATALINA_HOME: /app/tomcat Using CATALINA_TMPDIR: /app/tomcat/temp Using JRE_HOME: /app/j2sdk1.8.0/jre Using CLASSPATH: /app/tomcat/bin/bootstrap.jar:/app/tomcat/bin/tomcat-juli.jar Using CATALINA_OPTS: -javaagent:/app/skywalking/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=springx-web -Dskywalking.collector.backend_service=192.168.1.122:11800 Using CATALINA_PID: /app/tomcat/bin/CATALINA_PID Existing PID file found during start. Tomcat appears to still be running with PID 22832. Start aborted. # 这里说 Tomcat 已经运行了,PID 为 22832 If the following process is not a Tomcat process, remove the PID file and try again: UID PID PPID C STIME TTY TIME CMD # 可是这里并没有任何进程 输出的日志显示,PID 已存在。根据部分 Linux 应用的习惯可知,Tomcat 启动后,会将其 PID 记录在一个文件中,再次启动时会主动检测该文件,以判断是否重复启动。 ...

September 4, 2023 · 1 min · 185 words · Spring

使用 Docker-Compose 搭建 Jenkins

00 碎碎念 为什么使用 Docker 去搭建 Jenkins 呢? 主要原因是个人频繁切换环境,有时候在本地虚拟机玩,有时候会在云服务器上折腾,渐感被自己折磨过多了,因此希望能够创建一个配置文件,以便一键启动并快速方便地使用。另外,自己经常在其他地方装环境,公司的服务也比较老,一但要迁移,用 Docker 就很方便。所以,使用 Docker 是很适合的。 网上那么多一样的文章,为什么要写这篇呢? 虽然说这篇文章是作为笔记的,但是因为自己在使用网上的方法安装的时候,遇到几个问题,尝试了很多方法才成功,所以想要记录一下,以备不时之需。 01 Docker Compose 安装 以下是测试过的,能正常部署和使用 Jenkins 的 Docker Compose 配置,部分参数请按需调整。 version: '3.9' services: jenkins: # 镜像选择了 jdk17 最新版,可自行选择 image: jenkins/jenkins:jdk17 container_name: jenkins # 重启策略:除非手动停止,否则出错会无限重启 restart: unless-stopped # 指定用户 uid:gid(`用户id`:`宿主机的docker组id`,跟文件权限有关) user: 1000:995 ports: # 8080 为 Jenkins 的 Web 端口 - 9001:8080 # 50000 为代理节点与主服务器的通信端口? - 50001:50000 volumes: # 同步宿主机的时间 - /etc/timezone:/etc/timezone - /etc/localtime:/etc/localtime # Jenkins 数据目录映射出来,方面操作和备份 - .jenkins_home:/var/jenkins_home # 把宿主机的 docker 和 docker-compose 给 Jenkins 使用,这样可以直接在 Jenkins 内部打镜像,并直接操作容器 - /usr/bin/docker:/usr/bin/docker - /var/run/docker.sock:/var/run/docker.sock - /usr/local/bin/docker-compose:/usr/local/bin/docker-compose 使用 Docker Compose 直接启动即可: ...

August 21, 2023 · 3 min · 610 words · Spring

如何为终端或 Git 设置代理?

碎碎念 由于网络原因,我们不得不使用一些手段,以疏通或者加速它。 在 CMD/PowerShell 终端配置代理,可以允许整个命令行得到代理。 使用 git config 配置代理,则仅支持 git 自身获得代理。 CMD 设置代理 Windows 的 cmd 使用 set 命令来配置: > set http_proxy=http://127.0.0.1:1080 # Or > set https_proxy=https://127.0.0.1:1080 这种方式,可以进行终端全局的代理。 Windows 还有 PowerShell 终端,也是类似的。 PowerShell 设置代理 PowerShell 配置方式比较特殊,但同样是设置全局变量 HTTP_PROXY/HTTPS_PROXY(不区分大小写): > $env:HTTP_PROXY="http://127.0.0.1:1080" # Or > $env:HTTPS_PROXY="https://127.0.0.1:1080" 注: 终端配置的方式,每次关闭之后,都要重新配置。除了写一段初始化脚本,还可以直接配置 git 的全局代理。 Git Bash 设置代理 在 Git Bash 中,可以通过 git config 设置 HTTP 代理: > git config --global http.proxy "http://127.0.0.1:1080" # Or > git config --global https.proxy "https://127.0.0.1:1080" 但是,这种方式仅适用于 HTTP/HTTPS,不适用于 SSH 方式(即 git clone git@github.com:username/repo.git)。 ...

July 22, 2023 · 2 min · 248 words · Spring

使用 Docker-Compose 搭建 Maven 私服 Nexus

01 搭建私服的初衷 1.1 为什么搭建私服? 使用 Maven 管理项目依赖时,通常会从 Maven 仓库拉取第三方依赖,此时只需要配置公共仓库源即可。 但是,如果需要使用公司内部依赖,需要同时使用第三方依赖和私有依赖,这就需要搭建私服,用以存储私有组件库。 搭建私服,可以实现如下功能: 共享私有依赖,保护敏感信息 保存依赖版本,避免依赖变化或升级受影响 提升代理速读,缓存常用依赖到私服 自定义配置策略、规则、权限等 2.2 为什么选择 Nexus ? 常见仓库管理有如下几种: Nexus Repository Manager:Nexus 是一个广泛使用的 Maven 仓库管理器,它提供了丰富的功能,包括支持 Maven、Gradle、Ivy 等构建工具,具有强大的缓存和代理能力,以及用户权限控制、部署规则等功能。 Artifactory:Artifactory 是另一个流行的 Maven 仓库管理器,它支持多种构建工具,提供了企业级的功能,例如高度可定制的权限控制、智能缓存和复制、跨数据中心复制、虚拟仓库等。 Archiva:Archiva 是一个轻量级的 Maven 仓库管理器,它提供了基本的 Maven 仓库功能,例如部署、下载和缓存。虽然功能相对较少,但易于安装和使用,适用于小型项目或简单的私有仓库需求。 选择 Nexus 一来是满足需求,需要的功能都包含,二来是比较熟悉。其他管理系统也都可以,视情况选择即可。 02 使用 Docker-Compose 搭建 2.1 Docker-Compose 搭建 首先,编写 docker-compose.yaml: version: '3.9' services: nexus: image: sonatype/nexus3:latest #image: sonatype/nexus3:3.56.0 container_name: nexus3 restart: always ports: - 10240:8081 volumes: - ./nexus-data:/nexus-data 然后,创建目录 ./nexus-data 映射数据(不需要备份的就不需要啦),因为需要配置目录权限,所以这里要手动创建目录: ...

June 30, 2023 · 1 min · 193 words · Spring

MySQL 用户数据权限配置

碎碎念 对于普通的系统开发,很少会对数据进行细粒度的权限控制。 但是,在某些需要提供给第三方数据的场景中,要么会直接提供基础数据,要么会提供仅有部分权限的账户。如果是直接提供账户,就需要对账户进行比较精细的权限限制。 在 mysql 库中,有很多的系统配置表。其中,user 表中存储的是全局的权限,更细粒度的权限分别存储在其他表中。 01 权限 虽然在上一篇《MySQL 用户管理:创建、权限配置和删除》 中提到,修改权限可以直接修改表(update 操作),但是,有些权限涉及其他表,直接修改表不方便,也不建议。 当然,MySQL 已经为权限提供了 GRANT 和 REVOKE 命令,用于授权和回收权限。 常见权限名称如下,使用别名授权,就不需要直接 update 数据库了: 权限别名 权限列名 权限范围 SELECT select_priv Tables or columns INSERT insert_priv Tables or columns UPDATE update_priv Tables or columns DELETE delete_priv Tables CREATE create_priv Databases, tables, or indexes DROP drop_priv Databases, tables, or views INDEX index_priv Tables … … … 具体参考官方文档:6.2.2 Privileges Provided by MySQL 1.1 全局权限(user) 全局权限存储在 mysql.user 表中,作用于 MySQL 的所有数据库,除了 root,新建用户默认都没有权限(都是 N) ...

June 17, 2023 · 6 min · 1164 words · Spring

MySQL 用户管理:创建、权限配置和删除

碎碎念 遇到过的很多小伙伴,无论在开发环境,还是在正式环境,都是“一键 ROOT”。包括但不限于 Linux 服务器、MySQL 数据库或者其他中间件,一律使用 ROOT 账户登录使用。 虽然这么做,可以减少权限等其他不重要的问题,省去很多麻烦,但是,我觉得这个习惯并不好。如果是正式环境,应该尽量避免这种情况。而且,真正需要自己去配置这些的时候,整个过程都会磕磕绊绊。 作为一个爱折腾的小码农,还是忍不住要弄它几下的。 01 创建用户 1.1 查询用户 MySQL 所有的用户信息,均保存在数据库名为 mysql 的 user 表中。 mysql> select user, host, plugin from mysql.user ; +------------------+-----------+-----------------------+ | user | host | plugin | +------------------+-----------+-----------------------+ | root | % | mysql_native_password | | mysql.infoschema | localhost | caching_sha2_password | | mysql.session | localhost | caching_sha2_password | | mysql.sys | localhost | caching_sha2_password | | root | localhost | mysql_native_password | +------------------+-----------+-----------------------+ 从上面的结果可以看到,除了几个内置的账户,默认只有 root 用户。 ...

June 16, 2023 · 4 min · 665 words · Spring