本次使用minio进行文件服务搭建并使用
官方地址:https://docs.min.io/docs/distributed-minio-quickstart-guide.html
源码地址:https://github.com/minio/minio
1.添加pom文件
<dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>8.3.0</version> </dependency> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.9.1</version> </dependency>
2.yml配置
# 文件服务管理服务器 minio: # endpoint: http://192.168.*.*:10010 endpoint: http://127.0.0.1:9000 accessKey: minioadmin secretKey: minioadmin bucketName: xxx
3.代码样例
3.1 api接口
@CrossOrigin @RestController @Slf4j @Api(value = "文件管理",tags = "文件管理") @RequestMapping(value = "/fxaq/file") public class FileUploadController { @Autowired private MinioService minioService; @PostMapping(value = "/upload", headers = "content-type=multipart/form-data;charset=utf-8") @ApiOperation(value = "文件上传") public ResponseData uploadOneFile(@RequestParam(value = "multipartFile", required = false)MultipartFile multipartFile) throws Exception{ log.info("文件上传接口开始"); if (Objects.isNull(multipartFile) || multipartFile.getSize() == 0) { log.info("上传文件不能为空"); return ResponseData.failed(ConstantCode.FILE_EMPTY); } FileData fileData = minioService.uploadOne(multipartFile); if (Objects.nonNull(fileData)) { return ResponseData.ok(fileData); } return ResponseData.failed(ConstantCode.FILEUPLOAD_ERROR); } @PostMapping(value = "/filePreView") @ApiOperation(value = "文件预览") public void filePreView(FileData fileData,HttpServletResponse response) { log.info("文件预览接口开始"); try ( ServletOutputStream os = response.getOutputStream(); GetObjectResponse is = minioService.filePreView(fileData); ) { ByteStreams.copy(is, os); os.flush(); } catch (Exception e) { e.printStackTrace(); } } @PostMapping(value = "/download") @ApiOperation(value = "文件下载") public void downloadOneFile(FileData fileData,HttpServletResponse response) { try ( ServletOutputStream os = response.getOutputStream(); GetObjectResponse is = minioService.downloadOne(fileData.getBucketName(), fileData.getObjectName()); ) { //String objectName = new String(fileData.getObjectName().getBytes("UTF-8"), "UTF-8"); String objectName = URLEncoder.encode(fileData.getObjectName() , "UTF-8" );; response.addHeader("Accept-Ranges", "bytes"); response.addHeader("Content-Length", fileData.getFileLength() + ""); response.addHeader("Content-disposition", "attachment;filename=" + objectName); response.addHeader("Content-Type", "text/plain;charset=utf-8"); response.addHeader("Pragma","No-cache"); response.addHeader("Cache-Control","No-cache"); ByteStreams.copy(is, os); os.flush(); } catch (Exception e) { e.printStackTrace(); } } @PostMapping("/remove") @ApiOperation(value = "文件删除") public ResponseData removeFile(FileData fileData) { log.info("文件删除入参为: {} ", JSON.toJSONString(fileData)); boolean flag = minioService.removeObject(fileData.getBucketName(), fileData.getObjectName()); if (flag) { return ResponseData.ok(null); } return ResponseData.failed(ConstantCode.FILEUREMOVE_ERROR); } }
3.2 接口服务
@Service @Slf4j public class MinioService { /** * url分隔符 */ public static final String URI_DELIMITER = "/"; @Autowired private MinioClient minioClient; @Autowired private MinioProperties minioProperties; @Autowired private FileService fileService; private static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600; /** * 检查桶是否存在 * @param bucketName * @return * @throws Exception */ public boolean bucketExists(String bucketName) throws Exception { boolean flag = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); if (flag) { log.info("{} exists", bucketName); return true; } else { log.info("{} does not exist",bucketName); return false; } } /** * 创建桶 * @param bucketName * @return * @throws Exception */ public boolean makeBucket(String bucketName) throws Exception { boolean flag = bucketExists(bucketName); if (!flag) { minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); return true; } else { return false; } } /** * 上传文件 * * @param multipartFile */ @SneakyThrows public void upload(String bucketName,MultipartFile multipartFile) { PutObjectArgs putObjectArgs = PutObjectArgs.builder() .bucket(bucketName) .object(multipartFile.getOriginalFilename()) .contentType(multipartFile.getContentType()) .stream(multipartFile.getInputStream(), multipartFile.getSize(), -1) .build(); minioClient.putObject(putObjectArgs); } /** * 文件访问路径 * @param bucketName 存储桶名称 * @param objectName 存储桶里的对象名称 * @return */ @SneakyThrows public String getObjectUrl(String bucketName, String objectName){ boolean flag = bucketExists(bucketName); String url = ""; if (flag) { GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs.builder() .method(Method.GET) .bucket(bucketName) .object(objectName) .build(); url = minioClient.getPresignedObjectUrl(getPresignedObjectUrlArgs); } return url; } /** * 上传一个文件 * @param multipartFile * @return */ @SneakyThrows public FileData uploadOne(MultipartFile multipartFile) { String fileTypeCode = FileTypeUtils.getFileTypeCode(multipartFile.getOriginalFilename().toLowerCase()); String fileTypeName = FileTypeUtils.getFileTypeName(fileTypeCode); log.info("上传文件的类型是: {}, - {}", fileTypeCode,fileTypeName); String bucketName = minioProperties.getBucketName(); boolean flag = bucketExists(bucketName); if (!flag) { makeBucket(bucketName); } //上传文件 upload(bucketName, multipartFile); //获取文件url String url = getObjectUrl(bucketName,multipartFile.getOriginalFilename()); FileData fileData = new FileData(); fileData.setUrl(url); fileData.setBucketName(bucketName); fileData.setObjectName(multipartFile.getOriginalFilename()); fileData.setFileTypeCode(fileTypeCode); fileData.setFileTypeName(fileTypeName); fileData.setFileLength(multipartFile.getSize()); return fileData; } /** * 下载文件 * @param bucketName * @param objectName * @return */ @SneakyThrows public GetObjectResponse downloadOne(String bucketName,String objectName) { boolean flag = bucketExists(bucketName); if (flag) { GetObjectArgs getObjectArgs = GetObjectArgs.builder() .bucket(bucketName) .object(objectName) .build(); return minioClient.getObject(getObjectArgs); } return null; } /** * 文件转换 * @param fileData * @return */ @SneakyThrows public GetObjectResponse filePreView(FileData fileData) { String bucketName = fileData.getBucketName(); String objectName = fileData.getObjectName(); GetObjectArgs getObjectArgs = GetObjectArgs.builder() .bucket(bucketName) .object(objectName) .build(); GetObjectResponse response = minioClient.getObject(getObjectArgs); String outPath = "./" + objectName.split("\\.")[0] + ".pdf"; return response; //fileService.word2pdf(fileData.getUrl(),outPath); /*if (flag) { //获取到文件流 *//* String fileTypeCode = fileData.getFileTypeCode();*//* String outPath = "./" + fileData.getObjectName().substring(0) File inFile = new File(fileData.getUrl()); File outFile = new File(outPath); fileService.word2pdf(fileData.getUrl(),outPath); }*/ } /** * 删除文件 * @param bucketName * @param objectName * @return */ @SneakyThrows public boolean removeObject(String bucketName, String objectName) { boolean flag = bucketExists(bucketName); if (flag) { RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder() .bucket(bucketName) .object(objectName) .build(); minioClient.removeObject(removeObjectArgs); return true; } return false; } }
3.3文件服务配置
@Configuration public class MinioConfig { @Autowired private MinioProperties minioProperties; @Bean("minioClient") public MinioClient minioClient(){ return MinioClient.builder() .endpoint(minioProperties.getEndpoint()) .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey()) .build(); } }
3.4相关实体 MinioProperties (文件服务配置封装实体) FileData (文件返回值)
@Data @Component @ConfigurationProperties(prefix = "minio") public class MinioProperties { @Value("${minio.endpoint}") private String endpoint; @Value("${minio.accessKey}") private String accessKey; @Value("${minio.secretKey}") private String secretKey; @Value("${minio.bucketName}") private String bucketName; }
@Data @ApiModel(value = "文件返回值",description = "文件返回值") public class FileData implements Serializable { private static final long serialVersionUID = 2909024418136560072L; @ApiModelProperty(value = "文件url") private String url; @ApiModelProperty(value = "桶") private String bucketName; @ApiModelProperty(value = "文件名") private String objectName; @ApiModelProperty(value = "文件类型") private String fileTypeCode; @ApiModelProperty(value = "文件类型名称") private String fileTypeName; @ApiModelProperty(value = "文件长度") private Long fileLength; }