搭建檔案伺服器 MinIO
阿新 • • 發佈:2022-03-19
1 下載
minio官方文件
我選擇的是docker部署
docker pull minio/minio
docker run \
-p 9000:9000 \
-p 9001:9001 \
--name minio1 \
-v ~/minio/data:/data \
-e "MINIO_ROOT_USER=username" \
-e "MINIO_ROOT_PASSWORD=password" \
-d \
quay.io/minio/minio server /data --console-address ":9001"
訪問http://101.42.135.107:9001/
進入控制檯介面 ( 如果是雲伺服器記得開啟9001埠)
2 上傳檔案到minio
建立名為hms的桶
然後上傳一個圖片
設定訪問規則:
新增只讀屬性,字首為 “*”,這樣就可以瀏覽器訪問了
2 SpringBoot整合
2.1 依賴,主啟動
最開始用的8.3.7, 和我的jar包衝突了,又換成8.2.1
<dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.2.1</version> </dependency>
2.2 配置檔案
server: port: 9201 spring: application: name: file datasource: username: root password: 18170021 url: jdbc:mysql://localhost:3306/db_hms_file?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai driver-class-name: com.mysql.cj.jdbc.Driver cloud: nacos: server-addr: localhost:8848 # 配置檔案大小限制 servlet: multipart: max-file-size: 100MB max-request-size: 100MB minio: # minio配置是自定義的配置,注意:一定加http:// endpoint: http://localhost:9000 accessKey: root secretKey: root18170021 bucketName: hms mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
2.3 Minio客戶端配置類
@Data
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioClientConfig {
private String endpoint;
private String accessKey;
private String secretKey;
@Bean
public MinioClient minioClient() {
MinioClient minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
return minioClient;
}
}
2.4 工具類
不要被嚇跑哦,我只用到其中的上傳下載刪除三個方法,不過以後可能會用到就都copy過來了
@Component
public class MinioUtil {
@Autowired
private MinioClient minioClient;
/**
* 檢視儲存bucket是否存在
* @return boolean
*/
public Boolean bucketExists(String bucketName) {
Boolean found;
try {
found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
} catch (Exception e) {
return false;
}
return found;
}
/**
* 建立儲存bucket
* @return Boolean
*/
public Boolean makeBucket(String bucketName) {
try {
minioClient.makeBucket(MakeBucketArgs.builder()
.bucket(bucketName)
.build());
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 刪除儲存bucket
* @return Boolean
*/
public Boolean removeBucket(String bucketName) {
try {
minioClient.removeBucket(RemoveBucketArgs.builder()
.bucket(bucketName)
.build());
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 獲取全部bucket
*/
public List<Bucket> getAllBuckets() {
try {
return minioClient.listBuckets();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 檔案上傳
* @param file 檔案
* @return Boolean
*/
public Boolean upload(String bucketName, String fileName, MultipartFile file, InputStream inputStream) {
try {
PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(fileName)
.stream(inputStream,file.getSize(),-1).contentType(file.getContentType()).build();
//檔名稱相同會覆蓋
minioClient.putObject(objectArgs);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 預覽圖片
* @param fileName
* @return
*/
public String preview(String fileName,String bucketName){
// 檢視檔案地址
GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs
.builder().bucket(bucketName)
.object(fileName)
.method(Method.GET).build();
try {
String url = minioClient.getPresignedObjectUrl(build);
return url;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 檔案下載
* @param fileName 檔名稱
* @param res response
* @return Boolean
*/
public void download(String fileName,String bucketName, HttpServletResponse res) {
GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName)
.object(fileName).build();
try (GetObjectResponse response = minioClient.getObject(objectArgs)){
byte[] buf = new byte[1024];
int len;
try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()){
while ((len=response.read(buf))!=-1){
os.write(buf,0,len);
}
os.flush();
byte[] bytes = os.toByteArray();
res.setCharacterEncoding("utf-8");
//設定強制下載不開啟
//res.setContentType("application/force-download");
res.addHeader("Content-Disposition", "attachment;fileName=" + fileName);
try (ServletOutputStream stream = res.getOutputStream()){
stream.write(bytes);
stream.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 檢視檔案物件
* @return 儲存bucket內檔案物件資訊
*/
public List<Item> listObjects(String bucketName) {
Iterable<Result<Item>> results = minioClient.listObjects(
ListObjectsArgs.builder().bucket(bucketName).build());
List<Item> items = new ArrayList<>();
try {
for (Result<Item> result : results) {
items.add(result.get());
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return items;
}
/**
* 刪除
* @param fileName
* @return
* @throws Exception
*/
public boolean remove(String fileName,String bucketName){
try {
minioClient.removeObject( RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
}catch (Exception e){
return false;
}
return true;
}
/**
* 批量刪除檔案物件(沒測試)
* @param objects 物件名稱集合
*/
public Iterable<Result<DeleteError>> removeObjects(List<String> objects, String bucketName) {
List<DeleteObject> dos = objects.stream().map(e -> new DeleteObject(e)).collect(Collectors.toList());
Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build());
return results;
}
}
2.5 Controller
@RestController
@RequestMapping("file")
public class FileController {
private static final Logger log = LogManager.getLogger();
@Autowired
private FileItemServiceImpl fileItemService;
@PostMapping("upload")
public Result upload(@Valid @NotNull @RequestParam(value = "file") MultipartFile file, @Valid @NotNull Integer type) {
Result result;
try {
FileItemVO fileItemVO = fileItemService.uploadFile(file, type);
result = Result.success("檔案上傳成功!", fileItemVO);
} catch (BcException e) {
result = Result.error(e.getCode(), e.getMessage());
log.error(e.getMessage());
}
return result;
}
@GetMapping("download")
public void download(HttpServletResponse response,
@Valid @RequestParam @NotBlank(message = "fileId不能為空") Integer fileId) {
try {
fileItemService.downloadFile(fileId, response);
} catch (BcException e) {
log.error(e.getMessage());
}
}
@GetMapping("delete")
public Result<String> delete(@Valid @RequestParam @NotBlank(message = "fileId不能為空") Long fileId) {
Result result;
try {
fileItemService.deleteFile(fileId);
result = Result.success("刪除附件成功!", fileId);
} catch (BcException e) {
result = Result.error(e.getCode(), e.getMessage());
}
return result;
}
}
2.6 Service
service
public interface FileItemService {
/**
* 上傳檔案到伺服器中
* @param file
* @param type
* @return
*/
FileItemVO uploadFile(MultipartFile file, Integer type);
/**
* 下載檔案
* @param fileId
* @param response
*/
void downloadFile(Integer fileId, HttpServletResponse response);
/**
* 刪除檔案
* @param fileId
*/
void deleteFile(Long fileId);
}
serviceImpl
@Service
public class FileItemServiceImpl implements FileItemService {
@Resource
private MinioUtil minioUtil;
@Value("${minio.bucketName}")
private String bucketName;
@Value("${minio.endpoint}")
private String endpoint;
@Autowired
private FileMapper fileMapper;
private String[] fileFolders = new String[]{"doctorPhotos/", "report", "otherImage/"};
@Override
@Transactional(rollbackFor = Exception.class)
public FileItemVO uploadFile(MultipartFile file, Integer type) {
FileItemVO fileItemVO = null;
try {
String fileName = file.getOriginalFilename();
String ext = fileName.substring(fileName.lastIndexOf("."));
String newFileName = fileFolders[type] + UUID.randomUUID().toString().replaceAll("-", "") + ext;
InputStream inputStream = file.getInputStream();
Boolean flag = minioUtil.upload(bucketName, newFileName,file, inputStream);
if(!flag) {
throw new BcException(ErrorCode.file_upload_fail.getCode(), "檔案上傳失敗");
}
String url = getUrl(newFileName);
fileItemVO = FileItemVO.builder()
.newFileName(newFileName)
.fileName(fileName)
.ext(ext)
.url(url)
.build();
FileEntity fileEntity = new FileEntity();
BeanUtils.copyProperties(fileItemVO, fileEntity);
fileEntity.setType(type);
fileMapper.insert(fileEntity);
fileItemVO.setFileId(fileEntity.getId());
} catch (Exception e) {
throw new BcException(ErrorCode.file_upload_fail.getCode(), "檔案上傳失敗");
}
return fileItemVO;
}
@Transactional(readOnly = true)
@Override
public void downloadFile(Integer fileId, HttpServletResponse response) {
FileEntity fileEntity = fileMapper.selectById(fileId);
if(ObjectUtils.isEmpty(fileEntity)) {
throw new BcException(ErrorCode.file_not_exit.getCode(), "檔案不存在");
}
try {
minioUtil.download(fileEntity.getNewFileName(), bucketName, response);
} catch (Exception e) {
throw new BcException(ErrorCode.download_id_exception.getCode(), "檔案下載失敗");
}
}
@Transactional(rollbackFor = Exception.class)
@Override
public void deleteFile(Long fileId) {
FileEntity fileEntity = fileMapper.selectById(fileId);
if(ObjectUtils.isEmpty(fileEntity)) {
throw new BcException(ErrorCode.file_not_exit.getCode(), "檔案不存在");
}
try {
minioUtil.remove(fileEntity.getNewFileName(), bucketName);
fileMapper.deleteById(fileId);
} catch (Exception e) {
throw new BcException(ErrorCode.download_id_exception.getCode(), "檔案刪除失敗");
}
}
private String getUrl(String newFileName) {
return endpoint
+ "/"
+ bucketName
+ "/"
+ newFileName;
}
}
2.7 實體和資料庫
FileItemVO (上傳檔案後響應結果)
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class FileItemVO {
/**
* 檔案id
*/
private Long fileId;
/**
* 檔案可訪問URL
*/
private String url;
/**
* 檔案的拓展名
*/
private String ext;
/**
* 上傳的原始檔的檔名,帶有拓展
*/
private String fileName;
/**
* 上傳後的檔名
*/
private String newFileName;
}
file表
DROP TABLE IF EXISTS `file`;
CREATE TABLE `file` (
`id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT 'id',
`file_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '使用者上傳檔案的原始名稱,帶有檔案拓展',
`ext` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '檔案拓展名',
`type` int(0) NOT NULL COMMENT '檔案型別:1醫生照片 2其他圖片 3體檢報告',
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'url',
`new_file_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'minio裡面的檔名',
`created_time` datetime(0) NOT NULL COMMENT '建立時間',
`modified_time` datetime(0) NOT NULL COMMENT '修改時間',
`state` int(0) NOT NULL DEFAULT 0 COMMENT '狀態',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;