yml
minio: endpoint: http://10.233.32.30:9000 accessKey: FEYLLeZLcKbCllVTkfsg secretKey: nEN4JCJpDJ1tssbUui5gavjwZl19fVyyrIKdsCVt bucketName: test businessName: 1210Head contentType: file
package com.sf.gis.common.config; import io.minio.MinioClient; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Configuration; import org.springframework.beans.factory.annotation.Value; @Data @Slf4j @Configuration public class MinioClientSingleton { /** * Minio服务端地址 */ private static String endpoint; /** * Minio服务端账号 */ private static String accessKey; /** * Minio服务端密码 */ private static String secretKey; @Value("${minio.endpoint}") public void setEndpoint(String endpoint) { MinioClientSingleton.endpoint = endpoint; } @Value("${minio.accessKey}") public void setAccessKey(String accessKey) { MinioClientSingleton.accessKey = accessKey; } @Value("${minio.secretKey}") public void setSecretKey(String secretKey) { MinioClientSingleton.secretKey = secretKey; } /** * Minio客户端 */ private static volatile MinioClient minioClient; public MinioClientSingleton() { } /** * 获取minio客户端实例 * * @return {@link MinioClient} */ public static MinioClient getMinioClient() { log.info("AK:"+accessKey+" SA:"+secretKey+" endpoint :"+endpoint); if (minioClient == null) { synchronized (MinioClientSingleton.class) { if (minioClient == null) { minioClient = MinioClient.builder() .endpoint(endpoint) .credentials(accessKey, secretKey) .build(); log.info("MinioClientSingleton#getMinioClient,endpoint={},accessKey={},secretKey={}", endpoint, accessKey, secretKey); } } } return minioClient; } }
package com.sf.gis.common.config; import com.obs.services.ObsClient; import com.obs.services.exception.ObsException; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import java.text.SimpleDateFormat; import java.util.Date; /** * @ClassName: HweiOBSConfig * @Description: 华为云OBS配置类 * @Author: wuhuiju * @Date: 2021-12-21 15:56 * @Version: 1.0 */ @Data @Slf4j @Configuration public class MinIoConfig { @Value("${minio.bucketName}") private String bucketName; @Value("${minio.contentType}") private String contentType; }
package com.sf.gis.common.controller; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.StrUtil; import com.sf.gis.common.result.JsonResponse; import com.sf.gis.common.service.MinIoService; import com.sf.gis.common.utils.FileUtils; import com.sf.gis.common.utils.LogExceptionStackUtil; import io.minio.errors.*; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.Base64Utils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.List; @Slf4j @RestController @RequestMapping("/file") public class MinIoController { @Resource private MinIoService minIoService; @PostMapping("/uploadfile") @Operation(summary="上传文件") public JsonResponse uploadFile1(@RequestPart("file") MultipartFile file) throws ServerException, InvalidBucketNameException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, ServerException, InvalidBucketNameException, InsufficientDataException, ErrorResponseException, InvalidResponseException { return minIoService.fileUpload(file); } @GetMapping("/preview") @Operation(summary = "预览") public JsonResponse preview(@RequestParam("fileName") String fileName) { try { if (StringUtils.isBlank(fileName)) { JsonResponse.error("文件名为空"); } InputStream inputStream = minIoService.fileDownload(fileName); return JsonResponse.ok(Base64Utils.encodeToString(FileUtils.readInputStream(inputStream))); } catch (Exception e) { log.error("文件下载失败{}", LogExceptionStackUtil.logExceptionStack(e)); } return JsonResponse.ok("success"); } @GetMapping("/download") @Operation(summary = "文件下载") public void download(@RequestParam("fileName") String fileName, HttpServletRequest request, HttpServletResponse response) { ServletOutputStream ops = null; try (InputStream inputStream = minIoService.fileDownload(fileName); BufferedOutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) { // 为防止 文件名出现乱码 final String userAgent = request.getHeader("USER-AGENT"); // IE浏览器 if (StrUtil.contains(userAgent, "MSIE")) { fileName = URLEncoder.encode(fileName, "UTF-8"); } else { // google,火狐浏览器 if (StrUtil.contains(userAgent, "Mozilla")) { fileName = new String(fileName.getBytes(), "ISO8859-1"); } else { // 其他浏览器 fileName = URLEncoder.encode(fileName, "UTF-8"); } } response.setContentType("application/x-download"); // 设置让浏览器弹出下载提示框,而不是直接在浏览器中打开 response.addHeader("Content-Disposition", "attachment;filename=" + fileName); IoUtil.copy(inputStream, outputStream); ops = response.getOutputStream(); } catch (Exception e) { log.error("文件下载失败{}", LogExceptionStackUtil.logExceptionStack(e)); }finally { try { ops.close(); } catch (IOException e) { e.printStackTrace(); } } } @GetMapping("/ssfPreview") @Operation(summary = "预览") public JsonResponse ssfPreview(@RequestParam("urlPath") String urlPath) { HttpURLConnection connection = null; try { if (StringUtils.isBlank(urlPath)) { JsonResponse.error("路径为空"); } urlPath = urlPath.replace("10.246.6.154:9000","192.168.216.146:17000"); // 创建URL对象 URL url = new URL(urlPath); connection = (HttpURLConnection) url.openConnection(); // 设置请求方法为GET connection.setRequestMethod("GET"); // 获取响应码 int responseCode = connection.getResponseCode(); if (responseCode != HttpURLConnection.HTTP_OK) { JsonResponse.error("Failed to retrieve image: HTTP " + responseCode); } InputStream inputStream = connection.getInputStream(); return JsonResponse.ok(Base64Utils.encodeToString(FileUtils.readInputStream(inputStream))); } catch (Exception e) { log.error("文件下载失败{}", LogExceptionStackUtil.logExceptionStack(e)); } finally { // 关闭连接 if(connection!=null) connection.disconnect(); } return JsonResponse.ok("success"); } }
package com.sf.gis.common.service; import com.sf.gis.common.result.JsonResponse; import io.minio.errors.*; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.io.InputStream; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.List; public interface MinIoService { /** * @Description 删除文件 * @author wuhuiju * @date 2021/12/21 17:02 * @param: objectKey 文件名 * @return: boolean 执行结果 */ boolean delete(String objectKey); /** * @Description 批量删除文件 * @author wuhuiju * @date 2021/12/21 17:02 * @param: objectKeys 文件名集合 * @return: boolean 执行结果 */ boolean delete(List<String> objectKeys); JsonResponse fileUpload(MultipartFile uploadFil) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException, InvalidBucketNameException; /** * @Description 文件下载 * @author wuhuiju * @date 2021/12/21 17:04 * @param: objectKey * @return: java.io.InputStream */ InputStream fileDownload(String objectKey)throws Exception; /** * 图片压缩 * @param uploadFile * @param * @return */ String picZip(MultipartFile uploadFile); }
package com.sf.gis.common.service.impl; import com.obs.services.ObsClient; import com.obs.services.exception.ObsException; import com.obs.services.model.DeleteObjectsRequest; import com.sf.gis.common.config.HweiOBSConfig; import com.sf.gis.common.config.MinIoConfig; import com.sf.gis.common.config.MinioClientSingleton; import com.sf.gis.common.constants.CommonConstant; import com.sf.gis.common.enums.fileTypeEnum; import com.sf.gis.common.exceprtion.BusinessException; import com.sf.gis.common.result.JsonResponse; import com.sf.gis.common.service.MinIoService; import com.sf.gis.common.utils.LogExceptionStackUtil; import com.sf.gis.common.utils.PictureZipUtil; import com.sf.gis.common.utils.UUIDUtils; import io.minio.*; import io.minio.errors.*; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; import org.springframework.web.multipart.MultipartFile; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @Slf4j @Service public class MinIoServiceImpl implements MinIoService { @Autowired private MinioClientSingleton minioClientSingleton; @Autowired private HweiOBSConfig hweiOBSConfig; @Autowired private PictureZipUtil pictureZipUtil; @Value("${picture.zip.filesize}") private Integer fileSize; @Autowired private MinIoConfig minIoConfig; @Override public boolean delete(String objectKey) { ObsClient obsClient = null; try { // 创建ObsClient实例 obsClient = hweiOBSConfig.getInstance(); // obs删除 obsClient.deleteObject(hweiOBSConfig.getBucketName(),objectKey); } catch (ObsException e) { log.error("obs删除保存失败", e); } finally { hweiOBSConfig.destroy(obsClient); } return true; } @Override public boolean delete(List<String> objectKeys) { ObsClient obsClient = null; try { obsClient = hweiOBSConfig.getInstance(); DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(hweiOBSConfig.getBucketName()); objectKeys.forEach(x -> deleteObjectsRequest.addKeyAndVersion(x)); // 批量删除请求 obsClient.deleteObjects(deleteObjectsRequest); return true; } catch (ObsException e) { log.error("obs删除保存失败", e); } finally { hweiOBSConfig.destroy(obsClient); } return false; } /* @Override public JsonResponse fileUpload(MultipartFile file) { Map<String, String> objectObjectHashMap = new HashMap<>(); objectObjectHashMap.put("fileCompressUrl",""); boolean flag = false; String fileTypes=""; *//* cherkFileType(fileType);*//* String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")).replace(".", ""); if (ObjectUtils.isEmpty(file) || file.getSize() <= 0) { throw new BusinessException("上传的文件为空"); } *//*if (fileType==1){ fileTypes = CommonConstant.FILETYPETOW; String[] split = fileTypes.split(","); for (int i = 0; i < split.length; i++) { String filetypes = split[i]; if (StringUtils.equals(filetypes, fileSuffix)) { flag = true; } } if (!flag) { throw new BusinessException("文件类型有误!"); } if (file.getSize()>2097152200) {//200M throw new BusinessException("单次上传不能超过200M"); //1M=10485761字节 } } if (fileType==2){ fileTypes = CommonConstant.FILETYPETOW; String[] split = fileTypes.split(","); for (int i = 0; i < split.length; i++) { String filetypes = split[i]; if (StringUtils.equals(filetypes, fileSuffix)) { flag = true; } } if (!flag) { throw new BusinessException("文件类型有误!"); } if (file.getSize()>209715220) {//20M throw new BusinessException("单次上传不能超过20M"); } } if (fileType==3){ fileTypes = CommonConstant.PICTYPE; String[] split = fileTypes.split(","); for (int i = 0; i < split.length; i++) { String filetypes = split[i]; if (StringUtils.equals(filetypes, fileSuffix)) { flag = true; } } if (!flag) { throw new BusinessException("文件类型有误!"); } } if (fileType==4){ fileTypes = CommonConstant.PNGPDF; String[] split = fileTypes.split(","); for (int i = 0; i < split.length; i++) { String filetypes = split[i]; if (StringUtils.equals(filetypes, fileSuffix)) { flag = true; } } if (!flag) { throw new BusinessException("文件类型有误!"); } if (file.getSize()>209715220) {//20M throw new BusinessException("单次上传不能超过20M"); } }*//* boolean flags = false; String fileTypess = CommonConstant.PICTYPE; String[] split = fileTypess.split(","); for (int i = 0; i < split.length; i++) { String filetypes = split[i]; if (StringUtils.equals(filetypes, fileSuffix)) { flags = true; } } if (flags){ String fileCompressUrl = picZip(file); objectObjectHashMap.put("fileCompressUrl",fileCompressUrl); } ObsClient obsClient = null; String objectUrl = ""; try { String bucketName = hweiOBSConfig.getBucketName(); obsClient = hweiOBSConfig.getInstance(); // 上传文件到OBS String objectKey = UUIDUtils.getRandomUUID() + file.getOriginalFilename();//加一个逗号分割方便前段截取文件名 PutObjectRequest request = new PutObjectRequest(bucketName, objectKey, file.getInputStream()); PutObjectResult putObjectResult = obsClient.putObject(request); objectUrl = objectKey; log.info("已上传对象的URL:{}", putObjectResult.getObjectUrl()); log.info("生成的文件访问名:{}", objectKey); objectObjectHashMap.put("fileName", file.getOriginalFilename()); objectObjectHashMap.put("fileUrl", objectUrl); } catch (ObsException e) { log.error("obs上传失败:{}", LogExceptionStackUtil.logExceptionStack(e)); return JsonResponse.error("obs上传失败"); } catch (Exception e) { log.error("上传失败{}", LogExceptionStackUtil.logExceptionStack(e)); return JsonResponse.error("上传失败"); } finally { hweiOBSConfig.destroy(obsClient); } return JsonResponse.ok(objectObjectHashMap); }*/ private void cherkFileType(Integer fileType) { if (StringUtils.isBlank(fileType==null?"": fileTypeEnum.getValueByCode(fileType))){ throw new BusinessException("fileType参数有误!"); } } @Override public InputStream fileDownload(String fileName) throws Exception{ if (StringUtils.isBlank(fileName)){ throw new BusinessException("文件名不能为空!"); } /* if (bucketExists(minIoConfig.getBucketName())) {*/ ObjectStat objectStat = MinioClientSingleton.getMinioClient() .statObject(StatObjectArgs.builder().bucket(minIoConfig.getBucketName()).object(fileName).build()); if (objectStat!=null) { // 获取objectName的输入流。 return MinioClientSingleton.getMinioClient() .getObject(GetObjectArgs.builder().bucket(minIoConfig.getBucketName()).object(fileName).build()); } /* }*/ return null; } public static String getBucketObject(String bucketName, String objectName) throws ServerException, InvalidBucketNameException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException { if (bucketExists(bucketName)) { return MinioClientSingleton.getMinioClient().getObjectUrl(bucketName, objectName); } return null; } /** * 判断存储桶是否存在 * @param bucketName * @return */ public static boolean bucketExists(String bucketName) { boolean found = false; try { found = MinioClientSingleton.getMinioClient(). bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); } catch (Exception e) { log.error("MinioKit#bucketExists,查询存储桶异常,bucketName={}", bucketName, e); throw new RuntimeException("查询存储桶异常"); } return found; } @Override public String picZip(MultipartFile uploadFile) { String fileCompressUrl=""; Map<String, String> objectObjectHashMap = new HashMap<>(); InputStream inputStream=null; ObsClient obsClient = null; String objectUrl = ""; try { if(!checkPicZip(uploadFile)){ log.info("该图片大于{}Kb,需要压缩",fileSize); byte[] bytes= pictureZipUtil.picZip(uploadFile,fileSize); inputStream= new ByteArrayInputStream(bytes); }else{ log.info("该图片小于等于{}Kb,不需要压缩",fileSize); inputStream=uploadFile.getInputStream(); } String originalFilename= getFileName(uploadFile.getOriginalFilename()); /* makeBucket(minIoConfig.getBucketName());*/ fileCompressUrl=originalFilename; log.info("bucketName:"+minIoConfig.getBucketName()); ObjectWriteResponse objectWriteResponse = MinioClientSingleton.getMinioClient().putObject( PutObjectArgs.builder().bucket(minIoConfig.getBucketName()).object(originalFilename).contentType(minIoConfig.getContentType()) .stream( inputStream, inputStream.available(), -1) .build()); String url = MinioClientSingleton.getMinioClient().getObjectUrl(minIoConfig.getBucketName(), originalFilename); //文件访问路径 log.info("已上传对象的URL:{}", url); log.info("生成的文件访问名:{}", originalFilename); } catch (MinioException e) { log.error("picZipobs上传失败:{}", LogExceptionStackUtil.logExceptionStack(e)); throw new BusinessException("Minio上传失败"); } catch (Exception e) { log.error("picZip上传失败{}", LogExceptionStackUtil.logExceptionStack(e)); throw new BusinessException("上传失败"+e.getMessage()); } finally { if(inputStream!=null){ try { inputStream.close(); } catch (IOException e) { log.error("关闭流异常",e); } } } return fileCompressUrl; } private boolean checkPicZip(MultipartFile uploadFile){ if(uploadFile==null){ throw new BusinessException("上传文件对象为空!"); } if(uploadFile.getSize()==0L){ throw new BusinessException("文件大小为0!"); } if(!PictureZipUtil.isImage2(uploadFile.getOriginalFilename())){ throw new BusinessException("该文件格式不是图片格式!"); } boolean flag=PictureZipUtil.checkFileSizeIsLimit(uploadFile.getSize(),fileSize,"K"); return flag; } @Override public JsonResponse fileUpload(MultipartFile file) { log.info("minIoServiceImpl.fileUpload上传文件开始"); Map<String, String> objectObjectHashMap = new HashMap<>(); objectObjectHashMap.put("fileCompressUrl",""); String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")).replace(".", ""); if (ObjectUtils.isEmpty(file) || file.getSize() <= 0) { throw new BusinessException("上传的文件为空"); } boolean flag = false; String fileTypes = CommonConstant.FILETYPETOWSS; String[] splits = fileTypes.split(","); for (int i = 0; i < splits.length; i++) { String filetypes = splits[i]; if (StringUtils.equals(filetypes, fileSuffix)) { flag = true; } } if (!flag) { throw new BusinessException("文件类型有误!"); } boolean flags = false; String fileTypess = CommonConstant.PICTYPE; String[] split = fileTypess.split(","); for (int i = 0; i < split.length; i++) { String filetypes = split[i]; if (StringUtils.equals(filetypes, fileSuffix)) { flags = true; } } /*if (flags){ log.info("minIoServiceImpl.fileUpload上传文件压缩开始"); String fileCompressUrl = picZip(file); objectObjectHashMap.put("fileCompressUrl",fileCompressUrl); log.info("minIoServiceImpl.fileUpload上传文件压缩结束"); }*/ InputStream inputStream=null; String originalFilename= getFileName(file.getOriginalFilename()); try { log.info("minIoServiceImpl.fileUpload上传文件调用minio开始"); //makeBucket(minIoConfig.getBucketName());//判断桶是否存在 不存在创建 inputStream = file.getInputStream(); ObjectWriteResponse objectWriteResponse = MinioClientSingleton.getMinioClient().putObject( PutObjectArgs.builder().bucket(minIoConfig.getBucketName()).object(originalFilename).contentType(minIoConfig.getContentType()) .stream( inputStream, inputStream.available(), -1) .build()); String url = MinioClientSingleton.getMinioClient().getObjectUrl(minIoConfig.getBucketName(), originalFilename); //文件访问路径 log.info("已上传对象的URL:{}", url); log.info("生成的文件访问名:{}", originalFilename); objectObjectHashMap.put("fileName", file.getOriginalFilename()); objectObjectHashMap.put("fileUrl", originalFilename); objectObjectHashMap.put("contentType", file.getContentType()); objectObjectHashMap.put("fileCompressUrl",originalFilename); log.info("minIoServiceImpl.fileUpload上传文件调用minio结束"); } catch (MinioException e) { log.error("minio上传失败:{}", LogExceptionStackUtil.logExceptionStack(e)); return JsonResponse.error("minio上传失败"); } catch (Exception e) { log.error("上传失败{}", LogExceptionStackUtil.logExceptionStack(e)); return JsonResponse.error("上传失败"); }finally { try { inputStream.close(); } catch (IOException e) { log.error("关闭流异常",e); } } log.info("minIoServiceImpl.fileUpload上传文件结束"); return JsonResponse.ok(objectObjectHashMap); } /** * 通过MultipartFile,上传文件 * * @param bucketName 存储桶 * @param file 文件 * @param objectName 对象名 */ public static void putObject(String bucketName, MultipartFile file, String objectName, String contentType) throws Exception { InputStream inputStream = file.getInputStream(); ObjectWriteResponse objectWriteResponse = MinioClientSingleton.getMinioClient().putObject( PutObjectArgs.builder().bucket(bucketName).object(objectName).contentType(contentType) .stream( inputStream, inputStream.available(), -1) .build()); } private String getFileName(String filename){ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); // 设置存储对象名称 String dir = sdf.format(new Date()); /* int idx = filename.lastIndexOf("."); if (idx >= 0) { String ext = filename.substring(idx+1); String name = System.currentTimeMillis() + filename.substring(0, idx); filename = XString.md5(name) + "." + ext; }*/ return dir + "/"+UUIDUtils.getRandomUUID() +filename; } /** * 创建存储桶 * @param bucketName * @return */ /* public static boolean makeBucket(String bucketName) { try { if (!bucketExists(bucketName)) { MinioClientSingleton.getMinioClient(). makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); log.info("MinioKit#makeBucket,存储桶创建成功,bucketName={}", bucketName); return true; } } catch (Exception e) { log.error("MinioKit#bucketExists,查询存储桶异常,bucketName={}", bucketName, e); e.printStackTrace(); } return false; }*/ }