網(wǎng)絡(luò)有限公司做女裝網(wǎng)站的百度一下百度搜索百度
文件上傳,是指將本地圖片、視頻、音頻等文件上傳到服務(wù)器上,可以供其他用戶瀏覽或下載的過程。文件上傳在項目中應(yīng)用非常廣泛,我們經(jīng)常發(fā)抖音、發(fā)朋友圈都用到了文件上傳功能。
實現(xiàn)文件上傳服務(wù),需要有存儲的支持,那么我們的解決方案將以下幾種:
-
直接將圖片保存到服務(wù)的硬盤(springmvc中的文件上傳)
-
優(yōu)點:開發(fā)便捷,成本低
-
缺點:擴容困難
-
-
使用分布式文件系統(tǒng)進行存儲
-
優(yōu)點:容易實現(xiàn)擴容
-
缺點:開發(fā)復(fù)雜度稍大(有成熟的產(chǎn)品可以使用,比如:FastDFS,MinIO)
-
-
使用第三方的存儲服務(wù)(例如OSS)
-
優(yōu)點:開發(fā)簡單,擁有強大功能,免維護
-
缺點:付費
-
在本項目選用阿里云的OSS服務(wù)進行文件存儲。
因為在新增菜品時,需要上傳菜品對應(yīng)的圖片(文件),包括后緒其它功能也會使用到文件上傳,故要實現(xiàn)通用的文件上傳接口。
文件上傳,是指將本地圖片、視頻、音頻等文件上傳到服務(wù)器上,可以供其他用戶瀏覽或下載的過程。文件上傳在項目中應(yīng)用非常廣泛,我們經(jīng)常發(fā)抖音、發(fā)朋友圈都用到了文件上傳功能。
實現(xiàn)文件上傳服務(wù),需要有存儲的支持,那么我們的解決方案將以下幾種:
-
直接將圖片保存到服務(wù)的硬盤(springmvc中的文件上傳)
-
優(yōu)點:開發(fā)便捷,成本低
-
缺點:擴容困難
-
-
使用分布式文件系統(tǒng)進行存儲
-
優(yōu)點:容易實現(xiàn)擴容
-
缺點:開發(fā)復(fù)雜度稍大(有成熟的產(chǎn)品可以使用,比如:FastDFS,MinIO)
-
-
使用第三方的存儲服務(wù)(例如OSS)
-
優(yōu)點:開發(fā)簡單,擁有強大功能,免維護
-
缺點:付費
-
在本項目選用阿里云的OSS服務(wù)進行文件存儲。(前面課程已學(xué)習(xí)過阿里云OSS,不再贅述)
定義OSS相關(guān)配置
在sky-server模塊
注意冒號后面有空格!!!
application-dev.yml(開發(fā)環(huán)境下的配置文件,yml可以引用該文件的值,這樣就不用把值寫死)
sky:alioss:endpoint: oss-cn-hangzhou.aliyuncs.comaccess-key-id: LTAI5tPeFLzsPPT8gG3LPW64access-key-secret: U6k1brOZ8gaOIXv3nXbulGTUzy6Pd7bucket-name: sky-take-out
application.yml
spring:profiles:active: dev ? ?#設(shè)置環(huán)境
sky:alioss:endpoint: ${sky.alioss.endpoint}access-key-id: ${sky.alioss.access-key-id}access-key-secret: ${sky.alioss.access-key-secret}bucket-name: ${sky.alioss.bucket-name}
細節(jié):application-dev.yml是開發(fā)環(huán)境下的配置文件,yml可以引用該文件的值,這樣就不用把值寫死
讀取配置信息
封裝一個類專門存放配置信息
在sky-common模塊中,已定義配置屬性類(讀取配置文件中對應(yīng)的配置信息sky.alioss,并將其封裝為一個類)
@ConfigurationProperties(prefix = "sky.alioss")
?細節(jié):
- 配置類存放位置:common的properties包下
- 配置類的注解:@Component
- @ConfigurationProperties(prefix = "sky.alioss")說明配置類對應(yīng)的配置項
?生成OSS工具類對象
在sky-server模塊
定義一個配置類用于自動創(chuàng)建OSS工具類對象(在此過程中為配置類的屬性賦值了)
package com.sky.config;import com.sky.properties.AliOssProperties;
import com.sky.utils.AliOssUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** 配置類,用于創(chuàng)建AliOssUtil對象*/
@Configuration
@Slf4j
public class OssConfiguration {//自動啟動@Bean//工具類對象只需要存在一個bean就好@ConditionalOnMissingBeanpublic AliOssUtil aliOssUtil(AliOssProperties aliOssProperties){log.info("開始創(chuàng)建阿里云文件上傳工具類對象:{}",aliOssProperties);return new AliOssUtil(aliOssProperties.getEndpoint(),aliOssProperties.getAccessKeyId(),aliOssProperties.getAccessKeySecret(),aliOssProperties.getBucketName());}
}
其中,AliOssUtil.java已在sky-common模塊中定義
package com.sky.utils;import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayInputStream;@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketName;/*** 文件上傳** @param bytes* @param objectName* @return*/public String upload(byte[] bytes, String objectName) {// 創(chuàng)建OSSClient實例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);try {// 創(chuàng)建PutObject請求。ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}//文件訪問路徑規(guī)則 https://BucketName.Endpoint/ObjectNameStringBuilder stringBuilder = new StringBuilder("https://");stringBuilder.append(bucketName).append(".").append(endpoint).append("/").append(objectName);log.info("文件上傳到:{}", stringBuilder.toString());return stringBuilder.toString();}
}
注意:?
//文件訪問路徑規(guī)則 https://BucketName.Endpoint/ObjectNameStringBuilder stringBuilder = new StringBuilder("https://");stringBuilder.append(bucketName).append(".").append(endpoint).append("/").append(objectName);
定義文件上傳通用接口
在sky-server模塊中定義接口
package com.sky.controller.admin;import com.sky.constant.MessageConstant;
import com.sky.result.Result;
import com.sky.utils.AliOssUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.UUID;/*** 通用接口*/
@RestController
@RequestMapping("/admin/common")
@Api(tags = "通用接口")
@Slf4j
public class CommonController {@Autowiredprivate AliOssUtil aliOssUtil;/*** 文件上傳* @param file* @return*/@PostMapping("/upload")@ApiOperation("文件上傳")public Result<String> upload(MultipartFile file){log.info("文件上傳:{}",file);try {//原始文件名String originalFilename = file.getOriginalFilename();//截取原始文件名的后綴 dfdfdf.png substring只傳一個參數(shù),表示從該位置開始截取String extension = originalFilename.substring(originalFilename.lastIndexOf("."));//構(gòu)造新文件名稱String objectName = UUID.randomUUID().toString() + extension;//文件的請求路徑String filePath = aliOssUtil.upload(file.getBytes(), objectName);return Result.success(filePath);} catch (IOException e) {log.error("文件上傳失敗:{}", e);}return Result.error(MessageConstant.UPLOAD_FAILED);}
}
細節(jié):
MultipartFile file這個file一定是和前端請求的文件名保持一致的,不能隨便取名。
?