依赖
< dependency> < groupId> io.minio</ groupId> < artifactId> minio</ artifactId> < version> 8.5.3</ version> </ dependency>
配置项
minio : url : http: //localhost: 9000 accessKey : exampleAccessKeysecretKey : exampleSecretKeybucket : exampleBucketaccessUrl : http: //localhost: 9000/exampleBucket
配置属性绑定
@Data
@ConfigurationProperties ( prefix = "minio" )
public class MinioProperties { private String url; private String accessKey; private String secretKey; private String bucket; private String accessUrl;
}
工具类:
import io. minio. * ;
import io. minio. errors. MinioException ;
import io. minio. http. Method ;
import io. minio. messages. Bucket ;
import io. minio. messages. DeleteObject ;
import io. minio. messages. Item ;
import lombok. extern. slf4j. Slf4j ;
import org. springframework. web. multipart. MultipartFile ; import javax. servlet. ServletOutputStream ;
import javax. servlet. http. HttpServletRequest ;
import javax. servlet. http. HttpServletResponse ;
import java. io. * ;
import java. net. URL;
import java. net. URLConnection ;
import java. net. URLDecoder ;
import java. net. URLEncoder ;
import java. nio. charset. StandardCharsets ;
import java. security. InvalidKeyException ;
import java. security. NoSuchAlgorithmException ;
import java. util. * ;
import java. util. concurrent. TimeUnit ;
import java. util. zip. ZipEntry ;
import java. util. zip. ZipOutputStream ;
@Slf4j
public class MinioUtils { private static MinioClient minioClient; private static String endpoint; private static String accessKey; private static String secretKey; private static final String SEPARATOR = "/" ; private MinioUtils ( ) { } public MinioUtils ( String endpoint, String accessKey, String secretKey) { MinioUtils . endpoint = endpoint; MinioUtils . accessKey = accessKey; MinioUtils . secretKey = secretKey; createMinioClient ( ) ; } public void createMinioClient ( ) { try { if ( null == minioClient) { minioClient = MinioClient . builder ( ) . endpoint ( endpoint) . credentials ( accessKey, secretKey) . build ( ) ; System . err. println ( "创建Minio通道成功!" ) ; } } catch ( Exception e) { System . err. println ( "创建Minio通道失败!" ) ; } } public static String getBasisUrl ( String bucketName) { return endpoint + SEPARATOR + bucketName + SEPARATOR; } public static boolean bucketExists ( String bucketName) throws Exception { return minioClient. bucketExists ( BucketExistsArgs . builder ( ) . bucket ( bucketName) . build ( ) ) ; } public static void createBucket ( String bucketName) throws Exception { if ( ! minioClient. bucketExists ( BucketExistsArgs . builder ( ) . bucket ( bucketName) . build ( ) ) ) { minioClient. makeBucket ( MakeBucketArgs . builder ( ) . bucket ( bucketName) . build ( ) ) ; } } public static List < Bucket > getAllBuckets ( ) throws Exception { return minioClient. listBuckets ( ) ; } public static Optional < Bucket > getBucket ( String bucketName) throws Exception { return minioClient. listBuckets ( ) . stream ( ) . filter ( b -> b. name ( ) . equals ( bucketName) ) . findFirst ( ) ; } public static void removeBucket ( String bucketName) throws Exception { minioClient. removeBucket ( RemoveBucketArgs . builder ( ) . bucket ( bucketName) . build ( ) ) ; } public static boolean doesObjectExist ( String bucketName, String objectName) { boolean exist = true ; try { minioClient. statObject ( StatObjectArgs . builder ( ) . bucket ( bucketName) . object ( objectName) . build ( ) ) ; } catch ( Exception e) { exist = false ; } return exist; } public static boolean doesFolderExist ( String bucketName, String objectName) { boolean exist = false ; try { Iterable < Result < Item > > results = minioClient. listObjects ( ListObjectsArgs . builder ( ) . bucket ( bucketName) . prefix ( objectName) . recursive ( false ) . build ( ) ) ; for ( Result < Item > result : results) { Item item = result. get ( ) ; if ( item. isDir ( ) && objectName. equals ( item. objectName ( ) ) ) { exist = true ; } } } catch ( Exception e) { exist = false ; } return exist; } public static List < Item > getAllObjectsByPrefix ( String bucketName, String prefix, boolean recursive) throws Exception { List < Item > list = new ArrayList < > ( ) ; Iterable < Result < Item > > objectsIterator = minioClient. listObjects ( ListObjectsArgs . builder ( ) . bucket ( bucketName) . prefix ( prefix) . recursive ( recursive) . build ( ) ) ; if ( objectsIterator != null ) { for ( Result < Item > o : objectsIterator) { Item item = o. get ( ) ; list. add ( item) ; } } return list; } public static ObjectWriteResponse putObject ( String bucketName, MultipartFile file, String objectName, String contentType) throws Exception { InputStream inputStream = file. getInputStream ( ) ; return minioClient. putObject ( PutObjectArgs . builder ( ) . bucket ( bucketName) . object ( objectName) . contentType ( contentType) . stream ( inputStream, inputStream. available ( ) , - 1 ) . build ( ) ) ; } public static ObjectWriteResponse putObject ( String bucketName, MultipartFile file, String objectName) throws Exception { InputStream inputStream = file. getInputStream ( ) ; return minioClient. putObject ( PutObjectArgs . builder ( ) . bucket ( bucketName) . object ( objectName) . stream ( inputStream, inputStream. available ( ) , - 1 ) . build ( ) ) ; } public static ObjectWriteResponse putObject ( String bucketName, String objectName, String filePath) throws Exception { URLConnection urlConnection = new URL ( filePath) . openConnection ( ) ; return minioClient. putObject ( PutObjectArgs . builder ( ) . bucket ( bucketName) . object ( objectName) . contentType ( urlConnection. getContentType ( ) ) . stream ( urlConnection. getInputStream ( ) , urlConnection. getContentLength ( ) , - 1 ) . build ( ) ) ; } public static ObjectWriteResponse putObject ( String bucketName, String fileAbsName, URLConnection connection) throws Exception { InputStream inputStream = connection. getInputStream ( ) ; return minioClient. putObject ( PutObjectArgs . builder ( ) . bucket ( bucketName) . object ( fileAbsName) . contentType ( connection. getContentType ( ) ) . stream ( inputStream, inputStream. available ( ) , - 1 ) . build ( ) ) ; } public static ObjectWriteResponse putObject ( String bucketName, String objectName, InputStream inputStream) throws Exception { return minioClient. putObject ( PutObjectArgs . builder ( ) . bucket ( bucketName) . object ( objectName) . stream ( inputStream, inputStream. available ( ) , - 1 ) . build ( ) ) ; } public static ObjectWriteResponse putDirObject ( String bucketName, String objectName) throws Exception { return minioClient. putObject ( PutObjectArgs . builder ( ) . bucket ( bucketName) . object ( objectName) . stream ( new ByteArrayInputStream ( new byte [ ] { } ) , 0 , - 1 ) . build ( ) ) ; } public static ObjectWriteResponse copyObject ( String bucketName, String objectName, String srcBucketName, String srcObjectName) throws Exception { return minioClient. copyObject ( CopyObjectArgs . builder ( ) . source ( CopySource . builder ( ) . bucket ( bucketName) . object ( objectName) . build ( ) ) . bucket ( srcBucketName) . object ( srcObjectName) . build ( ) ) ; } public static void downloadFile ( String bucketName, String originalName, HttpServletRequest request, HttpServletResponse response) { try { InputStream file = getObject ( bucketName, originalName) ; String useragent = request. getHeader ( "USER-AGENT" ) . toLowerCase ( ) ; if ( useragent. contains ( "msie" ) || useragent. contains ( "like gecko" ) || useragent. contains ( "trident" ) ) { originalName = URLEncoder . encode ( originalName, StandardCharsets . UTF_8. displayName ( ) ) ; } else { originalName = new String ( originalName. getBytes ( StandardCharsets . UTF_8) , StandardCharsets . ISO_8859_1) ; } response. setCharacterEncoding ( "UTF-8" ) ; response. setHeader ( "Content-Disposition" , "attachment;filename=" + originalName) ; ServletOutputStream servletOutputStream = response. getOutputStream ( ) ; int len; byte [ ] buffer = new byte [ 1024 ] ; while ( ( len = file. read ( buffer) ) > 0 ) { servletOutputStream. write ( buffer, 0 , len) ; } servletOutputStream. flush ( ) ; file. close ( ) ; servletOutputStream. close ( ) ; } catch ( Exception e) { System . err. println ( String . format ( "下载文件:%s异常" , originalName) ) ; } } public static InputStream getObject ( String bucketName, String objectName) throws Exception { return minioClient. getObject ( GetObjectArgs . builder ( ) . bucket ( bucketName) . object ( objectName) . build ( ) ) ; } public InputStream getObject ( String bucketName, String objectName, long offset, long length) throws Exception { return minioClient. getObject ( GetObjectArgs . builder ( ) . bucket ( bucketName) . object ( objectName) . offset ( offset) . length ( length) . build ( ) ) ; } public static Iterable < Result < Item > > listObjects ( String bucketName, String prefix, boolean recursive) { return minioClient. listObjects ( ListObjectsArgs . builder ( ) . bucket ( bucketName) . prefix ( prefix) . recursive ( recursive) . build ( ) ) ; } public static Iterable < Result < Item > > listObjects ( String bucketName, boolean recursive) { return minioClient. listObjects ( ListObjectsArgs . builder ( ) . bucket ( bucketName) . recursive ( recursive) . build ( ) ) ; } public static void removeObject ( String bucketName, String objectName) throws Exception { minioClient. removeObject ( RemoveObjectArgs . builder ( ) . bucket ( bucketName) . object ( objectName) . build ( ) ) ; } public static void removeObjects ( String bucketName, List < String > keys) { List < DeleteObject > objects = new LinkedList < > ( ) ; keys. forEach ( s -> { objects. add ( new DeleteObject ( s) ) ; try { removeObject ( bucketName, s) ; } catch ( Exception e) { System . err. println ( "批量删除失败!" ) ; } } ) ; } public static String getPreviewUrl ( String bucketName, String object, String contentType, Integer validTime, TimeUnit timeUnit) { Map < String , String > reqParams = null ; if ( contentType != null ) { reqParams = new HashMap < > ( ) ; reqParams. put ( "response-content-type" , contentType != null ? contentType : "application/pdf" ) ; } String url = null ; try { url = minioClient. getPresignedObjectUrl ( GetPresignedObjectUrlArgs . builder ( ) . method ( Method . GET) . bucket ( bucketName) . object ( object) . expiry ( validTime, timeUnit) . extraQueryParams ( reqParams) . build ( ) ) ; } catch ( Exception e) { e. printStackTrace ( ) ; } return url; } public List < Item > listObjects ( int limit, String bucketName) { List < Item > objects = new ArrayList < > ( ) ; Iterable < Result < Item > > results = minioClient. listObjects ( ListObjectsArgs . builder ( ) . bucket ( bucketName) . maxKeys ( limit) . includeVersions ( true ) . build ( ) ) ; try { for ( Result < Item > result : results) { objects. add ( result. get ( ) ) ; } } catch ( Exception e) { e. printStackTrace ( ) ; } return objects; } public static void netToMinio ( String httpUrl, String bucketName) { int i = httpUrl. lastIndexOf ( "." ) ; String substring = httpUrl. substring ( i) ; URL url; try { url = new URL ( httpUrl) ; URLConnection urlConnection = url. openConnection ( ) ; urlConnection. setRequestProperty ( "User-Agent" , "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" ) ; DataInputStream dataInputStream = new DataInputStream ( url. openStream ( ) ) ; File tempFile = File . createTempFile ( UUID. randomUUID ( ) . toString ( ) . replace ( "-" , "" ) , substring) ; FileOutputStream fileOutputStream = new FileOutputStream ( tempFile) ; ByteArrayOutputStream output = new ByteArrayOutputStream ( ) ; byte [ ] buffer = new byte [ 1024 ] ; int length; while ( ( length = dataInputStream. read ( buffer) ) > 0 ) { output. write ( buffer, 0 , length) ; } fileOutputStream. write ( output. toByteArray ( ) ) ; putObject ( bucketName, tempFile. getAbsolutePath ( ) , tempFile. getName ( ) ) ; dataInputStream. close ( ) ; fileOutputStream. close ( ) ; } catch ( Exception e) { e. printStackTrace ( ) ; } } public byte [ ] fileToBytes ( String path) { FileInputStream fis = null ; ByteArrayOutputStream bos = null ; try { bos = new ByteArrayOutputStream ( ) ; fis = new FileInputStream ( path) ; int temp; byte [ ] bt = new byte [ 1024 * 10 ] ; while ( ( temp = fis. read ( bt) ) != - 1 ) { bos. write ( bt, 0 , temp) ; } bos. flush ( ) ; } catch ( IOException e) { e. printStackTrace ( ) ; } finally { try { if ( Objects . nonNull ( fis) ) { fis. close ( ) ; } } catch ( IOException e) { e. printStackTrace ( ) ; } } return bos. toByteArray ( ) ; } public static String getUtf8ByURLDecoder ( String str) throws UnsupportedEncodingException { String url = str. replaceAll ( "%(?![0-9a-fA-F]{2})" , "%25" ) ; return URLDecoder . decode ( url, "UTF-8" ) ; } public static void downloadMinioFileToZip ( String bucketName, HttpServletResponse response) { downloadMinioFileToZip ( bucketName, "" , response) ; } public static void downloadMinioFileToZip ( String bucketName, String folderPath, HttpServletResponse response) { try { if ( folderPath == null || folderPath. isEmpty ( ) ) { folderPath = "" ; } response. setContentType ( "application/zip" ) ; response. setHeader ( "Content-Disposition" , "attachment;filename=" + bucketName + ".zip" ) ; try ( ZipOutputStream zipOut = new ZipOutputStream ( response. getOutputStream ( ) ) ) { Iterable < Result < Item > > results = minioClient. listObjects ( ListObjectsArgs . builder ( ) . bucket ( bucketName) . prefix ( folderPath) . recursive ( true ) . build ( ) ) ; for ( Result < Item > result : results) { Item item = result. get ( ) ; String objectName = item. objectName ( ) ; log. info ( "找到对象: {}" , objectName) ; if ( objectName. endsWith ( "/" ) ) { continue ; } ZipEntry zipEntry = new ZipEntry ( objectName) ; zipOut. putNextEntry ( zipEntry) ; try ( InputStream stream = minioClient. getObject ( GetObjectArgs . builder ( ) . bucket ( bucketName) . object ( objectName) . build ( ) ) ) { byte [ ] buf = new byte [ 8192 ] ; int bytesRead; while ( ( bytesRead = stream. read ( buf) ) != - 1 ) { zipOut. write ( buf, 0 , bytesRead) ; } zipOut. closeEntry ( ) ; log. info ( "文件压缩成功: {}" , objectName) ; } catch ( Exception e) { log. error ( "下载并压缩文件时发生错误: {}" , e. getMessage ( ) , e) ; } } log. info ( "所有文件已成功压缩并通过响应输出。" ) ; } catch ( IOException e) { log. error ( "创建压缩包时发生错误: {}" , e. getMessage ( ) , e) ; } } catch ( MinioException | InvalidKeyException | NoSuchAlgorithmException e) { log. error ( "发生错误: {}" , e. getMessage ( ) , e) ; } } }
配置类:
import com. saas. iot. utils. MinioUtils ;
import io. minio. MinioClient ;
import org. springframework. boot. context. properties. EnableConfigurationProperties ;
import org. springframework. context. annotation. Bean ;
import org. springframework. context. annotation. Configuration ; import javax. annotation. Resource ; @Configuration
@EnableConfigurationProperties ( MinioProperties . class )
public class MinioConfig { @Resource private MinioProperties minioProperties; @Bean public MinioClient minioClient ( ) { return MinioClient . builder ( ) . endpoint ( minioProperties. getUrl ( ) ) . credentials ( minioProperties. getAccessKey ( ) , minioProperties. getSecretKey ( ) ) . build ( ) ; } @Bean public MinioUtils creatMinioClient ( ) { return new MinioUtils ( minioProperties. getUrl ( ) , minioProperties. getAccessKey ( ) , minioProperties. getSecretKey ( ) ) ; } }
测试接口实现类:
请求接口:
@PostMapping ( "upload" ) @ApiOperation ( "文件上传" ) public R upload ( MultipartFile file) { return R . ok ( sysFileService. uploadFile ( file) ) ; }
服务层接口方法:
String uploadFile ( MultipartFile file) throws Exception ;
实现方法:
@Override public String uploadFile ( MultipartFile file) throws Exception { if ( file. isEmpty ( ) || file. getSize ( ) <= 0 || StrUtil . isBlank ( file. getOriginalFilename ( ) ) ) { throw new RuntimeException ( "上传文件不能为空" ) ; } String originalFilename = file. getOriginalFilename ( ) ; String [ ] defaultAllowedExtension = MimeTypeUtils . DEFAULT_ALLOWED_EXTENSION; Set < String > typeSet = new HashSet < > ( Arrays . asList ( defaultAllowedExtension) ) ; originalFilename = originalFilename. substring ( originalFilename. lastIndexOf ( "." ) + 1 ) ; if ( ! typeSet. contains ( originalFilename) ) { throw new RuntimeException ( "文件格式不支持" ) ; } ObjectWriteResponse response = MinioUtils . putObject ( minioConfig. getBucket ( ) , file, getFileName ( originalFilename) , file. getContentType ( ) ) ; return minioConfig. getAccessUrl ( ) + minioConfig. getBucket ( ) + "/" + response. object ( ) ; } private String getFileName ( String suffix) { return "data/local/" + suffix + "/" + IdUtil . getSnowflake ( ) + "." + suffix; }
定义系统允许文件类型:
public static final String [ ] DEFAULT_ALLOWED_EXTENSION = { "bmp" , "gif" , "jpg" , "jpeg" , "png" , "doc" , "docx" , "xls" , "xlsx" , "ppt" , "pptx" , "html" , "htm" , "txt" , "rar" , "zip" , "gz" , "bz2" , "bin" , "apk" , "ipa" , "mp4" , "avi" , "rmvb" , "tif" , "pdf" } ;