13

10 分钟使用 Spring Boot + Vue + Antd + US3 搭建自己的图床

 3 years ago
source link: https://zhuanlan.zhihu.com/p/339204330
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

10 分钟使用 Spring Boot + Vue + Antd + US3 搭建自己的图床

网上已经一些运行不错的图床了,比如

那为什么我们还要自己搭建图床呢?一来是因为码农总是喜欢折腾,二来是有了自己的图床数据自己存储更安全。那么接下来我们就搞起来。下面是演示地址,可以先看一下搭建完成的效果。

https://xiaotuwo.github.io
点击按钮上传图片,完成以后可以复制链接和下载

v2-6ac646fca6935f22c163cc41b0b67e71_720w.jpg

准备前端环境

  1. 安装 nodejs

自行去nodejs 官网下载,我们主要是为了使用 npm 工具。

  1. 安装淘宝镜像,如果是在国内,下载镜像很慢,所以使用国内的镜像 。
sudo npm install -g cnpm --registry=https://registry.npm.taobao.org
  1. 安装 vue-cli 工具

因为我们前端使用的 vue,所以需要安装vue-cli

cnpm install -g @vue/cli
vue create xiaotuwo
  1. 添加 antd 依赖
cnpm install ant-design-vue --save
cd xiaotuwo  
npm run serve
  1. 访问,能够访问 HelloWorld 页面说明我们环境准备成功了。
http://localhost:8080

编写前端代码

到这里我们基础环境就搭建完成了,下面就开始编写前端的代码。我们是以 sm.ms 作为原型进行搭建。如下图我们只编辑他的头部,上传部分和尾部

成品形态如下,把 sm.ms 拖拽上传图片的交互设计改成了点击上传图片,不过如果你想实现拖拽也是非常简单,下面是 antd 的样式,换一个标签即可。
https://www.antdv.com/components/upload-cn/

头部和尾部代码非常简单,我们只讲解上传部分代码。搭建好 vue 框架以后去上面提供的 antd 的网址里面找到 upload 控件,直接点击复制自己喜欢的代码样式,粘贴到 content/index.vue 里面就可以了,然后修改 a-upload 的 action 为自己的服务器地址即可,本地测试就是http://localhost:8887/api/images/upload,下文中也有配套的服务端代码。

vue 的语法就不具体展开了,主要讲解一个地方, handlePreview 方法里面我添加了一个复制链接的逻辑,可以轻松的点击预览的时候复制图片链接,这样方便的把网址放入其他地方进行使用。

his.$message.success('复制图片链接成功');
document.addEventListener("copy", function copyCall(e) {
  e.preventDefault()
  e.clipboardData.setData("text/html", file.preview)
  e.clipboardData.setData("text/plain", file.preview)
  document.removeEventListener("copy", copyCall)
})

到这里基本的前端的搭建完成了,可以直接查看源码
https://github.com/xiaotuwo/xiaotuwo-client

服务器端环境准备

本文采用的是 US3 进行图床搭建,目前 US3 有 20G 的免费存储和每个月 20G 的免费流量,对于自用和起步还是足够的。

复制下面的链接到浏览器访问查看 US3 官网,首次进入需要注册
https://urlify.cn/YNNBNn
注册完成以后,进入控制台创建 US3 空间

进入空间以后填写存储名,私有空间和公开空间都可以,我创建的是 xiaotuwo.cn-bj.ufileos.com 留存备用。

在 US3 控制台创建令牌,主要是用来上传,删除图片使用

选择好自己刚才创建的空间,设置年限点击确定即可,记得一定要勾选令牌的权限

点击完成以后获取到公钥私钥,复制备用

编写服务端代码

服务端代码主要分为三个部分
1、接收请求的 Controller
2、上传图片到 US3 的逻辑
3、返回内容处理

1、 编写 Controller
使用 MultipartHttpServletRequest 接收到前端的 file 文件,调用 uCloudProvider 进行上传。

@PostMapping({"/api/files/upload"})
    @ResponseBody
    public FileDTO upload(HttpServletRequest request) {
        FileDTO resultFileDTO = new FileDTO();
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        MultipartFile file = multipartRequest.getFile("file");
        long start = System.currentTimeMillis();
        try {
            if (file == null) {
                resultFileDTO.setStatus("error");
            }
            FileDTO fileDTO = uCloudProvider.uploadWithExpired(file.getInputStream(), file.getContentType(), Objects.requireNonNull(file.getOriginalFilename()));
            log.info("UPLOAD_FILE_EXPIRED|ip:{}|referer:{}|url:{}|cost:{}", getIpAddress(request), request.getHeader("referer"), fileDTO.getUrl(), System.currentTimeMillis() - start);
            executorService.submit(new UCloudScanner(fileDTO, uCloudProvider, executorService, 1));
            resultFileDTO.setName(fileDTO.getName());
            resultFileDTO.setUrl(fileDTO.getUrl());
            resultFileDTO.setThumbUrl(fileDTO.getUrl());
            resultFileDTO.setStatus("done");
        } catch (Exception e) {
            log.error("UPLOAD_FILE_ERROR", e);
            resultFileDTO.setStatus("error");
        }
        return resultFileDTO;
    }

