企业级项目开发中都会有文件、图片、视频等文件上传并能够访问的场景,对于初学者Demo可能会直接存储在应用服务器上;对于传统项目可能会单独搭建FastDFS、MinIO等文件服务来实现存储,这种方案可能对于企业成本较小,但缺点也是很多,例如:1、增加技术人员的运维和维护成本,2、规模越来越大时需要硬件的支持,且存在文件丢失风险,3、服务器没有CDN,用户访问网站图片加载慢用户体验不好。
所以,一般上规模的项目、或者追求用户体验的项目可能会考虑使用第三方的云服务来存储,市场主流厂商有:七牛云、阿里云OSS、腾讯云COS等,具体采用哪种存储方案需结合项目、规模、成本等因素,综合考量确定。
因为用的腾讯云服务器,为了方便统一管理,所以直接用了腾讯云的COS对象存储服务,下面是基于SpringBoot和腾讯云COS提供的Java SDK快速对接实现文件上传功能。
1、开通腾讯云对象存储服务
https://console.cloud.tencent.com/cos5
2、创建存储桶
3、密钥管理,新建密钥
4、yml配置密钥、COS信息
cos:baseUrl: fxxxxxa-1xxxxx1.cos.ap-shanghai.myqcloud.comaccessKey: AKxxxxxxxxxxxxxxxxxxxxxxxxxCFsecretKey: oKxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxniregionName: ap-shanghaibucketName: fxxxxxa-1xxxxx1folderPrefix: /files
5、COSConfig配置类
@Data
@Component
@ConfigurationProperties(prefix = "cos")
public class COSConfig {private String baseUrl;private String accessKey;private String secretKey;private String regionName;private String bucketName;private String folderPrefix;
}
6、COS文件上传工具类
/*** 腾讯云COS文件上传工具类*/
@Slf4j
public class COSClientUtil {/*** 获取配置信息*/private static COSConfig cosConfig = SpringBeanUtils.getBean(COSConfig.class);/*** 初始化用户身份信息*/private static COSCredentials cred = new BasicCOSCredentials(cosConfig.getAccessKey(), cosConfig.getSecretKey());/*** 设置bucket的区域*/private static ClientConfig clientConfig = new ClientConfig(new Region(cosConfig.getRegionName()));/*** 生成COS客户端*/private static COSClient cosClient = new COSClient(cred, clientConfig);/*** 上传文件** @param file* @return* @throws Exception*/public static String upload(MultipartFile file) throws Exception {String date = DateUtils.formateDate(new Date(), "yyyy-MM-dd");String originalFilename = file.getOriginalFilename();long nextId = IdGenerator.getFlowIdWorkerInstance().nextId();String name = nextId + originalFilename.substring(originalFilename.lastIndexOf("."));String folderName = cosConfig.getFolderPrefix() + "/" + date + "/";String key = folderName + name;File localFile = null;try {localFile = transferToFile(file);String filePath = uploadFileToCOS(localFile, key);log.info("upload COS successful: {}", filePath);return filePath;} catch (Exception e) {throw new Exception("文件上传失败");} finally {localFile.delete();}}/*** 上传文件到COS** @param localFile* @param key* @return*/private static String uploadFileToCOS(File localFile, String key) throws InterruptedException {PutObjectRequest putObjectRequest = new PutObjectRequest(cosConfig.getBucketName(), key, localFile);ExecutorService threadPool = Executors.newFixedThreadPool(8);// 传入一个threadPool, 若不传入线程池, 默认TransferManager中会生成一个单线程的线程池TransferManager transferManager = new TransferManager(cosClient, threadPool);// 返回一个异步结果Upload, 可同步的调用waitForUploadResult等待upload结束, 成功返回UploadResult, 失败抛出异常Upload upload = transferManager.upload(putObjectRequest);UploadResult uploadResult = upload.waitForUploadResult();transferManager.shutdownNow();cosClient.shutdown();String filePath = cosConfig.getBaseUrl() + uploadResult.getKey();return filePath;}/*** 用缓冲区来实现这个转换, 即创建临时文件* 使用 MultipartFile.transferTo()** @param multipartFile* @return*/private static File transferToFile(MultipartFile multipartFile) throws IOException {String originalFilename = multipartFile.getOriginalFilename();String prefix = originalFilename.split("\\.")[0];String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));File file = File.createTempFile(prefix, suffix);multipartFile.transferTo(file);return file;}}
7、Controller测试上传接口:
/*** 腾讯云COS上传** @param file* @return* @throws Exception*/@PostMapping(value = "/cosUpload")public ResponseEntity cosUpload(MultipartFile file) throws Exception {String filePath = COSClientUtil.upload(file);UploadDTO dto = UploadDTO.builder().filePath(filePath).build();return ResultVOUtil.success(dto);}
8、PostMan接口调用
9、浏览器预览效果