uniapp 微信小程序文件操作
下载文件
直接请求文件接口文件打开将会失败,例如xlsx打开将会无法解析
1 | reportApi.getIncome().then(res => { |
使用uniapp提供的downloadFile函数
1 | uni.downloadFile({ |
打开文件
1 | function viewDoc(filePath) { |
直接请求文件接口文件打开将会失败,例如xlsx打开将会无法解析
1 | reportApi.getIncome().then(res => { |
使用uniapp提供的downloadFile函数
1 | uni.downloadFile({ |
1 | function viewDoc(filePath) { |
本文档分析 JVM Metaspace 区域的 OutOfMemoryError 问题,包括处理方法、JVM 内存区域分类以及 OOM 发生原因。
Metaspace(元数据空间)是 Java 8 引入的概念,替代了永久代(PermGen)。它存储类的元数据信息,如:
1 | # 设置初始大小 |
1 | # 查看当前 Metaspace 使用情况 |
结果分析:
MC:Metaspace 容量MU:Metaspace 使用量 M:使用率,如果持续 > 90% 就有问题CCS:压缩类空间容量CCSU:压缩类空间使用量1 | # 获取详细类加载信息 |
重点关注:
1 | # 生成堆转储文件 |
使用 MAT(Memory Analyzer Tool)分析:
关键指标:
1 | # 启动时添加JVM参数来跟踪类加载 |
查找动态生成类:
1 | # 在类加载日志中查找动态生成的类 |
1 | # 查看所有jar包中的类数量 |
重点检查的库:
1 | // 添加JVM参数监控类卸载 |
排查脚本示例:
1 | #!/bin/bash |
检查代码中的问题模式:
1 | // 1. 检查是否有类似代码(容易导致类泄漏) |
日志排查命令:
1 | # 在应用日志中查找类加载相关异常 |
正常情况:
异常情况:
紧急情况处理:
1 | # 临时增加 Metaspace 大小 |
堆内内存是受 JVM 堆空间管理的内存区域。
特点:
-Xmx 参数限制包含区域:
堆外内存是不受 JVM 堆空间管理的内存区域。
特点:
-Xmx 参数限制包含区域:
常见使用场景:
1 | // Direct ByteBuffer 使用堆外内存 |
堆内 vs 堆外内存对比:
| 特性 | 堆内内存 | 堆外内存 |
|---|---|---|
| GC 管理 | 是 | 否 |
| 大小限制 | -Xmx | 物理内存 |
| 访问速度 | 较慢 | 较快 |
| 内存泄漏风险 | 低 | 高 |
| 典型用途 | 对象存储 | 缓存、IO缓冲区 |
1 | java.lang.OutOfMemoryError: Java heap space |
发生原因:
1 | java.lang.OutOfMemoryError: Metaspace |
发生原因:
1 | java.lang.OutOfMemoryError: Code cache |
发生原因:
1 | java.lang.OutOfMemoryError: Direct buffer memory |
发生原因:
1 | java.lang.StackOverflowError |
发生原因:
| 区域 | OOM 场景 | 常见原因 |
|---|---|---|
| Heap | 对象分配失败 | 内存泄漏、大对象、配置不当 |
| Metaspace | 类元数据存储失败 | 类加载器泄漏、动态类生成 |
| Code Cache | JIT 编译空间不足 | 热点代码过多、缓存配置小 |
| Direct Memory | 堆外内存不足 | NIO 使用不当、直接内存泄漏 |
| Stack | 栈空间耗尽 | 递归过深、线程栈配置小 |
1 | // 应用可能有异常处理机制 |
1 | -XX:MetaspaceSize=128m |
Metaspace OOM 是 JVM 内存管理中的常见问题,理解其发生机制和处理方法对于 Java 应用的稳定运行至关重要。通过合理的配置、监控和代码实践,可以有效预防和解决此类问题。
本文档整理了从Java 8到Java 21中Web系统开发必须掌握的关键特性,按照学习优先级进行分类。
为什么重要: 流式编程是现代Java开发的标准方式,极大提升代码简洁性和可读性。
1 | // 传统写法 |
应用场景:
为什么重要: 避免NPE(空指针异常),让代码更安全。
1 | // Service层安全处理 |
为什么重要: 大幅简化DTO/VO类的编写,减少80%样板代码。
传统DTO类写法:
1 | // 传统的DTO类 - 需要大量样板代码 |
Records写法 - 一行搞定:
1 | // Record类 - 自动生成所有样板代码 |
特点:
限制:
1 | // 1. 简单DTO |
适合使用Records的场景:
不适合使用Records的场景:
为什么重要: 原生HTTP客户端,无需依赖第三方库。
1 | // 微服务间通信 |
为什么重要: 提高代码可读性,减少冗余类型声明。
1 | // 简化变量声明 |
为什么重要: 优雅处理多行字符串,特别是JSON和SQL。
1 | // 复杂SQL查询 |
为什么重要: 处理高并发请求,特别适合I/O密集型Web应用。
1 | // 异步Controller |
为什么重要: 更好的API设计,限制继承层次。
1 | // 支付方式建模 |
为什么重要: 更优雅的条件处理,减少if-else链。
1 | // 处理不同支付方式 |
1 | // 用户DTO |
最后更新时间:2025-07-18
适用版本:Java 8 - Java 21
1 | public class TestThread { |
在java中执行异步任务需要新建一个Thread线程,然后通过Runnable接口实现一个任务,最后将任务通过参数的方式传递给Thread类。
1 | public class TestThread { |
上面这种方式获取异步执行结果是有问题的,输出集合的大小可能为0,这是因为在输出结果的时候异步任务可能还没开始执行。
为了能够在获取到异步任务执行的结果后再继续之后的代码,我们可以使用CountDownLatch或者FutureTask,因为本篇内容是讲Future,所以仅说明Future的使用方法。
为了解决Runnable不能适配没有返回值的问题,jdk使用适配器模式为我们实现了FutureTask类,FutureTask实现了Runnable接口和Future接口
1 | public class TestThread { |
通过调用FutureTask的get()方法,当前线程会阻塞等待异步线程执行完成并将结果返回。
了解了FutureTask之后,我们知道FutureTask.get()方法会阻塞当前线程,等待异步执行结果返回。我们来看下面这个例子。
1 | public class TestThread { |
String pdfFont1 = getFontFromPdf(task1.get());在执行该代码的时候会等待task1执行完成在继续后面的代码,那么如果task2先执行完成的话就要干等着。
这时候我们可以将getFontFromPdf方法也放到task中如下,这样就能避免这个问题。
1 | // 异步任务 |
另外,我们还能通过CompetableFuture来解决这个问题,代码如下
1 | public class TestThread { |
CompletableFuture通过thenApplyAsync方法追加了对方法结果的二次处理,CompletableFuture是jdk8的新特性,设计更符合lamda的流编程。
将linux的cas项目部署到windows上,访问https://cas.example.com:8443显示如下页面。

误认为和项目配置有关系
cas-template有个配置文件在/etc/cas/config/cas.properties,配置信息如下。
1 | cas.server.name: https://cas.example.org:8443 |
这里配置的域名是在集群的时候才有用的,单机并没有意义,而我误以为不能访问是因为这个配置没有生效。
确认https是正常的
因为我的启动方式是./gradlew run通过内置的tomcat启动,所以https证书是通过springboot进行管理的,application.yml的配置没有问题。
1 | server: |
代理可能影响
关掉clash代理,果然可以了。可以在Clash For Windows中Settings > System Proxy > Bypass Domain中添加不走代理的列表。
本文档详细说明如何在 Knife4j(基于 SpringDoc OpenAPI 3)中配置全局 Header 参数,使其在 API 文档页面的”Authorize”对话框中显示,实现统一的接口认证和自定义请求头管理。
有些Docker镜像的生成有时候分为多个阶段,如:
可以看到构建阶段需要依赖于maven,运行阶段需要依赖于tomcat。为了减小镜像大小,理想的镜像是仅包含运行环境的tomcat而不包含编译打包环境maven的镜像。
这时候有两种方式可以实现该目的。
方式一:使用gitlab runner的Docker excutor构建
1 | stages: |
通过runner启动一个maven容器,在maven容器中将java源代码转为jar,然后使用dind技术将jar放入tomcat镜像,这时候就得到tomcat + jar的镜像。
方式二:使用docker的多阶段构建
1 | # 构建阶段 |
将生成jar逻辑放在Dockerfile中,先用maven镜像生成jar,得到一个maven + jar的镜像,然后使用tomcat镜像将刚刚生成的镜像中的jar复制过来,得到一个tomcat + jar的镜像。
二者的区别就是生成jar的逻辑是写在gitlab的.gitlab-ci.yml中还是写在Dockerfile中。
我个人倾向写在Dockerfile中,主要有一下几点考量。
Docker build命令构建镜像本文记录了将Hexo博客从传统Docker部署方案迁移至CNB(Cloud Native Build)自动部署平台的完整过程,包括遇到的问题和解决方案。
原先使用GitLab CI/CD + Docker的自动化部署方式:
构建环境:基于GitLab CI/CD的自动化构建
构建流程:
部署方式:通过GitLab CI/CD自动部署到服务器Docker环境
1 | FROM node |
1 | # .gitlab-ci.yml |
CNB(Cloud Native Build)是腾讯云提供的云原生构建平台,具有以下优势:
1 | # .cnb.yml配置文件 |
问题描述:
1 | YAMLException: bad indentation of a mapping entry |
原因:sed命令中包含特殊字符和中文,YAML解析器无法正确处理
解决方案:
1 | # 错误写法 |
使用双引号包裹整个命令,内部使用转义字符处理特殊字符。
问题描述:
1 | rewrite or internal redirection cycle while internally redirecting to "/index.html" |
原因:Hexo站点缺少必要的页面(categories、tags、about),导致Next主题出现内部重定向循环
解决方案:
在构建过程中添加页面初始化步骤:
1 | hexo new page categories |
问题描述:构建时找不到配置文件或主题文件
解决方案:
调整构建步骤顺序,确保在初始化页面前先复制所有必要文件:
问题描述:rsync部署时需要SSH私钥认证
解决方案:
${SSH_PRIVATE_KEY}引用私钥问题描述:
1 | "/app/chlm-nginx/html/blog/index.html" is not found (2: No such file or directory) |
原因:nginx配置中使用的路径与docker-compose.yml中的挂载路径不一致
1 | # docker-compose.yml |
但nginx配置中使用了错误路径:
1 | root /app/chlm-nginx/html/blog; # 错误路径 |
解决方案:
修正nginx配置中的路径:
1 | location / { |
问题描述:
1 | directory index of "/home/chlm/html/blog/categories/" is forbidden |
原因:访问目录时nginx尝试列出目录内容而不是查找index.html
解决方案:
使用正确的try_files配置:
1 | location / { |
问题描述:
1 | rewrite or internal redirection cycle while internally redirecting to "/index.html" |
原因:不当的try_files配置导致无限重定向
常见错误配置:
1 | # 错误:会导致循环重定向 |
正确配置:
1 | # 正确:避免循环重定向 |
最终优化配置:
1 | location / { |
注意:不要添加静态资源过滤规则,会与其他服务冲突:
1 | # ❌ 错误:不要添加这样的配置 |
原因:
root指令:
1 | # 访问 /blog/index.html 会查找 /var/www/blog/index.html |
alias指令:
1 | # 访问 /blog/index.html 会查找 /var/www/hexo/index.html |
选择原则:
rootalias作用:按顺序尝试多个文件/URI,直到找到存在的文件或执行fallback
语法:try_files file1 file2 ... uri;
常见用法场景:
静态网站路径重写(如Hexo博客):
1 | try_files $uri $uri/ $uri/index.html =404; |
SPA应用路由支持:
1 | try_files $uri $uri/ /index.html; |
多语言站点回退:
1 | try_files $uri $uri/ /zh/index.html /en/index.html =404; |
缓存穿透处理:
1 | try_files $uri @backend; |
必须使用try_files的场景:
静态网站生成器(Hexo/Hugo/Jekyll等):
/categories/ /categories/index.html单页应用(SPA):
/user/profile/index.html伪静态URL:
/article/123/article.php?id=123不需要try_files的场景:
1 | try_files $uri $uri/ $uri/index.html =404; |
原因分析:
URL美化:Hexo生成美化的URL结构
https://blog.com/categories//categories/index.html目录结构映射:
/ → /index.html/categories/ → /categories/index.html/archives/2025/ → /archives/2025/index.html兼容性处理:同时支持带trailing slash和不带的URL
查看目录结构:
1 | # 安装tree工具 |
nginx日志分析:
1 | # 实时查看错误日志 |
try_files调试:
1 | # 临时添加调试日志 |
通过将Hexo博客迁移至CNB平台,实现了:
迁移过程中主要的挑战在于YAML配置语法和Hexo页面初始化,通过合适的转义和构建步骤安排成功解决。CNB平台为静态博客提供了一个高效、稳定的自动化部署解决方案。
在gitlab runner写自动发布脚本的时候,有如下这段代码,git clone一直显示没有权限,然而使用相同密钥的宿主机是没有问题的,只有而runner容器可以ssh却不能clone。
1 | build: |
经过一番折腾,检查了下宿主机know_hosts文件,发现了端倪,git连接的地址加上了端口,所以know_host需要添加一个带端口的记录。
1 | build: |
适合场景:命令还未启动
1 | ./test & |
适合场景: 命令已运行
1 | # 运行命令 |
这两种方式存在的问题是会话关闭后可能会导致命令停止。
步骤1:系统发送Sighup信号给控制进程(通常为shell);
步骤2:控制进程停止,发送Sighup到前台进程和后台进程;
步骤3:子进程收到信号;
步骤4:子进程关闭当前进程;
编写一个实时输出的脚本
1 | vim test |
1 | #!/bin/bash |
1 | chmod +x test |
另外启动一个控制台实时查看log文件是否有更新
1 | tail -f log |
从根源解决问题,不关闭终端,而是把当前shell隐藏起来。
screen和tmux是一个终端复用软件,通过该软件能够使终端隐藏起来而不是关闭。
以tmux为例
1 | # 进入tmux |
不同的shell有不同的实现。
这个是shell的配置,是否在终端退出时发出挂起信号?on为是,off为否
1 | # 查看huponexit命令的状态 |
1 | # 关闭终端退出挂起 |
使用该命令运行的命令会运行在init进程中,这就使得命令的运行与当前的shell没有关系了
1 | setsid ./test |
1 | # 使用pstree查看,发现进程在init进程上 |

忽略Sighup信号
1 | nohup ./test.sh |
该命令需要set选项monitor处于开启状态时才能执行
1 | # 查看monitor是否开启 |
将任务从当前jobs列表中移除并忽略Sighup信号,但是进程还属于当前shell
1 | # 运行任务 |
trap 命令用于指定当前进程在接受到信号后将要采取的行动
1 | # 设置接受到Sighup执行echo hello |

因为trap的作用域是进程,所以编写一个脚本,使trap和要运行的脚本运行在同一个进程中。
1 | #!/bin/bash |