網(wǎng)站積分解決方案百度下載電腦版
前言:
文件上傳下載在項(xiàng)目開(kāi)發(fā)中是一個(gè)非常常見(jiàn)的業(yè)務(wù)場(chǎng)景,在云服務(wù)上還沒(méi)有興起的時(shí)候,一般來(lái)說(shuō)都會(huì)把文件單獨(dú)存放到文件服務(wù)器上,隨著云服務(wù)的興起,各類云服務(wù)廠商都提供了 OSS 服務(wù),本篇我們分享 Spring Boot 項(xiàng)目如何把文件存儲(chǔ)到阿里云 OSS。
Spring Boot 集成阿里云 OSS
阿里云提供了 SDK,項(xiàng)目中引入相關(guān)依賴即可,我們?cè)?pom.xml 文件中引入依賴如下:
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.15.1</version>
</dependency>
阿里云訪問(wèn)信息
阿里云訪問(wèn)信息有四個(gè)如下:
- Endpoint:OSS服務(wù)所在地域的訪問(wèn)域名。
- AccessKeyId:訪問(wèn)OSS服務(wù)的密鑰ID。
- AccessKeySecret:訪問(wèn)OSS服務(wù)的密鑰秘鑰。
- BucketName:您創(chuàng)建的存儲(chǔ)空間名稱。
阿里云 OSS 上傳下載工具類
根據(jù)阿里云的訪問(wèn)要求封裝了阿里云 OSS 上傳下載工具類,如下:
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.comm.Protocol;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.PutObjectRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Date;/*** @ClassName: AliyunOssUtil* @Author: Author* @Date: 2024/11/13 19:39* @Description:*/
@Slf4j
@Component
public class AliyunOssUtil {@Value("${aliyun.oss.endpoint}")private String endpoint;@Value("${aliyun.oss.accessKeyId}")private String accessKeyId;@Value("${aliyun.oss.accessKeySecret}")private String accessKeySecret;@Value("${aliyun.oss.bucketName}")private String bucketName;/*** @return com.aliyun.oss.ClientBuilderConfiguration* @description 獲取配置類*/public ClientBuilderConfiguration getConfig() {// ClientBuilderConfiguration是OSSClient的配置類,可配置代理、連接超時(shí)、最大連接數(shù)等參數(shù)。ClientBuilderConfiguration conf = new ClientBuilderConfiguration();// 設(shè)置從連接池中獲取連接的超時(shí)時(shí)間(單位:毫秒),默認(rèn)不超時(shí)。conf.setConnectionRequestTimeout(3000);// 設(shè)置連接空閑超時(shí)時(shí)間。超時(shí)則關(guān)閉連接,默認(rèn)為60000毫秒。conf.setIdleConnectionTime(30000);conf.setProtocol(Protocol.HTTPS);return conf;}/*** @param file:* @param fileName:* @return java.lang.String* @description*/public String uploadOssFile(File file, String fileName) throws IOException {// 獲取上傳的文件的輸入流InputStream in = new FileInputStream(file);PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, in);String fileUrl = null;// 創(chuàng)建OSSClient實(shí)例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, getConfig());try {// 上傳文件ossClient.putObject(putObjectRequest);// 獲取文件訪問(wèn)路徑Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 100);URL url = ossClient.generatePresignedUrl(bucketName, fileName, expiration);//url 解碼 返回的地址需要進(jìn)行 URL 解碼fileUrl = URLDecoder.decode(url.toString(), "UTF-8");} catch (OSSException e) {log.error("oss上傳文件失敗,異常信息:", e);} finally {if (ossClient != null) {// 關(guān)閉ossClientossClient.shutdown();}}return fileUrl;}/*** @param fileUrl:* @param fileName:* @return java.io.File* @description*/public File downLoadOssFile(String fileUrl, String fileName) throws IOException {OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, getConfig());File file = new File(fileName);if (!file.exists()) {file.createNewFile();}String[] array = fileUrl.split("[?]");fileUrl = array[0];//key 填寫(xiě)不包含 Bucket 名稱在內(nèi)的路徑 例如 testfolder/mytest.xlsxString key = fileUrl.substring(fileUrl.lastIndexOf(StrUtil.SLASH) + 1);ossClient.getObject(new GetObjectRequest(bucketName, key), file);ossClient.shutdown();return file;}/*** oss中文件是否存在** @param fileName* @return*/public Boolean isFileExist(String fileName) {// 創(chuàng)建OSSClient實(shí)例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, getConfig());Boolean result = Boolean.FALSE;try {result = ossClient.doesObjectExist(bucketName, fileName);} catch (OSSException oe) {log.error("oss檢驗(yàn)文件是否存在失敗,Error Message:{},Error Code:{}", oe.getMessage(), oe.getErrorCode());} finally {if (ossClient != null) {// 關(guān)閉ossClientossClient.shutdown();}}return result;}/*** 刪除oss文件** @param fileName*/public void deleteFile(String fileName) {// 創(chuàng)建OSSClient實(shí)例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, getConfig());try {// 刪除文件ossClient.deleteObject(bucketName, fileName);} catch (OSSException oe) {log.error("oss刪除文件失敗,Error Message:{},Error Code:{}", oe.getMessage(), oe.getErrorCode());} finally {if (ossClient != null) {// 關(guān)閉ossClientossClient.shutdown();}}}}
業(yè)務(wù)場(chǎng)景
業(yè)務(wù)場(chǎng)景要求用戶端發(fā)起導(dǎo)出請(qǐng)求后,快速生成一個(gè)導(dǎo)出記錄響應(yīng)到用戶端,后端異步完成導(dǎo)出操作,后端完成導(dǎo)出后,將導(dǎo)出的文件上傳到阿里云 OSS,用戶可以在頁(yè)面完成文件的下載。
前面我們已經(jīng)封裝好了阿里云 OSS 的工具類,這里我們實(shí)現(xiàn)整個(gè)業(yè)務(wù),調(diào)用 OSS 工具類完成文件的上傳下載即可。
Service 代碼如下
部分項(xiàng)目中的代碼沒(méi)有展示出來(lái),了解整體實(shí)現(xiàn)思路即可。。
import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;/*** @ClassName: FileServiceImpl* @Author: Author* @Date: 2024/11/13 19:39* @Description:*/
@Slf4j
@Service
public class FileServiceImpl implements IFlieService {@Autowiredprivate AibabaCloudFileMapper aibabaCloudFileMapper;@Autowiredprivate AliyunOssUtil aliyunOssUtil;//前面我們已經(jīng)封裝好了阿里云 OSS 的工具類,這里我們實(shí)現(xiàn)整個(gè)業(yè)務(wù),調(diào)用 OSS 工具類完成文件的上傳下載即可。@Transactional(rollbackFor = Exception.class)@Overridepublic void exportList(FileQueryDTO fileQueryDTO) {List<SourceCodeAnalysisExportVO> exportList = new ArrayList<>();//導(dǎo)出記錄落庫(kù)AlibabaCloudFileDO alibabaCloudFileDO = new AlibabaCloudFileDO();//文件業(yè)務(wù)類型alibabaCloudFileDO.setBusinessType(1);//文件生成中alibabaCloudFileDO.setFileStatus(1);String fileName = "導(dǎo)出學(xué)生成績(jī)單" + DateUtil.format(new Date(), "yyyyMMddHHmmss");alibabaCloudFileDO.setFileName(fileName);aibabaCloudFileMapper.insert(alibabaCloudFileDO);uploadFileAliOss(exportList, fileName, alibabaCloudFileDO.getId());}@Overridepublic HttpServletResponse downLoadSouceCodeAnalysisFile(Long id, HttpServletResponse response) {AlibabaCloudFileDO alibabaCloudFileDO = aibabaCloudFileMapper.selectById(id);if (ObjectUtil.isNull(alibabaCloudFileDO)) {throw new BusinessException("文件id異常,請(qǐng)確認(rèn)后重試");}ServletOutputStream outputStream = null;try {String fileName = URLEncoder.encode(alibabaCloudFileDO.getFileName(), "UTF-8");response.setContentType("application/x-download;charset=utf-8");response.addHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");//調(diào)用 阿里云下載File file = aliyunOssUtil.downLoadOssFile(alibabaCloudFileDO.getFileAddress(), fileName);byte[] array = FileUtils.readFileToByteArray(file);outputStream = response.getOutputStream();outputStream.write(array);outputStream.flush();} catch (IOException e) {log.error("源代碼掃描文件下載失敗,失敗原因:", e);} finally {try {if (ObjectUtil.isNotNull(outputStream)) {outputStream.close();}} catch (IOException e) {e.printStackTrace();}}return response;}/*** @param exportList:* @param fileName:* @param id:* @description 異步上傳文件到 阿里云 OSS 該業(yè)務(wù)請(qǐng)求量很小 所以使用了 @Async 的異步方式*/@Asyncpublic void uploadFileAliOss(List<SourceCodeAnalysisExportVO> exportList, String fileName, Long id) {File tempFile = null;AlibabaCloudFileDO alibabaCloudFileDO = new AlibabaCloudFileDO();alibabaCloudFileDO.setId(id);try {// 創(chuàng)建臨時(shí)文件tempFile = File.createTempFile(fileName, ".xlsx");// 使用EasyExcel寫(xiě)入數(shù)據(jù)EasyExcel.write(tempFile, SourceCodeAnalysisExportVO.class).sheet("sheet1").doWrite(exportList);String fileUrl = aliyunOssUtil.uploadOssFile(tempFile, fileName + ".xlsx");alibabaCloudFileDO.setFileAddress(fileUrl);//更新文件生成成功alibabaCloudFileDO.setFileStatus(2);} catch (IOException e) {//文件生成失敗alibabaCloudFileDO.setFileStatus(3);log.error("文件上傳阿里云OSS 失敗,文件導(dǎo)出主鍵id:{}", id, e);} finally {//更新aibabaCloudFileMapper.updateById(alibabaCloudFileDO);tempFile.delete();}}}
下載文件代碼
完成導(dǎo)出后,用戶可以在頁(yè)面上看到下載按鈕,點(diǎn)擊下載就可以完成導(dǎo)出的文件下載了。
@PostMapping(value = "/download-source-code-analysis-file")@ApiOperation(httpMethod = "POST", value = "下載源代碼分析文件", notes = "下載源代碼分析文件")public HttpServletResponse downLoadSouceCodeAnalysisFile(@RequestParam("id") Long id, HttpServletResponse response) {return sourceCodeAnalysisService.downLoadSouceCodeAnalysisFile(id, response);}
總結(jié):本篇重點(diǎn)是分享阿里云 OSS 文件上傳下載功能,結(jié)合項(xiàng)目中的一個(gè)場(chǎng)景做了一個(gè)簡(jiǎn)單的異步導(dǎo)出,偏業(yè)務(wù)代碼,簡(jiǎn)單分享,希望可以幫助到有需要的朋友。
如有不正確的地方歡迎各位指出糾正。