2、上传图片到 US3 的逻辑
上传 US3 主要是一些配置文件,我直接使用的 Maven 的 Filter 处理,配置文件在 pom.xml 里面,编译的时候写入 application.properties

<id>dev</id>
<properties>
    <server.port>8887</server.port>
    <ucloud.ufile.public-key>你的公钥</ucloud.ufile.public-key>
    <ucloud.ufile.private-key>你的私钥</ucloud.ufile.private-key>
    <ucloud.ufile.upload-domain-private>你的bucket名字.cn-bj.ufileos.com</ucloud.ufile.upload-domain-private>
    <ucloud.ufile.download-domain-private>你的bucket名字.cn-bj.ufileos.com</ucloud.ufile.download-domain-private>
    <ucloud.uaicensor.publicKey>鉴黄公钥</ucloud.uaicensor.publicKey>
    <ucloud.uaicensor.privateKey>鉴黄私钥</ucloud.uaicensor.privateKey>
    <ucloud.uaicensor.resourceId>鉴黄ID</ucloud.uaicensor.resourceId>
    <ucloud.uaicensor.url>http://api.uai.ucloud.cn/v1/image/scan</ucloud.uaicensor.url>
</properties>
<activation>
    <activeByDefault>true</activeByDefault>
</activation>

我们会发现配置文件里面除了文件的配置还有一套鉴黄的配置,对的这个地方不是本文的重点,但是图床一定要有鉴黄的能力,具体的实现可以参考文章 怒爬某 Hub 资源就为撸了一个鉴黄平台
具体 US3 的逻辑代码也是非常的简单,主要的逻辑就是上传,使用私钥和时间戳生成链接,显示。

public FileDTO upload(InputStream fileStream, String mimeType, String fileName) {
        String generatedFileName;
        String[] filePaths = fileName.split("\\.");
        if (filePaths.length > 1) {
            generatedFileName = UUID.randomUUID().toString() + "." + filePaths[filePaths.length - 1];
        } else {
            throw new ErrorCodeException(ErrorCode.FILE_UPLOAD_FAIL);
        }
        long start = System.currentTimeMillis();
        try {
            log.debug("UCloudProvider start upload file, filename : {}, time : {}", fileName, new Date());
            ObjectAuthorization objectAuthorization = new UfileObjectLocalAuthorization(publicKey, privateKey);
            ObjectConfig config = new ObjectConfig(uploadDomainPrivate);
            PutObjectResultBean response = UfileClient.object(objectAuthorization, config)
                    .putObject(fileStream, mimeType)
                    .nameAs(generatedFileName)
                    .toBucket(bucketNamePrivate)
                    .setOnProgressListener((bytesWritten, contentLength) -> {
                    })
                    .execute();
            log.debug("UCloudProvider end upload file, filename : {}, time : {}, cost : {}", fileName, new Date(), System.currentTimeMillis() - start);
            if (response != null && response.getRetCode() == 0) {
                long start2 = System.currentTimeMillis();
                log.debug("UCloudProvider start get url, filename : {}, time : {}", fileName, new Date());

                String url = UfileClient.object(objectAuthorization, new ObjectConfig(downloadDomainPrivate))
                        .getDownloadUrlFromPrivateBucket(generatedFileName, bucketNamePrivate, 24 * 60 * 60)
                        .createUrl();

                log.debug("UCloudProvider end get url, filename : {}, time : {}, cost : {}", fileName, new Date(), System.currentTimeMillis() - start2);

                FileDTO fileDTO = new FileDTO();
                fileDTO.setUrl(url.replace("http", "https"));
                fileDTO.setName(generatedFileName);
                return fileDTO;
            } else {
                log.debug("UCloudProvider end upload file, filename : {}, time : {}, cost : {}", fileName, new Date(), System.currentTimeMillis() - start);
                log.error("upload error,{}", response);
                throw new ErrorCodeException(ErrorCode.FILE_UPLOAD_FAIL);
            }
        } catch (UfileClientException | UfileServerException e) {
            log.debug("UCloudProvider end upload file, filename : {}, time : {}, cost : {}", fileName, new Date(), System.currentTimeMillis() - start);
            log.error("upload error,{}", fileName, e);
            throw new ErrorCodeException(ErrorCode.FILE_UPLOAD_FAIL);
        }
    }

3、 返回内容处理,这里也需要注意一下,为了配合 antd 的 upoad 控件,我们的 dto 如下

@Data
public class FileDTO {
    private String name;
    private String status;
    private String url;
    private String thumbUrl;
}

服务器端源码访问
https://github.com/xiaotuwo/xiaotuwo-server

到这里就全部结束了,你学废了吗?如果有任何问题,可以到 US3 自己的官方论坛提问:
https://uclub.ucloud.cn/invite/93

文章来源:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK