技术派如何实现图片上传至服务器
大家好,我是技术派的二哥呀。
今天由我来给大家讲一下技术派中是如何实现原生图片上传的,这个功能说起来简单,但其实挺考验技术实力的,因为图片上传涉及到 IO 读写,可以说,一个文件上传的功能,就可以把 IO 流涉及到的知识全部覆盖到,比如说字节流 ByteArrayInputStream、缓存流 BufferedOutputStream、文件 File 的读写权限、文件魔数等等。
想要完全搞清楚,甚至想要手写一个属于自己的文件读写 Util 类,是需要下一番功夫的。因为考虑的细节还是蛮多的,比如说静态资源配置、图片大小限制、前端图片上传组件、后端图片接收参数 MultipartHttpServletRequest 等等。
技术派中对于图片的上传,是做了充分准备的,当你在本地拉取技术派源码跑起来的时候,我们默认会把图片保存到本地;当你需要在生产环境部署的话,我们默认会采用 OSS 配合 CDN 的方式来完成。这篇内容主要来本地上传图片的方式。
业务介绍
技术派中关于图片上传的入口有三处:
- 发表文章时
- 上传文章封面时
- 上传用户头像时
先来看发表文章,这里又涉及到四种方式:
- 通过编辑器的菜单添加图片。
- 直接复制一张图片粘贴到编辑器中。
- 复制外部的图片链接(markdown 格式),到编辑器中。
- 导入 MD 文件到编辑器中(如果有图片链接时)。
这四种方式都会触发图片上传功能(严格一点的话,后面两个还涉及到图片转链,后面会讲),后台的接口是一样的,都调用的是 ImageRestController,上传图片调用的是 upload 方法,请求参数为 HttpServletRequest;转存图片链接调用的是 save方法,参数为图片的外部链接。响应结果为 ResVo,其中包含最关键的信息——图片路径。

搞清楚业务的话,就很容易去看懂技术派的源码,然后学习和模仿了。
代码实现
第一步,在 dev/application-image.yml 文件中添加图片的配置
image:
abs-tmp-path: /tmp/storage/
web-img-path: /forum/image/
tmp-upload-path: /tmp/forum/
cdn-host:
oss:
type: local
prefix: paicoding/
endpoint:
ak:
sk:
bucket:
host: https://cdn.tobebetterjavaer.com
spring:
web:
resources:
# 支持本地图片上传之后的链接,其中 file:///d的用于win系统,后面的file: 适用于mac/linux系统
static-locations:
- classpath:/static/
- file:///d:${image.abs-tmp-path}
- file:${image.abs-tmp-path}
来解释一下参数的含义:
- abs-tmp-path:存储的绝对路径
- web-img-path:图片在 Web 应用中的相对路径
- tmp-upload-path:上传文件的临时存储目录
- cdn-host:图片的 CDN 访问域名(本地不需要)
- oss:图片上传到阿里云 OSS 时的配置(讲 OSS 上传的时候再细说)
- spring.web.resources.static-locations 是 Spring Boot 提供的一种加载静态资源的机制。
静态资源通常包括 CSS、JavaScript、图片等文件,通过设置 spring.web.resources.static-locations,我们可以告诉 Spring Boot 在哪些位置查找静态资源。Spring Boot 的默认静态资源位置包括:
- classpath:/static
- classpath:/public
- classpath:/resources
- classpath:/META-INF/resources
当我们为 spring.web.resources.static-locations 提供自定义的值时,Spring Boot 会覆盖这些默认值。在技术派的项目结构中,我们将 CSS 和 JavaScript,以及一些图片资源放在了 paicoding-ui 模块的 static 目录下。

也就意味着,在我们的前端页面中,如果遇到类似这样的 请求时,Spring Boot 将会从 classpath:/static/ 目录下去找。

注意,我们还指定了另外两个静态资源位置:file:///d:${image.abs-tmp-path} 和 file:${image.abs-tmp-path},前者用于 Windows 系统,后者用于 macOS 和 Linux 系统。
拿 macOS 举例,我们会把图片保存在 /tmp/storage/forum/image 目录下。

也就是说,我们可以通过 http://127.0.0.1:8080/forum/image/20230423060009676_69.jpg 这种形式访问图片。

还可以通过 file:/tmp/storage/forum/image/20230423060009676_69.jpg 的形式访问图片。

file:/ 是一个 URI(统一资源标识符)的方案,表示在本地文件系统上的资源。例如,如果你想引用本地文件系统上的一个文件,可以使用 file:/。以下是一些示例:
file:/C:/path/to/your/file.txt:表示在 Windows 系统上的C:/path/to/your/file.txt文件。file:/Users/username/path/to/your/file.txt:表示在 macOS 或 Linux 系统上的/Users/username/path/to/your/file.txt文件。
第二步,新建 ImageProperties.java 类
使用 @ConfigurationProperties 注解使其和配置文件中的图片配置关联起来。
@Setter
@Getter
@Component
@ConfigurationProperties(prefix = "image")
public class ImageProperties {
/**
* 存储绝对路径
*/
private String absTmpPath;
/**
* 存储相对路径
*/
private String webImgPath;
/**
* 上传文件的临时存储目录
*/
private String tmpUploadPath;
/**
* 访问图片的host
*/
private String cdnHost;
private OssProperties oss;
public String buildImgUrl(String url) {
if (!url.startsWith(cdnHost)) {
return cdnHost + url;
}
return url;
}
}
@Setter...
未能定位到原文的划线
企业级Agent工作流编排项目PaiFlow
Vibe Coding版本的PaiAgent
派聪明RAG AI知识库Java版本+Go版本
微服务 PmHub、技术派、MYDB
求职派JobClaw(OpenClaw/Hermes架构
PaiCLI(类似Claude Code的Agent
派简历(代码已完成)
等实战项目。
1. 微信扫右侧的优惠券加入知识星球
2. 解锁星球的实战项目教程和源码: 项目源码+教程获取
真诚点赞 诚不我欺
回复