最近关注我的都知道,我开了一个 communication(地址) 项目,本意是将它开发成一个多功能系统中台,所以为其量身打造了很多个功能,可以说都快成一个大杂烩了被我搞得。
但我发现这个项目连基本的文件上传都没有,这不行,要搞一个。
在进行文件上传功能前,我分析了一下腾讯及阿里的文件存储服务功能,流程都基本类似都是申请XXX云账号,开通文件存储对象功能,对接sdk,开始编码等。
那为啥用第三方,不直接将文件上传到自己的服务器中呢!一是我前面接触过阿里OSS文件存储服务功能,觉得很方便存取不用花他多时间管理文件服务、二是本地文件上传对于分布式系统要求很高嘛,所以图简单就直接用第三方了。不过后面我会再出一期上传到本地服务其的文件上传教程(下期)。
好了,铺垫很多了,现在就开始用 SpringBoot + OSS 搭建一个通用的文件上传功能。
所有代码均在Gitee:https://gitee.com/j3_baiqi/communication
一、开通阿里云OSS服务功能
访问地址,登录自己的阿里云(一定要实名认证)
按照如下截图进行操作:
一:选择 OSS 文件服务产品
二:进入 OSS 控制台
三:点击 Bucket 列表创建一个 bucket
四:配置 Bucket
- Bucket 名称:和项目相关的名称就行了
- 存储类型:标准存储
- 版本控制:不开通
- 读写权限:公共读就行
- 服务端加密方式:无
- 试试日志查询:不开通
点击确认,一个 bucket 就创建好了,如下:
下面就要创建一个代码可以访问 OSS 服务的 AccessKey
。
一:进入 AccessKey 管理
二:选择子 AccessKey
三:创建 AccessKey 用户
四:配置 AccessKey 用户
五:AccessKey 用户列表
注意!注意!注意!创建好之后出现的 用户 AccessKey 列表中的 AccessKey ID、AccessKey Secret 这两个值非常重要,而且只会显示一次,如果不拿小本本记录下来,忘了就只能删除重现创建。
下面就要给这个用户 key 赋权限(只给管理 OSS 服务的权限就行)
六:添加权限
到此,代码开发前的准备工作就完成了,此时你应该知道如下信息:
- bucket:j3-communication
- Bucket 域名(外网访问):https://oss-cn-guangzhou.aliyuncs.com
- accessKeyId:你自己的
- accessKeySecret:你自己的
二、代码实现
2.1 添加依赖
创建一个 SpringBoot 项目,添加如下依赖。
地址:https://help.aliyun.com/document_detail/32009.html
<!--OSS文件服务--> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.10.2</version> </dependency>
再配置一下文件上传大小限制
再 application.yml 中添加如下配置,限制单个文件最大 100M 、文件上传总大小 200M。
spring: servlet: multipart: max-file-size: 100MB max-request-size: 200MB
2.2 文件上传编码
实现功能有:
- 单个文件上传
- 多个文件上传
- 单个文件删除
- 多个文件删除
@Slf4j @Component @AllArgsConstructor public class OssTemplate { // 我自己抽的统一文件前缀,communication-resource private final String prefix = "oss.file.prefix"; // 你的 bucket,j3-communication private final String bucket = "oss.file.bucket"; // 你的 bucket 外网访问域名,https://oss-cn-guangzhou.aliyuncs.com private final String endpoint = "oss.file.endpoint"; // 拼接返回url要用的,bucket + 域名 例如: j3-communication.oss-cn-guangzhou.aliyuncs.com private final String bucketHost = "oss.file.bucketHost"; // 这两个就没啥好说的了 private final String accessKeyId = "oss.file.accessKeyId"; private final String accessKeySecret = "oss.file.accessKeySecret"; // 生成文件路径用的,根据日期 private final SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd"); /** * 单个文件上传 * @param file * @return */ public String upload(MultipartFile file) { // 路径拼接 String dataPath = format.format(new Date()); // 文件名称生成 String uuid = UUID.randomUUID().toString().replace("-", ""); String path = prefix + "/" + dataPath + "/" + uuid + file.getOriginalFilename(); try { // 上传 ossUpload(bucket, path, file.getInputStream()); } catch (IOException e) { throw new SysException("文件上传失败!"); } // 因为 oss 不会返回访问 url 所以我们自己可以拼接一个: // 协议(https://) + 域名访问地址(j3-communication.oss-cn-guangzhou.aliyuncs.com) + 自己拼接的路径(xxx/xxx/a.jpg) return "https://" + bucketHost + "/" + path; } /** * 多个文件上传 * @param files * @return */ public List<String> upload(MultipartFile[] files) { List<String> usrList = new ArrayList<>(files.length); for (MultipartFile file : files) { usrList.add(upload(file)); } return usrList; } /** * 具体上传代码 * @param bucket backet名称 * @param path 路径 * @param inputStream 文件流 * @return */ private PutObjectResult ossUpload(String bucket, String path, InputStream inputStream) { OSS ossClient = null; PutObjectResult putObjectResult = null; try { // 创建OSSClient实例。 ossClient = new OSSClientBuilder().build(endpoint , accessKeyId , accessKeySecret); // 通过文件流的形式上传文件 putObjectResult = ossClient.putObject(bucket, path, inputStream); } catch (Exception e) { //错误处理 log.error("==========ossUpload_error, {}", e); throw new SysException("文件上传失败!"); } finally { //资源关闭 assert ossClient != null; ossClient.shutdown(); } return putObjectResult; } /** * 单个删除 * @param url 文件url */ public void delete(String url) { // 处理 url log.info("============入参:{}", url); String path = url.substring(("https://" + bucketHost + "/").length()); log.info("============path:{}", path); ossDelete(bucket, Collections.singletonList(path)); } /** * 多个删除 * @param urlList */ public void delete(List<String> urlList) { List<String> keys = new ArrayList<>(urlList.size()); for (String url : urlList) { keys.add(url.substring(("https://" + bucketHost + "/").length())); } ossDelete(bucket, keys); } /** * 具体删除代码 * @param bucket backet * @param pathList 文件url列表 */ private void ossDelete(String bucket, List<String> pathList) { OSS ossClient = null; try { // 创建OSSClient实例。 ossClient = new OSSClientBuilder().build(endpoint , accessKeyId , accessKeySecret); // ossClient.deleteObject(bucket, path); DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucket); deleteObjectsRequest.setKeys(pathList); ossClient.deleteObjects(deleteObjectsRequest); } catch (Exception e) { //错误处理 log.error("==========ossUpload_error, {}", e); throw new SysException("文件删除失败!"); } finally { //资源关闭 assert ossClient != null; ossClient.shutdown(); } } }
2.3 编写 controller 测试
@Slf4j @AllArgsConstructor @ResponseResult @RequestMapping("/test/oss") public class OssTemplateTest { private final OssTemplate ossTemplate; @PostMapping("/upload") public String upload(MultipartFile file) { return ossTemplate.upload(file); } @PostMapping("/batch") public List<String> upload(MultipartFile[] files) { return ossTemplate.upload(files); } @GetMapping("/delete") public void delete(@RequestParam(name = "url") String url) { ossTemplate.delete(url); } @PostMapping("/deletes") public void deletes(@RequestBody List<String> urlList) { ossTemplate.delete(urlList); } }
2.4 验证
可以访问自己的 oss 文件后台验证文件是否存在
这样,一个简单的文件上传就写好了,还是非常简单的,主要功能还是 OssTemplate
类。
下篇写直接上传文件到服务器,然后通过 Nginx 代理访问服务器中的资源文件。
好了,今天的内容到这里就结束了,关注我,我们下期见