diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java index d966ad85436b99b652a8fdbae621a5a4f442b9ec..61bef9516f6652e70dd8b2d10a6f44f9c870410f 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java @@ -1,27 +1,14 @@ package com.ruoyi.web.controller.common; -import java.util.ArrayList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -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 com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.common.utils.file.FileUploadUtils; +import com.ruoyi.common.utils.file.FileOperateUtils; import com.ruoyi.common.utils.file.FileUtils; +import com.ruoyi.common.utils.file.MimeTypeUtils; import com.ruoyi.framework.config.ServerConfig; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; @@ -29,10 +16,19 @@ import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.ArrayList; +import java.util.List; /** * 通用请求处理 - * + * * @author ruoyi */ @Tag(name = "通用请求处理") @@ -48,7 +44,7 @@ public class CommonController { /** * 通用下载请求 - * + * * @param fileName 文件名称 * @param delete 是否删除 */ @@ -58,6 +54,7 @@ public class CommonController { @Parameter(name = "delete", description = "是否删除") }) @GetMapping("/download") + @Anonymous public void fileDownload( @RequestParam("fileName") String fileName, @RequestParam("delete") Boolean delete, @@ -72,9 +69,10 @@ public class CommonController { response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); FileUtils.setAttachmentResponseHeader(response, realFileName); - FileUtils.writeBytes(filePath, response.getOutputStream()); + // FileUtils.writeBytes(filePath, response.getOutputStream()); + FileOperateUtils.downLoad(filePath, response.getOutputStream()); if (delete) { - FileUtils.deleteFile(filePath); + FileOperateUtils.deleteFile(fileName); } } catch (Exception e) { log.error("下载文件失败", e); @@ -86,12 +84,13 @@ public class CommonController { */ @Operation(summary = "通用上传请求(单个)") @PostMapping("/upload") + @Anonymous public AjaxResult uploadFile(@RequestBody MultipartFile file) throws Exception { try { // 上传文件路径 - String filePath = RuoYiConfig.getUploadPath(); + // String filePath = RuoYiConfig.getUploadPath(); // 上传并返回新文件名称 - String fileName = FileUploadUtils.upload(filePath, file); + String fileName = FileOperateUtils.upload(file); String url = serverConfig.getUrl() + fileName; AjaxResult ajax = AjaxResult.success(); ajax.put("url", url); @@ -109,6 +108,7 @@ public class CommonController { */ @Operation(summary = "通用上传请求(多个)") @PostMapping("/uploads") + @Anonymous public AjaxResult uploadFiles(@RequestBody List files) throws Exception { try { @@ -120,7 +120,7 @@ public class CommonController { List originalFilenames = new ArrayList(); for (MultipartFile file : files) { // 上传并返回新文件名称 - String fileName = FileUploadUtils.upload(filePath, file); + String fileName = FileOperateUtils.upload(filePath, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); String url = serverConfig.getUrl() + fileName; urls.add(url); fileNames.add(fileName); @@ -143,6 +143,7 @@ public class CommonController { */ @Operation(summary = "本地资源通用下载") @GetMapping("/download/resource") + @Anonymous public void resourceDownload(@Parameter(name = "resource", description = "资源名称") String resource, HttpServletRequest request, HttpServletResponse response) throws Exception { @@ -157,8 +158,9 @@ public class CommonController { // 下载名称 String downloadName = StringUtils.substringAfterLast(downloadPath, "/"); response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); - FileUtils.setAttachmentResponseHeader(response, downloadName); - FileUtils.writeBytes(downloadPath, response.getOutputStream()); + FileUtils.setAttachmentResponseHeader(response, resource); + FileOperateUtils.downLoad(resource, response.getOutputStream()); + // FileUtils.writeBytes(downloadPath, response.getOutputStream()); } catch (Exception e) { log.error("下载文件失败", e); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java index 3e7e6d0569632d90a3e0c68a77a427282f8e41ff..623009e8d6b5678734298d63478d1268d16d093b 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java @@ -1,15 +1,5 @@ package com.ruoyi.web.controller.system; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -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 com.ruoyi.common.annotation.Log; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.core.controller.BaseController; @@ -19,24 +9,28 @@ import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.common.utils.file.FileUploadUtils; +import com.ruoyi.common.utils.file.FileOperateUtils; +import com.ruoyi.common.utils.file.FileUtils; import com.ruoyi.common.utils.file.MimeTypeUtils; import com.ruoyi.framework.web.service.TokenService; import com.ruoyi.system.service.ISysUserService; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; /** * 个人信息 业务处理 - * + * * @author ruoyi */ -@Tag(name = "个人信息" , description = "业务处理") +@Tag(name = "个人信息", description = "业务处理") @RestController @RequestMapping("/system/user/profile") -public class SysProfileController extends BaseController -{ +public class SysProfileController extends BaseController { @Autowired private ISysUserService userService; @@ -48,8 +42,7 @@ public class SysProfileController extends BaseController */ @Operation(summary = "个人信息") @GetMapping - public AjaxResult profile() - { + public AjaxResult profile() { LoginUser loginUser = getLoginUser(); SysUser user = loginUser.getUser(); AjaxResult ajax = AjaxResult.success(user); @@ -64,25 +57,21 @@ public class SysProfileController extends BaseController @Operation(summary = "修改用户") @Log(title = "个人信息", businessType = BusinessType.UPDATE) @PutMapping - public AjaxResult updateProfile(@RequestBody SysUser user) - { + public AjaxResult updateProfile(@RequestBody SysUser user) { LoginUser loginUser = getLoginUser(); SysUser sysUser = loginUser.getUser(); user.setUserName(sysUser.getUserName()); - if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) - { + if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); } - if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) - { + if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); } user.setUserId(sysUser.getUserId()); user.setPassword(null); user.setAvatar(null); user.setDeptId(null); - if (userService.updateUserProfile(user) > 0) - { + if (userService.updateUserProfile(user) > 0) { // 更新缓存用户信息 sysUser.setNickName(user.getNickName()); sysUser.setPhonenumber(user.getPhonenumber()); @@ -100,22 +89,18 @@ public class SysProfileController extends BaseController @Operation(summary = "重置密码") @Log(title = "个人信息", businessType = BusinessType.UPDATE) @PutMapping("/updatePwd") - public AjaxResult updatePwd(String oldPassword, String newPassword) - { + public AjaxResult updatePwd(String oldPassword, String newPassword) { LoginUser loginUser = getLoginUser(); String userName = loginUser.getUsername(); String password = loginUser.getPassword(); - if (!SecurityUtils.matchesPassword(oldPassword, password)) - { + if (!SecurityUtils.matchesPassword(oldPassword, password)) { return error("修改密码失败,旧密码错误"); } - if (SecurityUtils.matchesPassword(newPassword, password)) - { + if (SecurityUtils.matchesPassword(newPassword, password)) { return error("新密码不能与旧密码相同"); } newPassword = SecurityUtils.encryptPassword(newPassword); - if (userService.resetUserPwd(userName, newPassword) > 0) - { + if (userService.resetUserPwd(userName, newPassword) > 0) { // 更新缓存用户密码 loginUser.getUser().setPassword(newPassword); tokenService.setLoginUser(loginUser); @@ -130,14 +115,14 @@ public class SysProfileController extends BaseController @Operation(summary = "头像上传") @Log(title = "用户头像", businessType = BusinessType.UPDATE) @PostMapping("/avatar") - public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception - { - if (!file.isEmpty()) - { + public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception { + if (!file.isEmpty()) { LoginUser loginUser = getLoginUser(); - String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION); - if (userService.updateUserAvatar(loginUser.getUsername(), avatar)) - { + String extractPath = loginUser.getUsername() + File.separator + loginUser.getUserId(); + String fileName = "avatar." + FileUtils.getExtension(file); + String avatar = FileOperateUtils.upload(RuoYiConfig.getAvatarPath()+extractPath, fileName, file, + MimeTypeUtils.IMAGE_EXTENSION); + if (userService.updateUserAvatar(loginUser.getUsername(), avatar)) { AjaxResult ajax = AjaxResult.success(); ajax.put("imgUrl", avatar); // 更新缓存用户头像 diff --git a/ruoyi-admin/src/main/resources/application-middleware.yml b/ruoyi-admin/src/main/resources/application-middleware.yml index 118ed25b18e00d21a3287c0188a0a5e557fe7174..e7e68a54b1a24210cca8fc02f638106446aa4378 100644 --- a/ruoyi-admin/src/main/resources/application-middleware.yml +++ b/ruoyi-admin/src/main/resources/application-middleware.yml @@ -25,7 +25,11 @@ spring: # Minio配置 minio: - url: http://localhost:9000 - accessKey: minioadmin - secretKey: minioadmin - bucketName: ruoyi + enable: true + downLoadLimit: 1024 + client: + master: + url: http://localhost:9000 + accessKey: + secretKey: + defaultBuket: diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 085340b3c9743d63d550a2efca20a1142af91b4d..4d5c898fd71d6cb97968e88a49666ec968966765 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -12,6 +12,8 @@ ruoyi: addressEnabled: false # 验证码类型 math 数组计算 char 字符验证 captchaType: math + # 指定文件服务类型(值为disk代表使用磁盘作为文件操作服务,minio代表使用minio作为文件操作服务) + fileServer: minio # 开发环境配置 server: diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java index 29281cf1b1fe0c974594537b764393aa0c3a9b5f..24abfe2e859aec414cf53ab9e4cb5df3ed9b6e97 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java @@ -5,7 +5,7 @@ import org.springframework.stereotype.Component; /** * 读取项目相关配置 - * + * * @author ruoyi */ @Component @@ -24,12 +24,17 @@ public class RuoYiConfig /** 上传路径 */ private static String profile; + + + private static String fileServer; + /** 获取地址开关 */ private static boolean addressEnabled; /** 验证码类型 */ private static String captchaType; + public String getName() { return name; @@ -88,6 +93,14 @@ public class RuoYiConfig RuoYiConfig.captchaType = captchaType; } + public static String getFileServer() { + return fileServer; + } + + public void setFileServer(String fileServer) { + RuoYiConfig.fileServer = fileServer; + } + /** * 获取导入上传路径 */ diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/DiskFileService.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/DiskFileService.java new file mode 100644 index 0000000000000000000000000000000000000000..51c47b5b070c86e812100ec172d4eabddb93a006 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/DiskFileService.java @@ -0,0 +1,104 @@ +package com.ruoyi.common.utils.file; + +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.uuid.UUID; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.nio.file.Paths; +import java.util.Objects; + +import static com.ruoyi.common.utils.file.FileUtils.getAbsoluteFile; +import static com.ruoyi.common.utils.file.FileUtils.getPathFileName; + +/** + * 磁盘文件操作实现类 + */ +@Component("file:strategy:disk") +public class DiskFileService implements FileService { + + private static String defaultBaseDir = RuoYiConfig.getProfile(); + + public static void setDefaultBaseDir(String defaultBaseDir) { + DiskFileService.defaultBaseDir = defaultBaseDir; + } + + public static String getDefaultBaseDir() { + return defaultBaseDir; + } + + @Override + public String upload(String filePath, MultipartFile file) throws Exception { + int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length(); + if (fileNamelength > FileUtils.DEFAULT_FILE_NAME_LENGTH) { + throw new FileNameLengthLimitExceededException(FileUtils.DEFAULT_FILE_NAME_LENGTH); + } + + // String fileName = extractFilename(file); + + String absPath = getAbsoluteFile(filePath).getAbsolutePath(); + file.transferTo(Paths.get(absPath)); + return getPathFileName(filePath); + } + + @Override + public String upload(MultipartFile file, String name) throws Exception { + try { + return upload(getDefaultBaseDir(), file); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } + + @Override + public String upload(MultipartFile file) throws Exception { + try { + String filePath = getDefaultBaseDir() + File.separator + DateUtils.dateTime() + File.separator + + DateUtils.dateTimeNow() + UUID.fastUUID().toString().substring(0, 6) + + "." + FileUtils.getExtension(file); + return upload(filePath, file); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } + + @Override + public String upload(String baseDir, String fileName, MultipartFile file) throws Exception { + String filePath = RuoYiConfig.getProfile() + File.separator + baseDir + File.separator + fileName; + return upload(filePath, file); + } + + @Override + public InputStream downLoad(String filePath) throws Exception { + // 本地资源路径 + String localPath = RuoYiConfig.getProfile(); + // 数据库资源地址 + String downloadPath = localPath + StringUtils.substringAfter(filePath, Constants.RESOURCE_PREFIX); + // 下载名称 + + File file = new File(downloadPath); + if (!file.exists()) { + throw new FileNotFoundException("未找到文件"); + } + return new FileInputStream(file); + } + + @Override + public boolean deleteFile(String filePath) throws Exception { + String relivatePath = StringUtils.substringAfter(filePath, Constants.RESOURCE_PREFIX); + String fileAbs = RuoYiConfig.getProfile() + relivatePath; + boolean flag = false; + File file = new File(fileAbs); + // 路径为文件且不为空则进行删除 + if (file.isFile() && file.exists()) { + flag = file.delete(); + } + return flag; + } + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileOperateUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileOperateUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..ffa06a1450854107a23c17a393a890a00179c4b9 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileOperateUtils.java @@ -0,0 +1,103 @@ +package com.ruoyi.common.utils.file; + +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.utils.spring.SpringUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * 文件上传工具类 + * + * @author ruoyi + */ +public class FileOperateUtils { + + private static FileService fileService = SpringUtils.getBean("file:strategy:" + RuoYiConfig.getFileServer()); + /** + * 默认大小 50M + */ + public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024; + + /** + * 默认上传的地址 + */ + + /** + * 以默认配置进行文件上传 + * + * @param file 上传的文件 + * @return 文件路径 + * @throws Exception + */ + public static final String upload(MultipartFile file) throws IOException { + try { + FileUtils.assertAllowed(file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); + return fileService.upload(file); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } + + /** + * 根据文件路径上传 + * + * @param filePath 上传文件的路径 + * @param file 上传的文件 + * @param allowedExtension 允许的扩展名 + * @return 文件名称 + * @throws IOException + */ + public static final String upload(String filePath, MultipartFile file, String[] allowedExtension) throws Exception { + FileUtils.assertAllowed(file, allowedExtension); + return fileService.upload(filePath, file); + } + + /** + * 根据文件路径上传 + * + * @param baseDir 相对应用的基目录 + * @param file 上传的文件 + * @param fileName 上传文件名 + * @param allowedExtension 允许的扩展名 + * @return 文件名称 + * @throws IOException + */ + public static final String upload(String baseDir, String fileName, MultipartFile file, + String[] allowedExtension) + throws IOException { + try { + String filePath = baseDir + File.separator + fileName; + return upload(filePath, file, allowedExtension); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } + + /** + * 根据文件路径下载 + * + * @param fileUrl 下载文件路径 + * @param outputStream 需要输出到的输出流 + * @return 文件名称 + * @throws IOException + */ + public static final void downLoad(String fileUrl, OutputStream outputStream) throws Exception { + InputStream inputStream = fileService.downLoad(fileUrl); + FileUtils.writeBytes(inputStream, outputStream); + } + + /** + * 根据文件路径删除 + * + * @param fileUrl 下载文件路径 + * @return 是否成功 + * @throws IOException + */ + public static final boolean deleteFile(String fileUrl) throws Exception { + return fileService.deleteFile(fileUrl); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileService.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileService.java new file mode 100644 index 0000000000000000000000000000000000000000..e452b1d2c982a8c2c0687174ca3e54df66e46ccf --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileService.java @@ -0,0 +1,77 @@ +package com.ruoyi.common.utils.file; + +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; + +//默认上传下载 +/** + * 文件操作接口 + */ +public interface FileService { + + /** + * 文件上传 + * + * @param filePath 上传的文件路径 + * @param file 文件对象 + * @return 返回上传成功的文路径 + * @throws IOException 比如读写文件出错时 + * + */ + public String upload(String filePath, MultipartFile file) throws Exception; + + /** + * 文件上传 + * + * @param filePath 上传的文件路径 + * @param file 文件对象 + * @return 返回上传成功的文路径 + * @throws IOException 比如读写文件出错时 + * + */ + public String upload(MultipartFile file, String name) throws Exception; + + /** + * 文件上传 + * + * @param file 文件对象 + * @return 返回上传成功的文路径 + * @throws IOException 比如读写文件出错时 + * + */ + public String upload(MultipartFile file) throws Exception; + + /** + * 文件上传 + * + * @param baseDir 上传的文件基路径 + * @param fileName 文件名称 + * @param file 文件对象 + * @return 返回上传成功的文路径 + * @throws IOException 比如读写文件出错时 + * + */ + public String upload(String baseDir, String fileName, MultipartFile file) throws Exception; + + /** + * 文件下载 + * + * @param filePath 下载的文件路径 + * @return 返回上传成功的文路径 + * @throws IOException 比如读写文件出错时 + * + */ + public InputStream downLoad(String filePath) throws Exception; + + /** + * 文件下载 + * + * @param filePath 删除的文件路径 + * @return 返回上传成功的文路径 + * @throws IOException 比如读写文件出错时 + * + */ + public boolean deleteFile(String filePath) throws Exception; +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java index 68130b9c923ae4bef3175b78e1eb5ab9a7e1e07e..3e77f6dd46d73928394ea73f22d11dff3460d3a9 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java @@ -1,8 +1,9 @@ package com.ruoyi.common.utils.file; -import java.io.File; import org.apache.commons.lang3.StringUtils; +import java.io.File; + /** * 文件类型工具类 * @@ -14,7 +15,7 @@ public class FileTypeUtils * 获取文件类型 *

* 例如: ruoyi.txt, 返回: txt - * + * * @param file 文件名 * @return 后缀(不含".") */ @@ -47,7 +48,7 @@ public class FileTypeUtils /** * 获取文件类型 - * + * * @param photoByte 文件字节码 * @return 后缀(不含".") */ @@ -73,4 +74,4 @@ public class FileTypeUtils } return strFileExtendName; } -} \ No newline at end of file +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java deleted file mode 100644 index d9f2b138b1ffd81f779eed2074bf6da026852d42..0000000000000000000000000000000000000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java +++ /dev/null @@ -1,232 +0,0 @@ -package com.ruoyi.common.utils.file; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.Objects; -import org.apache.commons.io.FilenameUtils; -import org.springframework.web.multipart.MultipartFile; -import com.ruoyi.common.config.RuoYiConfig; -import com.ruoyi.common.constant.Constants; -import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException; -import com.ruoyi.common.exception.file.FileSizeLimitExceededException; -import com.ruoyi.common.exception.file.InvalidExtensionException; -import com.ruoyi.common.utils.DateUtils; -import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.common.utils.uuid.Seq; - -/** - * 文件上传工具类 - * - * @author ruoyi - */ -public class FileUploadUtils -{ - /** - * 默认大小 50M - */ - public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024; - - /** - * 默认的文件名最大长度 100 - */ - public static final int DEFAULT_FILE_NAME_LENGTH = 100; - - /** - * 默认上传的地址 - */ - private static String defaultBaseDir = RuoYiConfig.getProfile(); - - public static void setDefaultBaseDir(String defaultBaseDir) - { - FileUploadUtils.defaultBaseDir = defaultBaseDir; - } - - public static String getDefaultBaseDir() - { - return defaultBaseDir; - } - - /** - * 以默认配置进行文件上传 - * - * @param file 上传的文件 - * @return 文件名称 - * @throws Exception - */ - public static final String upload(MultipartFile file) throws IOException - { - try - { - return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); - } - catch (Exception e) - { - throw new IOException(e.getMessage(), e); - } - } - - /** - * 根据文件路径上传 - * - * @param baseDir 相对应用的基目录 - * @param file 上传的文件 - * @return 文件名称 - * @throws IOException - */ - public static final String upload(String baseDir, MultipartFile file) throws IOException - { - try - { - return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); - } - catch (Exception e) - { - throw new IOException(e.getMessage(), e); - } - } - - /** - * 文件上传 - * - * @param baseDir 相对应用的基目录 - * @param file 上传的文件 - * @param allowedExtension 上传文件类型 - * @return 返回上传成功的文件名 - * @throws FileSizeLimitExceededException 如果超出最大大小 - * @throws FileNameLengthLimitExceededException 文件名太长 - * @throws IOException 比如读写文件出错时 - * @throws InvalidExtensionException 文件校验异常 - */ - public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) - throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, - InvalidExtensionException - { - int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length(); - if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) - { - throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); - } - - assertAllowed(file, allowedExtension); - - String fileName = extractFilename(file); - - String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath(); - file.transferTo(Paths.get(absPath)); - return getPathFileName(baseDir, fileName); - } - - /** - * 编码文件名 - */ - public static final String extractFilename(MultipartFile file) - { - return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(), - FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file)); - } - - public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException - { - File desc = new File(uploadDir + File.separator + fileName); - - if (!desc.exists()) - { - if (!desc.getParentFile().exists()) - { - desc.getParentFile().mkdirs(); - } - } - return desc; - } - - public static final String getPathFileName(String uploadDir, String fileName) throws IOException - { - int dirLastIndex = RuoYiConfig.getProfile().length() + 1; - String currentDir = StringUtils.substring(uploadDir, dirLastIndex); - return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; - } - - /** - * 文件大小校验 - * - * @param file 上传的文件 - * @return - * @throws FileSizeLimitExceededException 如果超出最大大小 - * @throws InvalidExtensionException - */ - public static final void assertAllowed(MultipartFile file, String[] allowedExtension) - throws FileSizeLimitExceededException, InvalidExtensionException - { - long size = file.getSize(); - if (size > DEFAULT_MAX_SIZE) - { - throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); - } - - String fileName = file.getOriginalFilename(); - String extension = getExtension(file); - if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) - { - if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) - { - throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension, - fileName); - } - else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) - { - throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension, - fileName); - } - else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) - { - throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, - fileName); - } - else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) - { - throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension, - fileName); - } - else - { - throw new InvalidExtensionException(allowedExtension, extension, fileName); - } - } - } - - /** - * 判断MIME类型是否是允许的MIME类型 - * - * @param extension - * @param allowedExtension - * @return - */ - public static final boolean isAllowedExtension(String extension, String[] allowedExtension) - { - for (String str : allowedExtension) - { - if (str.equalsIgnoreCase(extension)) - { - return true; - } - } - return false; - } - - /** - * 获取文件名的后缀 - * - * @param file 表单文件 - * @return 后缀名 - */ - public static final String getExtension(MultipartFile file) - { - String extension = FilenameUtils.getExtension(file.getOriginalFilename()); - if (StringUtils.isEmpty(extension)) - { - extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType())); - } - return extension; - } -} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java index 2062b7585854e167b27063115306b091d6b07b17..282e1b94a3c3ca238643398c1f0b9351580cfcd8 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java @@ -1,66 +1,63 @@ package com.ruoyi.common.utils.file; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.ArrayUtils; import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.exception.file.FileSizeLimitExceededException; +import com.ruoyi.common.exception.file.InvalidExtensionException; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.uuid.IdUtils; +import com.ruoyi.common.utils.uuid.Seq; +import com.ruoyi.common.utils.uuid.UUID; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; + +import static com.ruoyi.common.utils.file.FileOperateUtils.DEFAULT_MAX_SIZE; /** * 文件处理工具类 - * + * * @author ruoyi */ -public class FileUtils -{ +public class FileUtils { public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+"; + /** + * 默认的文件名最大长度 100 + */ + public static final int DEFAULT_FILE_NAME_LENGTH = 100; + /** * 输出指定文件的byte数组 - * - * @param filePath 文件路径 + * * @param os 输出流 * @return */ - public static void writeBytes(String filePath, OutputStream os) throws IOException - { - FileInputStream fis = null; - try - { - File file = new File(filePath); - if (!file.exists()) - { - throw new FileNotFoundException(filePath); - } - fis = new FileInputStream(file); + public static void writeBytes(InputStream inputStream, OutputStream os) throws IOException { + + try { + byte[] b = new byte[1024]; int length; - while ((length = fis.read(b)) > 0) - { + while ((length = inputStream.read(b)) > 0) { os.write(b, 0, length); } - } - catch (IOException e) - { + } catch (IOException e) { throw e; - } - finally - { + } finally { IOUtils.close(os); - IOUtils.close(fis); + IOUtils.close(inputStream); } } @@ -71,51 +68,44 @@ public class FileUtils * @return 目标文件 * @throws IOException IO异常 */ - public static String writeImportBytes(byte[] data) throws IOException - { + public static String writeImportBytes(byte[] data) throws IOException { return writeBytes(data, RuoYiConfig.getImportPath()); } /** * 写数据到文件中 * - * @param data 数据 + * @param data 数据 * @param uploadDir 目标文件 * @return 目标文件 * @throws IOException IO异常 */ - public static String writeBytes(byte[] data, String uploadDir) throws IOException - { + public static String writeBytes(byte[] data, String uploadDir) throws IOException { FileOutputStream fos = null; String pathName = ""; - try - { + try { String extension = getFileExtendName(data); pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension; - File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName); + File file = FileUtils.getAbsoluteFile(uploadDir, pathName); fos = new FileOutputStream(file); fos.write(data); - } - finally - { + } finally { IOUtils.close(fos); } - return FileUploadUtils.getPathFileName(uploadDir, pathName); + return FileUtils.getPathFileName(uploadDir, pathName); } /** * 删除文件 - * + * * @param filePath 文件 * @return */ - public static boolean deleteFile(String filePath) - { + public static boolean deleteFile(String filePath) { boolean flag = false; File file = new File(filePath); // 路径为文件且不为空则进行删除 - if (file.isFile() && file.exists()) - { + if (file.isFile() && file.exists()) { flag = file.delete(); } return flag; @@ -123,32 +113,28 @@ public class FileUtils /** * 文件名称验证 - * + * * @param filename 文件名称 * @return true 正常 false 非法 */ - public static boolean isValidFilename(String filename) - { + public static boolean isValidFilename(String filename) { return filename.matches(FILENAME_PATTERN); } /** * 检查文件是否可下载 - * + * * @param resource 需要下载的文件 * @return true 正常 false 非法 */ - public static boolean checkAllowDownload(String resource) - { + public static boolean checkAllowDownload(String resource) { // 禁止目录上跳级别 - if (StringUtils.contains(resource, "..")) - { + if (StringUtils.contains(resource, "..")) { return false; } // 检查允许下载的文件规则 - if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource))) - { + if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource))) { return true; } @@ -158,33 +144,26 @@ public class FileUtils /** * 下载文件名重新编码 - * - * @param request 请求对象 + * + * @param request 请求对象 * @param fileName 文件名 * @return 编码后的文件名 */ - public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException - { + public static String setFileDownloadHeader(HttpServletRequest request, String fileName) + throws UnsupportedEncodingException { final String agent = request.getHeader("USER-AGENT"); String filename = fileName; - if (agent.contains("MSIE")) - { + if (agent.contains("MSIE")) { // IE浏览器 filename = URLEncoder.encode(filename, "utf-8"); filename = filename.replace("+", " "); - } - else if (agent.contains("Firefox")) - { + } else if (agent.contains("Firefox")) { // 火狐浏览器 filename = new String(fileName.getBytes(), "ISO8859-1"); - } - else if (agent.contains("Chrome")) - { + } else if (agent.contains("Chrome")) { // google浏览器 filename = URLEncoder.encode(filename, "utf-8"); - } - else - { + } else { // 其它浏览器 filename = URLEncoder.encode(filename, "utf-8"); } @@ -194,11 +173,11 @@ public class FileUtils /** * 下载文件名重新编码 * - * @param response 响应对象 + * @param response 响应对象 * @param realFileName 真实文件名 */ - public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException - { + public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) + throws UnsupportedEncodingException { String percentEncodedFileName = percentEncode(realFileName); StringBuilder contentDispositionValue = new StringBuilder(); @@ -220,36 +199,27 @@ public class FileUtils * @param s 需要百分号编码的字符串 * @return 百分号编码后的字符串 */ - public static String percentEncode(String s) throws UnsupportedEncodingException - { + public static String percentEncode(String s) throws UnsupportedEncodingException { String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString()); return encode.replaceAll("\\+", "%20"); } /** * 获取图像后缀 - * + * * @param photoByte 图像数据 * @return 后缀名 */ - public static String getFileExtendName(byte[] photoByte) - { + public static String getFileExtendName(byte[] photoByte) { String strFileExtendName = "jpg"; if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56) - && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) - { + && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) { strFileExtendName = "gif"; - } - else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) - { + } else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) { strFileExtendName = "jpg"; - } - else if ((photoByte[0] == 66) && (photoByte[1] == 77)) - { + } else if ((photoByte[0] == 66) && (photoByte[1] == 77)) { strFileExtendName = "bmp"; - } - else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) - { + } else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) { strFileExtendName = "png"; } return strFileExtendName; @@ -257,14 +227,12 @@ public class FileUtils /** * 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png - * + * * @param fileName 路径名称 * @return 没有文件路径的名称 */ - public static String getName(String fileName) - { - if (fileName == null) - { + public static String getName(String fileName) { + if (fileName == null) { return null; } int lastUnixPos = fileName.lastIndexOf('/'); @@ -275,17 +243,147 @@ public class FileUtils /** * 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi - * + * * @param fileName 路径名称 * @return 没有文件路径和后缀的名称 */ - public static String getNameNotSuffix(String fileName) - { - if (fileName == null) - { + public static String getNameNotSuffix(String fileName) { + if (fileName == null) { return null; } String baseName = FilenameUtils.getBaseName(fileName); return baseName; } + + /** + * 编码文件名 + */ + public static final String extractFilename(MultipartFile file) { + return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(), + FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), + getExtension(file)); + } + + public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException { + File desc = new File(uploadDir + File.separator + fileName); + + if (!desc.exists()) { + if (!desc.getParentFile().exists()) { + desc.getParentFile().mkdirs(); + } + } + return desc; + } + + public static final File getAbsoluteFile(String filePath) throws IOException { + File desc = new File(filePath); + + if (!desc.exists()) { + if (!desc.getParentFile().exists()) { + desc.getParentFile().mkdirs(); + } + } + return desc; + } + + public static final String getPathFileName(String uploadDir, String fileName) throws IOException { + int dirLastIndex = RuoYiConfig.getProfile().length() + 1; + String currentDir = StringUtils.substring(uploadDir, dirLastIndex); + return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; + } + + public static final String getPathFileName(String filePath) throws IOException { + int dirLastIndex = RuoYiConfig.getProfile().length() + 1; + String currentDir = StringUtils.substring(filePath, dirLastIndex); + return Constants.RESOURCE_PREFIX + "/" + currentDir; + } + + /** + * 文件大小校验 + * + * @param file 上传的文件 + * @return + * @throws FileSizeLimitExceededException 如果超出最大大小 + * @throws InvalidExtensionException + */ + public static final void assertAllowed(MultipartFile file, String[] allowedExtension) + throws FileSizeLimitExceededException, InvalidExtensionException { + long size = file.getSize(); + if (size > DEFAULT_MAX_SIZE) { + throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); + } + + String fileName = file.getOriginalFilename(); + String extension = getExtension(file); + if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) { + if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) { + throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension, + fileName); + } else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) { + throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension, + fileName); + } else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) { + throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, + fileName); + } else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) { + throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension, + fileName); + } else { + throw new InvalidExtensionException(allowedExtension, extension, fileName); + } + } + } + + /** + * 判断MIME类型是否是允许的MIME类型 + * + * @param extension + * @param allowedExtension + * @return + */ + public static final boolean isAllowedExtension(String extension, String[] allowedExtension) { + for (String str : allowedExtension) { + if (str.equalsIgnoreCase(extension)) { + return true; + } + } + return false; + } + + /** + * 获取文件名的后缀 + * + * @param file 表单文件 + * @return 后缀名 + */ + public static final String getExtension(MultipartFile file) { + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + if (StringUtils.isEmpty(extension)) { + extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType())); + } + return extension; + } + + public static final String getRelativePath(String filePath) { + Path absolute = Paths.get(filePath); + if (!absolute.isAbsolute()){ + return filePath; + } + Path root = absolute.getRoot(); + Path normalize = absolute.normalize(); + return normalize.subpath(root.getNameCount(), normalize.getNameCount()).toString().replace("\\", "/"); + } + + public static final boolean isAbsolutePath(String path) { + Path filePath = Paths.get(path); + return filePath.isAbsolute(); + } + + public static final String fastFilePath(MultipartFile file) { + return new StringBuilder(DateUtils.datePath()) + .append(File.separatorChar).append(DateUtils.dateTimeNow()) + .append("_").append(UUID.fastUUID().toString().substring(0, 4)) + .append(".").append(FileUtils.getExtension(file)).toString(); + } + } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java index 432dfda6f7004596e022d5db1c6643ac320d5c21..0ef3317c9d5a343dceb29f1d5497bb6b96792b0f 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java @@ -1,17 +1,18 @@ package com.ruoyi.common.utils.file; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.utils.StringUtils; +import org.apache.poi.util.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.util.Arrays; -import org.apache.poi.util.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.ruoyi.common.config.RuoYiConfig; -import com.ruoyi.common.constant.Constants; -import com.ruoyi.common.utils.StringUtils; /** * 图片处理工具类 @@ -57,7 +58,7 @@ public class ImageUtils /** * 读取文件为字节数据 - * + * * @param url 地址 * @return 字节数据 */ diff --git a/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/config/MinioClientConfig.java b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/config/MinioClientConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..b2491af079577e75b7151fd62077d8136781db7a --- /dev/null +++ b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/config/MinioClientConfig.java @@ -0,0 +1,103 @@ +package com.ruoyi.middleware.minio.config; + +import io.minio.MinioClient; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +@ConfigurationProperties("minio.client") +public class MinioClientConfig { + + public MinioClientEntity getMaster() { + return master; + } + + public void setMaster(MinioClientEntity master) { + this.master = master; + } + + public List getSlave() { + return slave; + } + + public void setSlave(List slave) { + this.slave = slave; + } + + private MinioClientEntity master; + + private List slave = new ArrayList<>(); + + public static class MinioClientEntity { + + private String url; + private String accessKey; + private String secretKey; + private String name; + private String defaultBuket; + + private MinioClient client; + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getAccessKey() { + return accessKey; + } + + public void setAccessKey(String accessKey) { + this.accessKey = accessKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDefaultBuket() { + return defaultBuket; + } + + public void setDefaultBuket(String defaultBuket) { + this.defaultBuket = defaultBuket; + } + + public MinioClient getClient() { + return client; + } + + public void setClient(MinioClient client) { + this.client = client; + } + + public MinioClientEntity(String url, String accessKey, String secretKey, String name, String defaultBuket) { + this.url = url; + this.accessKey = accessKey; + this.secretKey = secretKey; + this.name = name; + this.defaultBuket = defaultBuket; + } + + public MinioClientEntity() { + } + } +} diff --git a/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/config/MinioConfig.java b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/config/MinioConfig.java index d339c05568a50aebb1f97e5222c332e42fb4f10c..7f9c165b61da87addd1a8b87394ea473b65a6a59 100644 --- a/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/config/MinioConfig.java +++ b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/config/MinioConfig.java @@ -1,80 +1,118 @@ package com.ruoyi.middleware.minio.config; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; +import com.ruoyi.common.annotation.Anonymous; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.file.FileOperateUtils; +import com.ruoyi.common.utils.file.FileUtils; +import io.minio.*; +import io.minio.errors.*; +import io.minio.messages.Bucket; +import io.minio.messages.Item; +import jakarta.annotation.PostConstruct; +import org.apache.http.impl.io.EmptyInputStream; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Configuration; -import io.minio.MinioClient; - -/** - * Minio 配置信息 - * - * @author ruoyi - */ -@Configuration -@ConfigurationProperties(prefix = "minio") +import java.io.File; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +@Configuration("MinioConfiguration") +@ConditionalOnProperty(prefix = "minio", name = { "enable" }, havingValue = "true", matchIfMissing = false) public class MinioConfig { - /** - * 服务地址 - */ - private static String url; - - /** - * 用户名 - */ - private static String accessKey; - - /** - * 密码 - */ - private static String secretKey; - - /** - * 存储桶名称 - */ - private static String bucketName; - - public static String getUrl() { - return url; + public int maxSize; + + public static String prefix = "/minio"; + @Autowired + private MinioClientConfig minioClientConfig; + + private Map slaveClients = new ConcurrentHashMap<>(); + + private List slaveClientsList = new CopyOnWriteArrayList<>(); + + private MinioClientConfig.MinioClientEntity masterClient; + + @PostConstruct + public void init() { + List collect = minioClientConfig.getSlave().stream().map(item -> { + setClient(item); + isBuketExistOnAnonymous(item); + return item; + }).toList(); + collect.forEach(item -> { + slaveClients.put(item.getName(), item); + slaveClientsList.add(item); + }); + MinioClientConfig.MinioClientEntity master = minioClientConfig.getMaster(); + setClient(master); + isBuketExistOnAnonymous(master); + masterClient = master; } - public void setUrl(String url) { - MinioConfig.url = url; + public int getMaxSize() { + return maxSize; } - public static String getAccessKey() { - return accessKey; + private void setMaxSize(int maxSize) { + this.maxSize = maxSize; } - public void setAccessKey(String accessKey) { - MinioConfig.accessKey = accessKey; + public List getSlaveClientsList() { + return slaveClientsList; } - public static String getSecretKey() { - return secretKey; + public Map getSlaveClients() { + return this.slaveClients; } - public void setSecretKey(String secretKey) { - MinioConfig.secretKey = secretKey; + public MinioClientConfig.MinioClientEntity getMasterClient() { + return this.masterClient; } - public static String getBucketName() { - return bucketName; + private static void setClient(MinioClientConfig.MinioClientEntity entity){ + if (StringUtils.isEmpty(entity.getAccessKey())){ + MinioClient build = MinioClient.builder().endpoint(entity.getUrl()).build(); + entity.setClient(build); + }else { + MinioClient build = MinioClient.builder().endpoint(entity.getUrl()) + .credentials(entity.getAccessKey(), entity.getSecretKey()).build(); + entity.setClient(build); + BucketExistsArgs bucketExistArgs = BucketExistsArgs.builder().bucket(entity.getDefaultBuket()).build(); + try { + boolean b = entity.getClient().bucketExists(bucketExistArgs); + if (!b){ + throw new RuntimeException("defaultBucket does not exist"); + } + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + entity.setClient(build); + } } - public void setBucketName(String bucketName) { - MinioConfig.bucketName = bucketName; - } - @Bean - public MinioClient getMinioClient() { + private static void isBuketExistOnAnonymous(MinioClientConfig.MinioClientEntity entity) { try { - return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build(); - } catch (Exception e) { - - return null; + String defaultBuket = entity.getDefaultBuket(); + if(StringUtils.isEmpty(defaultBuket)){ + throw new RuntimeException("defaultBuket without a default value "); + } + PutObjectArgs putObjectArgs= PutObjectArgs.builder().object(FileUtils.getRelativePath(RuoYiConfig.getProfile())+ "/") + .stream(EmptyInputStream.nullInputStream(),0,-1).bucket(entity.getDefaultBuket()).build(); + entity.getClient().putObject(putObjectArgs); + + }catch (Exception e){ + throw new RuntimeException(e); } } + } diff --git a/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/controller/MinioController.java b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/controller/MinioController.java index 48159c801c1c2d8fc550fc451bb35b65085cc1bd..45858cd6a51103d78cfdd4505be2c22a0e367e54 100644 --- a/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/controller/MinioController.java +++ b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/controller/MinioController.java @@ -1,32 +1,44 @@ package com.ruoyi.middleware.minio.controller; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.multipart.MultipartFile; - import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.file.FileUtils; -import com.ruoyi.middleware.minio.utils.FileUploadMinioUtils; +import com.ruoyi.middleware.minio.domain.MinioFileVO; + +import com.ruoyi.middleware.minio.utils.MinioUtil; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import okhttp3.Headers; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/minio") public class MinioController { - @PostMapping("/upload") + + + @GetMapping("/{buketName}") @Anonymous - public AjaxResult uploadFileMinio(MultipartFile file) throws Exception { - try { - // 上传并返回新文件名称 - String fileName = FileUploadMinioUtils.uploadMinio(file); - AjaxResult ajax = AjaxResult.success(); - ajax.put("url", fileName); - ajax.put("fileName", fileName); - ajax.put("newFileName", FileUtils.getName(fileName)); - ajax.put("originalFilename", file.getOriginalFilename()); - return ajax; - } catch (Exception e) { - return AjaxResult.error(e.getMessage()); + public void downLoadFile(HttpServletRequest request, HttpServletResponse response, + @PathVariable("buketName") String buketName, + @RequestParam("fileName") String fileName, + @RequestParam(value = "clientName", required = false) String clientName) throws Exception { + + if (!StringUtils.isEmpty(clientName)) { + MinioFileVO file = MinioUtil.SlaveClient.getFile(clientName, buketName, fileName); + Headers headers = file.getHeaders(); + + String contentType = headers.get("content-Type"); + response.setContentType(contentType); + FileUtils.writeBytes(file.getFileInputSteam(), response.getOutputStream()); + } else { + MinioFileVO file = MinioUtil.getFile(buketName, fileName); + + Headers headers = file.getHeaders(); + String contentType = headers.get("content-Type"); + response.setContentType(contentType); + FileUtils.writeBytes(file.getFileInputSteam(), response.getOutputStream()); } } } diff --git a/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/domain/MinioFileVO.java b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/domain/MinioFileVO.java new file mode 100644 index 0000000000000000000000000000000000000000..a2f433f1b31c54e42cbe63a6580be8a2532caebb --- /dev/null +++ b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/domain/MinioFileVO.java @@ -0,0 +1,68 @@ +package com.ruoyi.middleware.minio.domain; + + +import okhttp3.Headers; + +import java.io.InputStream; + +public class MinioFileVO { + + + private InputStream fileInputSteam; + private String object; + private Headers headers; + private String buket; + private String region; + public InputStream getFileInputSteam() { + return fileInputSteam; + } + + public void setFileInputSteam(InputStream fileInputSteam) { + this.fileInputSteam = fileInputSteam; + } + + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Headers getHeaders() { + return headers; + } + + public void setHeaders(Headers headers) { + this.headers = headers; + } + + public String getBuket() { + return buket; + } + + public void setBuket(String buket) { + this.buket = buket; + } + + public String getRegion() { + return region; + } + + public void setRegion(String region) { + this.region = region; + } + + public MinioFileVO(InputStream fileInputSteam, String object, Headers headers, String buket, String region) { + this.fileInputSteam = fileInputSteam; + this.object = object; + this.headers = headers; + this.buket = buket; + this.region = region; + } + + public MinioFileVO() { + } + +} diff --git a/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/exception/MinioClientErrorException.java b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/exception/MinioClientErrorException.java new file mode 100644 index 0000000000000000000000000000000000000000..35dfde3ac61f66afc6df65033389979d8553681e --- /dev/null +++ b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/exception/MinioClientErrorException.java @@ -0,0 +1,7 @@ +package com.ruoyi.middleware.minio.exception; + +public class MinioClientErrorException extends RuntimeException{ + public MinioClientErrorException(String msg){ + super(msg); + } +} diff --git a/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/exception/MinioClientNotFundException.java b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/exception/MinioClientNotFundException.java new file mode 100644 index 0000000000000000000000000000000000000000..02b4d27aa7fe16c1a98be58966ce200a5c95f73e --- /dev/null +++ b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/exception/MinioClientNotFundException.java @@ -0,0 +1,4 @@ +package com.ruoyi.middleware.minio.exception; + +public class MinioClientNotFundException extends RuntimeException{ +} diff --git a/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/utils/FileUploadMinioUtils.java b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/utils/FileUploadMinioUtils.java deleted file mode 100644 index 07530af88e84084ddca9a61257bc337e5fbec501..0000000000000000000000000000000000000000 --- a/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/utils/FileUploadMinioUtils.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.ruoyi.middleware.minio.utils; - -import java.io.IOException; - -import org.springframework.web.multipart.MultipartFile; - -import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException; -import com.ruoyi.common.exception.file.FileSizeLimitExceededException; -import com.ruoyi.common.exception.file.InvalidExtensionException; -import com.ruoyi.common.utils.file.FileUploadUtils; -import com.ruoyi.common.utils.file.MimeTypeUtils; -import com.ruoyi.middleware.minio.config.MinioConfig; - -public class FileUploadMinioUtils extends FileUploadUtils { - /** - * Minio默认上传的地址 - */ - private static String bucketName = MinioConfig.getBucketName(); - - public static String getBucketName() - { - return bucketName; - } - - /** - * 以默认BucketName配置上传到Minio服务器 - * - * @param file 上传的文件 - * @return 文件名称 - * @throws Exception - */ - public static final String uploadMinio(MultipartFile file) throws IOException - { - try - { - return uploadMinino(getBucketName(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); - } - catch (Exception e) - { - throw new IOException(e.getMessage(), e); - } - } - - /** - * 自定义bucketName配置上传到Minio服务器 - * - * @param file 上传的文件 - * @return 文件名称 - * @throws Exception - */ - public static final String uploadMinio(MultipartFile file, String bucketName) throws IOException - { - try - { - return uploadMinino(bucketName, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); - } - catch (Exception e) - { - throw new IOException(e.getMessage(), e); - } - } - - private static final String uploadMinino(String bucketName, MultipartFile file, String[] allowedExtension) - throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, - InvalidExtensionException - { - int fileNamelength = file.getOriginalFilename().length(); - if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) - { - throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); - } - assertAllowed(file, allowedExtension); - try - { - String fileName = extractFilename(file); - String pathFileName = MinioUtil.uploadFile(bucketName, fileName, file); - return pathFileName; - } - catch (Exception e) - { - throw new IOException(e.getMessage(), e); - } - } -} diff --git a/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/utils/MinioFileService.java b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/utils/MinioFileService.java new file mode 100644 index 0000000000000000000000000000000000000000..8555fc490ce73d1d165caca2a454bdca654a4e1b --- /dev/null +++ b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/utils/MinioFileService.java @@ -0,0 +1,64 @@ +package com.ruoyi.middleware.minio.utils; + +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.file.FileService; +import com.ruoyi.common.utils.file.FileUtils; +import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.middleware.minio.config.MinioConfig; +import com.ruoyi.middleware.minio.domain.MinioFileVO; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.InputStream; + +/** + * Minio文件操作实现类 + */ +@Component("file:strategy:minio") +public class MinioFileService implements FileService { + private static MinioConfig minioConfig = SpringUtils.getBean(MinioConfig.class); + + @Override + public String upload(String filePath, MultipartFile file) throws Exception { + String relativePath = null; + if (FileUtils.isAbsolutePath(filePath)) { + relativePath = FileUtils.getRelativePath(filePath); + } else { + relativePath = filePath; + } + return MinioUtil.uploadFile(minioConfig.getMasterClient().getDefaultBuket(), relativePath, file); + } + + @Override + public String upload(MultipartFile file, String name) throws Exception { + return MinioUtil.uploadFile(minioConfig.getMasterClient().getDefaultBuket(), name, file); + } + + @Override + public String upload(MultipartFile file) throws Exception { + String filePath = RuoYiConfig.getProfile() + File.separator + FileUtils.fastFilePath(file); + return upload(filePath, file); + } + + @Override + public String upload(String baseDir, String fileName, MultipartFile file) throws Exception { + + return upload(baseDir + File.pathSeparator + fileName, file); + } + + @Override + public InputStream downLoad(String fileUrl) throws Exception { + String filePath = StringUtils.substringAfter(fileUrl, "?fileName="); + MinioFileVO file = MinioUtil.getFile(minioConfig.getMasterClient().getDefaultBuket(), filePath); + return file.getFileInputSteam(); + } + + @Override + public boolean deleteFile(String fileUrl) throws Exception { + String filePath = StringUtils.substringAfter(fileUrl, "?fileName="); + MinioUtil.removeFile(minioConfig.getMasterClient().getDefaultBuket(), filePath); + return true; + } +} diff --git a/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/utils/MinioUtil.java b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/utils/MinioUtil.java index 46783c040099c387246b3e70fe08d0bcb23ea109..6f5157a63f560527a52d1ce33cb85de4b33a773d 100644 --- a/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/utils/MinioUtil.java +++ b/ruoyi-middleware/ruoyi-middleware-minio/src/main/java/com/ruoyi/middleware/minio/utils/MinioUtil.java @@ -1,46 +1,277 @@ package com.ruoyi.middleware.minio.utils; -import java.io.IOException; -import java.io.InputStream; - -import org.springframework.web.multipart.MultipartFile; - -import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.exception.file.FileException; +import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException; +import com.ruoyi.common.exception.file.FileSizeLimitExceededException; +import com.ruoyi.common.exception.file.InvalidExtensionException; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.file.FileUtils; import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.common.utils.uuid.UUID; +import com.ruoyi.middleware.minio.config.MinioClientConfig; +import com.ruoyi.middleware.minio.config.MinioConfig; +import com.ruoyi.middleware.minio.domain.MinioFileVO; +import com.ruoyi.middleware.minio.exception.MinioClientErrorException; +import com.ruoyi.middleware.minio.exception.MinioClientNotFundException; +import io.minio.*; +import io.minio.messages.DeleteError; +import org.springframework.web.multipart.MultipartFile; -import io.minio.GetPresignedObjectUrlArgs; -import io.minio.MinioClient; -import io.minio.PutObjectArgs; -import io.minio.http.Method; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; /** - * Minio 文件存储工具类 + * Minio工具 * - * @author ruoyi */ -public class MinioUtil -{ +public class MinioUtil { + + private static MinioConfig minioConfig = SpringUtils.getBean(MinioConfig.class); + /** - * 上传文件 + * 文件上传 + * + * @param buketName Minio的桶名 + * @param filePath 上传的文件路径 + * @param contentType 上传文件类型 + * @param inputStream 上传文件的输入流 + * @return 返回上传成功的文路径 + * @throws IOException 比如读写文件出错时 * - * @param bucketName 桶名称 - * @param fileName - * @throws IOException - */ - public static String uploadFile(String bucketName, String fileName, MultipartFile multipartFile) throws IOException - { - String url = ""; - MinioClient minioClient = SpringUtils.getBean(MinioClient.class); - try (InputStream inputStream = multipartFile.getInputStream()) - { - minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(inputStream, multipartFile.getSize(), -1).contentType(multipartFile.getContentType()).build()); - url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(fileName).method(Method.GET).build()); - url = url.substring(0, url.indexOf('?')); - return ServletUtils.urlDecode(url); - } - catch (Exception e) - { - throw new IOException(e.getMessage(), e); + */ + public static String uploadFile(String buketName, String filePath, + String contentType, InputStream inputStream) + throws Exception { + PutObjectArgs build = PutObjectArgs.builder().contentType(contentType) + .stream(inputStream, inputStream.available(), -1) + .bucket(buketName).object(filePath).build(); + return uploadFile(build); + } + + /** + * 文件上传 + * + * @param putObjectArgs Minio上传参数 + * @return 返回上传成功的文件路径 + */ + public static String uploadFile(PutObjectArgs putObjectArgs) throws Exception { + try { + MinioClientConfig.MinioClientEntity masterClient = minioConfig.getMasterClient(); + masterClient.getClient().putObject(putObjectArgs); + StringBuilder url = new StringBuilder(); + url.append(MinioConfig.prefix).append("/").append(masterClient.getDefaultBuket()) + // .append("/").append(filePath) + .append("?").append("fileName=").append(putObjectArgs.object()); + return url.toString(); + } catch (Exception e) { + throw new MinioClientErrorException(e.getMessage()); + } + + } + + /** + * 文件上传(从节点递归,直到上传成功) + * + * @param index 开始递归的从节点索引 + * @param putObjectArgs Minio上传文件参数 + * @return 返回上传成功的文件路径 + */ + private static String uploadFileIterator(int index, PutObjectArgs putObjectArgs) { + List slaveClientsList = minioConfig.getSlaveClientsList(); + if (index >= slaveClientsList.size()) { + throw new MinioClientNotFundException(); + } + try { + MinioClientConfig.MinioClientEntity minioClientEntity = slaveClientsList.get(index); + PutObjectArgs build = PutObjectArgs.builder().contentType(putObjectArgs.contentType()) + .object(putObjectArgs.object()) + .stream(putObjectArgs.stream(), putObjectArgs.stream().available(), -1) + .bucket(minioClientEntity.getDefaultBuket()).build(); + minioClientEntity.getClient().putObject(build); + StringBuilder url = new StringBuilder(); + url.append(MinioConfig.prefix).append("/").append(minioClientEntity.getDefaultBuket()) + .append("?").append("fileName=").append(putObjectArgs.object()) + .append("&").append("clientName=").append(minioClientEntity.getName()); + return url.toString(); + } catch (Exception e) { + return uploadFileIterator(index + 1, putObjectArgs); + } + } + + /** + * 文件上传 + * + * @param buketName Minio的桶名 + * @param file 上传的文件 + * @param fileName 上传文件名 + * @return 返回上传成功的文件名 + * @throws IOException 比如读写文件出错时 + */ + public static String uploadFile(String buketName, String fileName, MultipartFile file) throws Exception { + return uploadFile(buketName, fileName, file.getContentType(), file.getInputStream()); + } + + /** + * 文件上传 + * + * @param buketName Minio的桶名 + * @param file 上传的文件 + * @return 返回上传成功的文件名 + * @throws IOException 比如读写文件出错时 + */ + public static String uploadFile(String buketName, MultipartFile file) throws Exception { + String fileName = DateUtils.dateTimeNow() + UUID.fastUUID().toString().substring(0, 5) + "." + + FileUtils.getExtension(file); + + return uploadFile(buketName, fileName, file.getContentType(), file.getInputStream()); + } + + /** + * 文件删除 + * + * @param removeObjectArgs Minio删除文件的参数对象 + * @throws IOException 比如读写文件出错时 + */ + public static void removeFile(RemoveObjectArgs removeObjectArgs) throws Exception { + minioConfig.getMasterClient().getClient().removeObject(removeObjectArgs); + } + + /** + * 文件删除 + * + * @param buketName Minio的桶名 + * @param filePath 上传文件路径 + * @throws IOException 比如读写文件出错时 + */ + public static void removeFile(String buketName, String filePath) throws Exception { + RemoveObjectArgs build = RemoveObjectArgs.builder().object(filePath).bucket(buketName).build(); + removeFile(build); + } + + /** + * 文件批量删除 + * + * @param removeObjectsArgs Minio批量删除文件参数对象 + * @return 删除结果 + * @throws IOException 比如读写文件出错时 + */ + public static Iterable> removeFiles(RemoveObjectsArgs removeObjectsArgs) { + return minioConfig.getMasterClient().getClient().removeObjects(removeObjectsArgs); + } + + /** + * 文件下载 + * + * @param getObjectArgs Minio获取文件参数对象 + * @return 返回封装的Minio下载结果对象 + * @throws IOException 比如读写文件出错时 + */ + public static MinioFileVO getFile(GetObjectArgs getObjectArgs) throws Exception { + GetObjectResponse inputStream = minioConfig.getMasterClient().getClient().getObject(getObjectArgs); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + byte[] bytes = new byte[minioConfig.maxSize]; + int length = 0; + while (true) { + try { + if (!((length = inputStream.read(bytes, 0, bytes.length)) > 0)) { + break; + } + } catch (Exception e) { + throw new FileException("500", new String[] { e.getMessage() }); + } + byteArrayOutputStream.write(bytes, 0, length); + } + return new MinioFileVO(inputStream, inputStream.object(), inputStream.headers(), inputStream.bucket(), + inputStream.region()); + } + + /** + * 文件下载 + * + * @param buketName Minio的桶名 + * @param filePath 文件路径 + * @return 返回封装的Minio下载文件对象 + * @throws IOException 比如读写文件出错时 + */ + public static MinioFileVO getFile(String buketName, String filePath) throws Exception { + GetObjectArgs build = GetObjectArgs.builder().object(filePath).bucket(buketName).build(); + return getFile(build); + } + + /** + * 从节点对应操作工具类 + */ + public static class SlaveClient { + public static String uploadFile(String clientName, String buketName, String fileName, + String contentType, InputStream inputStream) + throws Exception { + PutObjectArgs build = PutObjectArgs.builder().contentType(contentType) + .stream(inputStream, inputStream.available(), -1) + .bucket(buketName).object(fileName).build(); + return uploadFile(clientName, build); } + + public static String uploadFile(String clientName, PutObjectArgs putObjectArgs) throws Exception { + MinioClientConfig.MinioClientEntity minioClientEntity = minioConfig.getSlaveClients().get(clientName); + minioClientEntity.getClient().putObject(putObjectArgs); + StringBuilder url = new StringBuilder(); + url.append(MinioConfig.prefix).append("/").append(minioClientEntity.getDefaultBuket()) + .append("?").append("fileName=").append(putObjectArgs.object()) + .append("&").append("clientName=").append(minioClientEntity.getName()); + return url.toString(); + } + + public static String uploadFile(String clientName, String buketName, String fileName, MultipartFile file) + throws Exception { + + return uploadFile(clientName, buketName, fileName, file.getContentType(), file.getInputStream()); + } + + public static String uploadFile(String clientName, String buketName, MultipartFile file) throws Exception { + String fileName = DateUtils.dateTimeNow() + UUID.fastUUID().toString().substring(0, 5); + return uploadFile(clientName, buketName, fileName, file.getContentType(), file.getInputStream()); + } + + public static void removeFile(String clientName, RemoveObjectArgs removeObjectArgs) throws Exception { + minioConfig.getSlaveClients().get(clientName).getClient().removeObject(removeObjectArgs); + } + + public static void removeFile(String clientName, String buketName, String fileName) throws Exception { + RemoveObjectArgs build = RemoveObjectArgs.builder().object(fileName).bucket(buketName).build(); + removeFile(clientName, build); + } + + public static Iterable> removeFiles(RemoveObjectsArgs removeObjectsArgs) { + return minioConfig.getMasterClient().getClient().removeObjects(removeObjectsArgs); + } + + public static MinioFileVO getFile(String clientName, GetObjectArgs getObjectArgs) throws Exception { + GetObjectResponse inputStream = minioConfig.getSlaveClients().get(clientName).getClient() + .getObject(getObjectArgs); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + byte[] bytes = new byte[minioConfig.maxSize]; + int length = 0; + while (true) { + try { + if (!((length = inputStream.read(bytes, 0, bytes.length)) > 0)) { + break; + } + } catch (Exception e) { + throw new FileException("500", new String[] { e.getMessage() }); + } + byteArrayOutputStream.write(bytes, 0, length); + } + return new MinioFileVO(inputStream, inputStream.object(), inputStream.headers(), inputStream.bucket(), + inputStream.region()); + } + + public static MinioFileVO getFile(String clientName, String buketName, String fileName) throws Exception { + GetObjectArgs build = GetObjectArgs.builder().object(fileName).bucket(buketName).build(); + return getFile(clientName, build); + } + } + }