廣東東莞網(wǎng)站建設(shè)微信管理軟件哪個最好
需求
要實現(xiàn)的功能是:實現(xiàn)一個可以支持minio+oss兩種方式,上傳下載文件的自定義依賴。其中還包括一些創(chuàng)建桶、刪除桶、刪除文件等功能,但是最主要的是實現(xiàn)自動配置。
如果對spring理解很深的話,自動配置這些東西很容易理解,但是對于技術(shù)小白來講只能按葫蘆畫瓢。
首先,StorageManager是我的自定義依賴對外提供的要注入spring的對象,其中的方法是對外提供的方法,方法返回的是StorageService接口。
package cn.chinatelecom.dxsc.park.oss;import cn.chinatelecom.dxsc.park.oss.entity.FileDomain;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;public class StorageManager {private static final Logger log = LoggerFactory.getLogger(StorageManager.class);private final StorageService storageService;public StorageManager(StorageService storageService) {this.storageService = storageService;}/*** 創(chuàng)建存儲桶** @param bucketName 桶名稱*/public void createBucket(String bucketName) {storageService.createBucket(bucketName);}/*** 刪除桶* @param bucketName 桶名稱* @return*/public Boolean removeBucket(String bucketName) {Boolean removeBucket = storageService.removeBucket(bucketName);return removeBucket;}/*** 刪除文件* @param fileName* @return*/public Boolean remove(String fileName){return storageService.remove(fileName);}/*** 下載文件** @param filePath 文件路徑* @return 文件流*/public InputStream getObject(String filePath) {return storageService.getObject(filePath);}/*** 上傳文件* @param file* @return*/public FileDomain saveFile(MultipartFile file) {FileDomain result = new FileDomain();try {InputStream in = file.getInputStream();long size = file.getSize();String contentType = file.getContentType();String fileName = generateName(file.getOriginalFilename());String filePath = generateKey(fileName);String url = storageService.saveFile(in, size, contentType, filePath);result.setSize(size);result.setUrl(url);result.setKey(filePath);result.setType(contentType);} catch (IOException e) {log.error("保存文件失敗", e);throw new RuntimeException(e);}return result;}private String generateName(String originalFilename) {return UUID.randomUUID().toString().replace("-", "") + originalFilename.substring(originalFilename.lastIndexOf("."));}private String generateKey(String fileName) {// 2022-10/24/b4c9106e3f574a61841ce4624494f0cc.jpg 在刪除和下載文件時需要傳入路徑才可以刪除和下載return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM/dd")) + "/" + fileName;}}
StorageService接口定義:
package cn.chinatelecom.dxsc.park.oss;import io.minio.errors.*;import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;public interface StorageService {/*** 創(chuàng)建存儲桶* @param bucketName 桶名稱*/void createBucket(String bucketName);/*** 存儲文件* @param inputStream 文件流* @param fileSize 文件大小* @param contentType 文件類型* @param keyName 文件名及路徑*/String saveFile(InputStream inputStream, long fileSize, String contentType, String keyName);/*** 下載文件* @param filePath 文件路徑* @return*/InputStream getObject(String filePath);/*** 刪除文件* @param fileName* @return*/Boolean remove(String fileName);/*** 刪除桶* @param bucketName 桶名稱* @return*/Boolean removeBucket(String bucketName);
}
FileDomain是上傳文件時返回的對象,其中包括文件url,文件在服務(wù)器的存儲路徑,文件類型、大小等等可以自己定義,這里沒有使用@Data注解而是手寫get和set方法,沒有引入Lombok依賴是因為在實現(xiàn)自定義依賴的時候,盡量能不引入依賴就不引入依賴。如果你在自定義依賴?yán)锩嬉氚姹?.0的Lombok,但是當(dāng)別人引用你的依賴的時候,同時也引用的1.0的Lombok,這樣就會出現(xiàn)最讓人頭疼的版本沖突問題,為了避免這種問題出現(xiàn),盡量不要在底層引用過多依賴。
package cn.chinatelecom.dxsc.park.oss.entity;public class FileDomain {/*** 路徑名稱*/private String key;/*** 文件url*/private String url;/*** 文件類型(contentType)*/private String type;/*** 文件大小*/private Long size;public String getKey() {return key;}public void setKey(String key) {this.key = key;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getType() {return type;}public void setType(String type) {this.type = type;}public Long getSize() {return size;}public void setSize(Long size) {this.size = size;}
}
接下來是自動配置的相關(guān)代碼
DxscStorageProperties是需要配置的一些屬性,比如accessKey以及accessSecret等等。
@ConfigurationProperties注解,在 SpringBoot 中,當(dāng)想需要獲取到配置文件數(shù)據(jù)時,除了可以用 Spring 自帶的 @Value 注解外,SpringBoot 還提供了一種更加方便的方式:@ConfigurationProperties。只要在 Bean 上添加上了這個注解,指定好配置文件的前綴,那么對應(yīng)的配置文件數(shù)據(jù)就會自動填充到 Bean 中。
package cn.chinatelecom.dxsc.park.oss.config;import org.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties(prefix = "dxsc.storage")
public class DxscStorageProperties {/*** 激活哪種存儲*/private String active;/*** oss地址*/private String endpoint;/*** 桶名稱*/private String bucketName;private String accessKey;private String accessSecret;public String getActive() {return active;}public void setActive(String active) {this.active = active;}public String getEndpoint() {return endpoint;}public void setEndpoint(String endpoint) {this.endpoint = endpoint;}public String getBucketName() {return bucketName;}public void setBucketName(String bucketName) {this.bucketName = bucketName;}public String getAccessKey() {return accessKey;}public void setAccessKey(String accessKey) {this.accessKey = accessKey;}public String getAccessSecret() {return accessSecret;}public void setAccessSecret(String accessSecret) {this.accessSecret = accessSecret;}}
接下來的代碼才是重中之重DxscStorageAutoConfiguration,此類將DxscStorageProperties注入到spring中,Spring Boot 會掃描到類路徑下的META-INF/spring.factories配置文件,把DxscStorageAutoConfiguration對應(yīng)的的Bean值添加到容器中。
package cn.chinatelecom.dxsc.park.oss.autoconfigure;import cn.chinatelecom.dxsc.park.oss.StorageManager;
import cn.chinatelecom.dxsc.park.oss.StorageService;
import cn.chinatelecom.dxsc.park.oss.config.DxscStorageProperties;
import cn.chinatelecom.dxsc.park.oss.impl.MinioStorageServiceImpl;
import cn.chinatelecom.dxsc.park.oss.impl.OssStorageServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@EnableConfigurationProperties(DxscStorageProperties.class)
@Configuration
public class DxscStorageAutoConfiguration {@Autowiredprivate DxscStorageProperties dxscStorageProperties;@Beanpublic StorageManager storageManager(StorageService storageService) {return new StorageManager(storageService);}@Bean@ConditionalOnProperty(prefix = "dxsc.storage", value = "active", havingValue = "minio")public StorageService minioService() {return new MinioStorageServiceImpl(dxscStorageProperties);}
//prefix為前綴,value為選擇哪個屬性,havingValue就是啟用哪種方式,當(dāng)active屬性為minio時就調(diào)用上面的,oss就調(diào)用下面的,
//大概就是這個意思@Bean@ConditionalOnProperty(prefix = "dxsc.storage", value = "active", havingValue = "oss")public StorageService OssService() {return new OssStorageServiceImpl(dxscStorageProperties);}}
spring.factories文件:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.chinatelecom.dxsc.park.oss.autoconfigure.DxscStorageAutoConfiguration
其中MinioStorageServiceImpl和OssStorageServiceImpl就是實現(xiàn)的文件上傳下載的接口,再此展示minion的接口:
oss接口可以查看官方文檔,其中寫得很清楚。
package cn.chinatelecom.dxsc.park.oss.impl;import cn.chinatelecom.dxsc.park.oss.StorageService;
import cn.chinatelecom.dxsc.park.oss.config.DxscStorageProperties;
import io.minio.*;
import io.minio.http.Method;import java.io.InputStream;public class MinioStorageServiceImpl implements StorageService {private final DxscStorageProperties dxscStorageProperties;private final MinioClient minioClient;public MinioStorageServiceImpl(DxscStorageProperties dxscStorageProperties) {this.dxscStorageProperties =dxscStorageProperties;this.minioClient = MinioClient.builder().endpoint(dxscStorageProperties.getEndpoint()).credentials(dxscStorageProperties.getAccessKey(), dxscStorageProperties.getAccessSecret()).build();}@Overridepublic void createBucket(String bucketName){boolean isExist = false;// 檢查存儲桶是否已經(jīng)存在try{isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());if (!isExist) {//創(chuàng)建桶minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config("{\"Version\":\"2023-2-20\",\"Statement\":[]}").build());}}catch (Exception e){throw new RuntimeException(e);}}@Overridepublic String saveFile(InputStream inputStream, long fileSize, String contentType, String keyName) {try {PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(dxscStorageProperties.getBucketName()).object(keyName).stream(inputStream, fileSize, -1).contentType(contentType).build();//文件名稱相同會覆蓋minioClient.putObject(objectArgs);// 查看文件地址GetPresignedObjectUrlArgs build = new GetPresignedObjectUrlArgs().builder().bucket(dxscStorageProperties.getBucketName()).object(keyName).method(Method.GET).build();try {return minioClient.getPresignedObjectUrl(build);} catch (Exception e) {throw new RuntimeException(e);}} catch (Exception e) {throw new RuntimeException(e);}}@Overridepublic InputStream getObject(String filePath) {try{GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(dxscStorageProperties.getBucketName()).object(filePath).build();return minioClient.getObject(objectArgs);}catch (Exception e){System.out.println("下載失敗");throw new RuntimeException(e);}}@Overridepublic Boolean remove(String fileName) {try {minioClient.removeObject(RemoveObjectArgs.builder().bucket(dxscStorageProperties.getBucketName()).object(fileName).build());} catch (Exception e) {return false;}return true;}@Overridepublic Boolean removeBucket(String bucketName) {try {//在刪除桶時,需要注意一下不能刪除自身,當(dāng)你的配置文件里的bucketName的test時還要刪除test,是不能刪除成功的//bucketName為test1時,刪除test,是可以的minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());} catch (Exception e) {return false;}return true;}
}
至此,自定義依賴完成,接下來是引用,引用方法為先將自定義依賴上傳至本地maven庫,然后才可以導(dǎo)入依賴,
<dependency><artifactId>dxsc-park-frame-oss</artifactId><groupId>cn.chinatelecom</groupId><version>1.0.0-SNAPSHOT</version></dependency>
然后,配置minio或者oss的accessKey和accessSecret等屬性:
(active為minio就是通過minion方式實現(xiàn)文件上傳下載)
dxsc:storage:active: minioendpoint: http://***.168.30.27:9000bucketName: dxsc-parkaccessKey: minioadminaccessSecret: minioadmin
# storage:
# active: oss
# endpoint: https://oss-cn-beijing.aliyuncs.com
# bucketName: dxsc-park
# accessKey: ***
# accessSecret: ***
server:port: 1101
最后注入StorageManager,在一開始的時候就說過StorageManager是對外提供的:
package cn.chinatelecom.dxsc.park.test.controller;import cn.chinatelecom.dxsc.park.oss.StorageManager;
import cn.chinatelecom.dxsc.park.oss.entity.FileDomain;
import org.apache.tomcat.util.http.fileupload.IOUtils;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;@RestController
@RequestMapping("/minio")
public class TestController {@Autowiredprivate StorageManager storageManager;@PostMapping("/createBucket")public void createBucket(@RequestParam("bucketName") String bucketName){storageManager.createBucket(bucketName);}@PostMapping("/removeBucket")public void removeBucket(@RequestParam("bucketName") String bucketName){storageManager.removeBucket(bucketName);}@PostMapping("/upload")public String upload(@RequestParam("file") MultipartFile file){FileDomain fileDomain = storageManager.saveFile(file);System.out.println(fileDomain.getUrl());return fileDomain.getKey();}@PostMapping("/remove")public Boolean remove(@RequestParam("fileName") String fileName){Boolean remove = storageManager.remove(fileName);return remove;}@PostMapping("/getObject")public void getObject(@RequestParam("filePath") String filePath, HttpServletResponse response) throws IOException {InputStream object = storageManager.getObject(filePath);response.setContentType("application/octet-stream");response.addHeader("Content-Disposition", "attachment;filename=" + "fileName");IOUtils.copy(object, response.getOutputStream());IOUtils.closeQuietly(object);}}
以上就是我在實現(xiàn)自動配置的全部內(nèi)容
一個集堅強(qiáng)與自信于一身的菇?jīng)觥?/p>