參考資料:Java操作阿里云OSS操作官方檔案
學會看檔案,并實際運用也是一種習慣和技能
下面就來簡單入門一下,用當下比較熱門的Springboot 去操作阿里云OSS檔案存盤,
1.需求
(沒踩過下面的坑的小伙伴可以直接跳過這一章節)
問題簡述
首先,我在之前自己做一些開源小專案案例中遇到一些檔案上傳下載的問題,比如在本機檔案上傳和下載都可以正常使用,通過將檔案上傳到Springboot專案的根目錄下,按日期分檔案夾,檔案訪問也很方便,可以直接回傳檔案相對路徑地址,并直接可以訪問,
問題
然而,這種方式存在弊端,因為當專案打包(jar包)部署阿里云學生機后,出現類似io.NotFoundException...(No Such Directory)的問題,,而如果打war包部署到tomcat則沒問題,可以正常使用,經過排查很久,找出問題所在:
因為jar打包封裝后是不能改變其內部目錄結構的,也就是說,按日期分類的檔案上傳檔案夾,如果當需要創建新日期的檔案夾的時候,是無法在jar包中新增檔案夾的,這時候就會出現IO例外問題,而對于放在tomcat中的war包,當tomcat運行的時候會自動解壓war包,其在服務器上是存在真實路徑的,
解決方案
- 方案一:我在網上找了一種方法,是通過打完jar包部署后,給springboot專案static下的檔案上傳檔案夾單獨分離出來(相當于是以相對路徑換絕對路徑),訪問的時候直接相當通過服務器上和jar包同級目錄下新建一個檔案上傳檔案夾,
- 方案二:直接將檔案上傳到服務器指定路徑下的檔案上傳位置,這種方式也相當于直接使用絕對路徑,
- 方案三:在服務器上使用FastDFS和Nginx搭建分布式檔案存盤,這種方式比較復雜,而且學生及本來記憶體和帶寬就小,在自己電腦的虛擬機可以試試這種方案,還是挺好用的,學生服務器就算了,
- 方案四:就是直接將檔案上傳到阿里云OSS檔案存盤系統上
2. 阿里云OSS購買和配置
這個比較簡單,給大家推薦一篇博文自己了解下阿里云oss購買和配置,也可以參考阿里云OSS官方檔案,
3. Springboot操作OSS
創建一個spring boot專案,pom檔案需要引入依賴:
pom.xml
<dependencies>
<!--
個人版本踩坑:
不加這個依賴的話,當在配置類中
使用@ConfigurationProperties(prefix = "aliyun")注解時,
我這個版本的spring boot會提示有問題
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- swagger ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!-- thymeleaf 可不加,個人習慣性引入 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 熱部署,看個人習慣 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- 小辣椒插件,推薦使用,可以節省javaBean的setter/getter,還可以使用鏈式呼叫 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- fastJson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<!-- aliyun-oos -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.8.3</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.1</version>
</dependency>
<!-- apache-common-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
包結構很簡單:

