平时在写博客的时候,一般用的Typora,文章和图片都会存在本地,到了转到线上博客的时候,图片还要一个个上传。Typora本身自带图片上传的功能,配合PicGo使用,不过自己想多折腾一下,这时就想建个文件服务器,迁移文章的时候也方便了,也让我那吃灰的服务器有了用途。😄
使用到的技术栈
- MinIO 分布式文件存储系统 ,当然也可以选择直接存到本地
- SpringBoot
- Powershell
后端准备
搭建完MinIO后,打开管理界面:

后端接口直接使用minio-client完成文件操作即可。
文件上传代码如下,其中省去对数据库的操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public String upload(MultipartFile multipartFile) throws IOException {
String originalFilename = multipartFile.getOriginalFilename();
if (originalFilename == null) throw new FileUploadException();
InputStream originalFileInputStream = multipartFile.getInputStream();
String year = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy"));
String decodeFileName = URLDecoder.decode(originalFilename, StandardCharsets.UTF_8);
if (decodeFileName.contains("\\")) { //windows
decodeFileName = decodeFileName.substring(decodeFileName.lastIndexOf("\\") + 1);
} else if (decodeFileName.contains("/")) { //linux
decodeFileName = decodeFileName.substring(decodeFileName.lastIndexOf("/") + 1);
}
String bucketName = bucketName + year;
String uuid = UUID.randomUUID().toString().replace("-", "");
String finalName = uuid + decodeFileName.substring(decodeFileName.lastIndexOf("."));
boolean createBucketFlag = minIOService.createBucket(bucketName);
if (createBucketFlag) {
minIOService.upload(bucketName, finalName, originalFileInputStream);
} else {
throw new FileUploadException();
}
return this.serverProtocol + "://" + this.serverDomain + ("dev".equals(profilesActive) ? ":" + this.serverPort : "") + "/file/preview/" + uuid;
}
|
文件上传完成后需要返回相应的预览链接,预览代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public void filePreview(String uuid, HttpServletResponse response) throws IOException {
ZFile zFile = getOneCache(ZFile::getFileUuid, uuid);
if (zFile == null) {
HttpResponseUtil.renderJson(Result.notFound(Object.class), response);
return;
}
String fileName = zFile.getFileName();
if (fileName == null) {
HttpResponseUtil.renderJson(Result.notFound(Object.class), response);
return;
}
String fileSuffix = fileName.substring(fileName.lastIndexOf("."));
String finalName = uuid + fileSuffix;
GetObjectResponse objectResponse = minIOService.getFile(zFile.getFileBucket(), finalName);
response.setContentType(ContentType.get(fileSuffix));
IoUtil.copy(objectResponse, response.getOutputStream());
}
|
配合PowerShell脚本
使用Typora的custom command line,完成调用ps脚本来上传,脚本内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
$uri = "http://127.0.0.1:8080/file/upload"
function post {
param (
[string]$filePath
)
$fileBytes = [System.IO.File]::ReadAllBytes($filePath);
$fileEnc = [System.Text.Encoding]::GetEncoding('ISO-8859-1').GetString($fileBytes);
$boundary = [System.Guid]::NewGuid().ToString();
$LF = "`r`n";
#$encodedFilePath = [System.Web.HttpUtility]::UrlEncode($filePath)
$encodedFilePath = [uri]::EscapeDataString($filePath)
$bodyLines = (
"--$boundary",
"Content-Disposition: form-data; name=`"file`"; filename=`"$encodedFilePath`"",
"Content-Type: application/octet-stream$LF",
$fileEnc
"--$boundary--$LF"
) -join $LF
Invoke-RestMethod -Uri $Uri -Headers $Headers -Method Post -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $bodyLines
}
for ($i = 2; $i -lt $args.Count; $i++) {
post($args[$i])
}
|
调用脚本内容如下:
1
|
powershell C:\Users\Gary\OneDrive\Documents\uploadFile.ps1 ${filename}
|
完成以上配置即可。