我們使用自己添加的application-aliyun-oss.properties組態檔,去配置OSS相關資訊,之所以不在application.yml 中配置,看個人習慣了,因為自定義的配置屬性還是提出來配比較好,沒必要所有的都配到application.yml(properties)中去,
application-aliyun-oss.properties
# 檔案上傳大小限制
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=1000MB
# 地域節點
aliyun.endPoint=oss-cn-beijing.aliyuncs.com
# Bucket 域名
aliyun.urlPrefix=http://csp-xxxx.oss-cn-beijing.aliyuncs.com/
# accessKey Id
aliyun.accessKeyId=LTAI4XXXXXXXzqD1saGFZ
# accessKey Secret
aliyun.accessKeySecret=2WjxNXXXXXXXX4f2bREc
# 你的Bucket名稱
aliyun.bucketName=csp-xxxx
# 目標檔案夾
aliyun.fileHost=files
config包下的相關配置類
AliyunOssConfig.java
/**
* @Auther: csp1999
* @Date: 2020/10/31/13:33
* @Description: 阿里云 OSS 基本配置
*/
// 宣告配置類,放入Spring容器
@Configuration
// 指定組態檔位置
@PropertySource(value = {"classpath:application-aliyun-oss.properties"})
// 指定組態檔中自定義屬性前綴
@ConfigurationProperties(prefix = "aliyun")
@Data// lombok
@Accessors(chain = true)// 開啟鏈式呼叫
public class AliyunOssConfig {
private String endPoint;// 地域節點
private String accessKeyId;
private String accessKeySecret;
private String bucketName;// OSS的Bucket名稱
private String urlPrefix;// Bucket 域名
private String fileHost;// 目標檔案夾
// 將OSS 客戶端交給Spring容器托管
@Bean
public OSS OSSClient() {
return new OSSClient(endPoint, accessKeyId, accessKeySecret);
}
}
Swagger2Config.java
/**
* @Auther: csp1999
* @Date: 2020/10/31/16:30
* @Description: Swagger 配置類
*/
@Configuration
@EnableSwagger2// 開啟swagger2
public class Swagger2Config {
@Bean
public Docket webApiConfig() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("webApi")
.apiInfo(webApiInfo())
.select()
.paths(Predicates.not(PathSelectors.regex("/error.*")))
.build();
}
private ApiInfo webApiInfo() {
return new ApiInfoBuilder()
.title("SpringBoot整合OSS-API檔案")
.description("阿里云OSS-檔案上傳下載測驗")
.version("1.0")
.contact(new Contact("CSP", "https://blog.csdn.net/weixin_43591980", ""))
.build();
}
}
定義一個關于執行狀態結果的列舉類
/**
* @Auther: csp1999
* @Date: 2020/10/31/17:03
* @Description: 狀態碼列舉類
*/
public enum StatusCode {
SUCCESS("success",200),ERROR("error",500);
private String msg;
private Integer code;
StatusCode(String msg,Integer code){
this.msg = msg;
this.code = code;
}
StatusCode(Integer code){
this.code = code;
}
StatusCode(String msg){
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
service層
在service使用ossClient操作阿里云OSS,進行上傳、下載、洗掉、查看所有檔案等操作,同時可以將圖片的url進行入庫操作:
FileUploadService.java
/**
* @Auther: csp1999
* @Date: 2020/10/31/14:30
* @Description: 檔案上傳Service (為節省文章中的代碼篇幅,不再做介面實作類處理)
*/
@Service("fileUploadService")
public class FileUploadService {
// 允許上傳檔案(圖片)的格式
private static final String[] IMAGE_TYPE = new String[]{".bmp", ".jpg",
".jpeg", ".gif", ".png"};
@Autowired
private OSS ossClient;// 注入阿里云oss檔案服務器客戶端
@Autowired
private AliyunOssConfig aliyunOssConfig;// 注入阿里云OSS基本配置類
/*
* 檔案上傳
* 注:阿里云OSS檔案上傳官方檔案鏈接:https://help.aliyun.com/document_detail/84781.html?spm=a2c4g.11186623.6.749.11987a7dRYVSzn
* @param: uploadFile
* @return: string
* @create: 2020/10/31 14:36
* @author: csp1999
*/
public String upload(MultipartFile uploadFile) {
// 獲取oss的Bucket名稱
String bucketName = aliyunOssConfig.getBucketName();
// 獲取oss的地域節點
String endpoint = aliyunOssConfig.getEndPoint();
// 獲取oss的AccessKeySecret
String accessKeySecret = aliyunOssConfig.getAccessKeySecret();
// 獲取oss的AccessKeyId
String accessKeyId = aliyunOssConfig.getAccessKeyId();
// 獲取oss目標檔案夾
String filehost = aliyunOssConfig.getFileHost();
// 回傳圖片上傳后回傳的url
String returnImgeUrl = "";
// 校驗圖片格式
boolean isLegal = false;
for (String type : IMAGE_TYPE) {
if (StringUtils.endsWithIgnoreCase(uploadFile.getOriginalFilename(), type)) {
isLegal = true;
break;
}
}
if (!isLegal) {// 如果圖片格式不合法
return StatusCode.ERROR.getMsg();
}
// 獲取檔案原名稱
String originalFilename = uploadFile.getOriginalFilename();
// 獲取檔案型別
String fileType = originalFilename.substring(originalFilename.lastIndexOf("."));
// 新檔案名稱
String newFileName = UUID.randomUUID().toString() + fileType;
// 構建日期路徑, 例如:OSS目標檔案夾/2020/10/31/檔案名
String filePath = new SimpleDateFormat("yyyy/MM/dd").format(new Date());
// 檔案上傳的路徑地址
String uploadImgeUrl = filehost + "/" + filePath + "/" + newFileName;
// 獲取檔案輸入流
InputStream inputStream = null;
try {
inputStream = uploadFile.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
/**
* 下面兩行代碼是重點坑:
* 現在阿里云OSS 默認圖片上傳ContentType是image/jpeg
* 也就是說,獲取圖片鏈接后,圖片是下載鏈接,而并非在線瀏覽鏈接,
* 因此,這里在上傳的時候要解決ContentType的問題,將其改為image/jpg
*/
ObjectMetadata meta = new ObjectMetadata();
meta.setContentType("image/jpg");
//檔案上傳至阿里云OSS
ossClient.putObject(bucketName, uploadImgeUrl, inputStream, meta);
/**
* 注意:在實際專案中,檔案上傳成功后,資料庫中存盤檔案地址
*/
// 獲取檔案上傳后的圖片回傳地址
returnImgeUrl = "http://" + bucketName + "." + endpoint + "/" + uploadImgeUrl;
return returnImgeUrl;
}
/*
* 檔案下載
* @param: fileName
* @param: outputStream
* @return: void
* @create: 2020/10/31 16:19
* @author: csp1999
*/
public String download(String fileName, HttpServletResponse response) throws UnsupportedEncodingException {
// // 設定回應頭為下載
// response.setContentType("application/x-download");
// // 設定下載的檔案名
// response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
// response.setCharacterEncoding("UTF-8");
// 檔案名以附件的形式下載
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
// 獲取oss的Bucket名稱
String bucketName = aliyunOssConfig.getBucketName();
// 獲取oss目標檔案夾
String filehost = aliyunOssConfig.getFileHost();
// 日期目錄
// 注意,這里雖然寫成這種固定獲取日期目錄的形式,邏輯上確實存在問題,但是實際上,filePath的日期目錄應該是從資料庫查詢的
String filePath = new DateTime().toString("yyyy/MM/dd");
String fileKey = filehost + "/" + filePath + "/" + fileName;
// ossObject包含檔案所在的存盤空間名稱、檔案名稱、檔案元資訊以及一個輸入流,
OSSObject ossObject = ossClient.getObject(bucketName, fileKey);
try {
// 讀取檔案內容,
InputStream inputStream = ossObject.getObjectContent();
BufferedInputStream in = new BufferedInputStream(inputStream);// 把輸入流放入快取流
ServletOutputStream outputStream = response.getOutputStream();
BufferedOutputStream out = new BufferedOutputStream(outputStream);// 把輸出流放入快取流
byte[] buffer = new byte[1024];
int len = 0;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
if (out != null) {
out.flush();
out.close();
}
if (in != null) {
in.close();
}
return StatusCode.SUCCESS.getMsg();
} catch (Exception e) {
return StatusCode.ERROR.getMsg();
}
}
/*
* 檔案洗掉
* @param: objectName
* @return: java.lang.String
* @create: 2020/10/31 16:50
* @author: csp1999
*/
public String delete(String fileName) {
// 獲取oss的Bucket名稱
String bucketName = aliyunOssConfig.getBucketName();
// 獲取oss的地域節點
String endpoint = aliyunOssConfig.getEndPoint();
// 獲取oss的AccessKeySecret
String accessKeySecret = aliyunOssConfig.getAccessKeySecret();
// 獲取oss的AccessKeyId
String accessKeyId = aliyunOssConfig.getAccessKeyId();
// 獲取oss目標檔案夾
String filehost = aliyunOssConfig.getFileHost();
// 日期目錄
// 注意,這里雖然寫成這種固定獲取日期目錄的形式,邏輯上確實存在問題,但是實際上,filePath的日期目錄應該是從資料庫查詢的
String filePath = new DateTime().toString("yyyy/MM/dd");
try {
/**
* 注意:在實際專案中,不需要洗掉OSS檔案服務器中的檔案,
* 只需要洗掉資料庫存盤的檔案路徑即可!
*/
// 建議在方法中創建OSSClient 而不是使用@Bean注入,不然容易出現Connection pool shut down
OSSClient ossClient = new OSSClient(endpoint,
accessKeyId, accessKeySecret);
// 根據BucketName,filetName洗掉檔案
// 洗掉目錄中的檔案,如果是最后一個檔案fileoath目錄會被洗掉,
String fileKey = filehost + "/" + filePath + "/" + fileName;
ossClient.deleteObject(bucketName, fileKey);
try {
} finally {
ossClient.shutdown();
}
System.out.println("檔案洗掉!");
return StatusCode.SUCCESS.getMsg();
} catch (Exception e) {
e.printStackTrace();
return StatusCode.ERROR.getMsg();
}
}
}
controller層
controller提供測驗介面
/**
* @Auther: csp1999
* @Date: 2020/10/31/16:40
* @Description: OSS 檔案上傳controller
*/
@Api(description = "阿里云OSS檔案上傳、下載、洗掉API")
@RequestMapping("api/pri/file")
@RestController
public class OssFileController {
@Autowired
private FileUploadService fileUploadService;
/*
* 檔案上傳api
* @param: file
* @return: com.alibaba.fastjson.JSONObject
* @create: 2020/10/31 17:35
* @author: csp1999
*/
@ApiOperation(value = "檔案上傳")
@PostMapping("upload")
public JSONObject upload(@RequestParam("file") MultipartFile file) {
JSONObject jsonObject = new JSONObject();
if (file != null) {
String returnFileUrl = fileUploadService.upload(file);
if (returnFileUrl.equals("error")) {
jsonObject.put("error", "檔案上傳失敗!");
return jsonObject;
}
jsonObject.put("success", "檔案上傳成功!");
jsonObject.put("returnFileUrl", returnFileUrl);
return jsonObject;
} else {
jsonObject.put("error", "檔案上傳失敗!");
return jsonObject;
}
}
/*
* 檔案下載api
* @param: fileName
* @param: response
* @return: com.alibaba.fastjson.JSONObject
* @create: 2020/10/31 17:35
* @author: csp1999
*/
@ApiOperation(value = "檔案下載")
@GetMapping(value = "download/{fileName}")
public JSONObject download(@PathVariable("fileName") String fileName, HttpServletResponse response) throws Exception {
JSONObject jsonObject = new JSONObject();
String status = fileUploadService.download(fileName, response);
if (status.equals("error")) {
jsonObject.put("error", "檔案下載失敗!");
return jsonObject;
} else {
jsonObject.put("success", "檔案下載成功!");
return jsonObject;
}
}
/*
* 檔案洗掉api
* @param: fileName
* @return: com.alibaba.fastjson.JSONObject
* @create: 2020/10/31 17:35
* @author: csp1999
*/
@ApiOperation(value = "檔案洗掉")
@GetMapping("/delete/{fileName}")
public JSONObject DeleteFile(@PathVariable("fileName") String fileName) {
JSONObject jsonObject = new JSONObject();
String status = fileUploadService.delete(fileName);
if (status.equals("error")) {
jsonObject.put("error", "檔案洗掉失敗!");
return jsonObject;
} else {
jsonObject.put("success", "檔案洗掉成功!");
return jsonObject;
}
}
}
4.運行專案測驗API介面
本機訪問:http://localhost:8083/swagger-ui.html

測驗上傳:

結果如圖:

如果說明上傳成功,我們來看一下這個鏈接能不能訪問到:


上傳成功!
如果文章對您有幫助,三連一波萬分感謝!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/203088.html
標籤:其他
上一篇:Java -- Spring Boot -- 爬蟲從入門到精通 -- 爬取某二手房全部房屋資訊 -- 專案實戰(爬取兩萬+房屋出售資訊)
