init
This commit is contained in:
parent
4b2f365605
commit
52aa611a1d
@ -1,27 +1,14 @@
|
|||||||
package com.ruoyi.web.controller.common;
|
package com.ruoyi.web.controller.common;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import com.ruoyi.common.annotation.Anonymous;
|
||||||
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.config.RuoYiConfig;
|
import com.ruoyi.common.config.RuoYiConfig;
|
||||||
import com.ruoyi.common.constant.Constants;
|
import com.ruoyi.common.constant.Constants;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
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.FileUtils;
|
||||||
|
import com.ruoyi.common.utils.file.MimeTypeUtils;
|
||||||
import com.ruoyi.framework.config.ServerConfig;
|
import com.ruoyi.framework.config.ServerConfig;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.Parameters;
|
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 io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
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
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@Tag(name = "通用请求处理")
|
@Tag(name = "通用请求处理")
|
||||||
@ -48,7 +44,7 @@ public class CommonController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用下载请求
|
* 通用下载请求
|
||||||
*
|
*
|
||||||
* @param fileName 文件名称
|
* @param fileName 文件名称
|
||||||
* @param delete 是否删除
|
* @param delete 是否删除
|
||||||
*/
|
*/
|
||||||
@ -58,6 +54,7 @@ public class CommonController {
|
|||||||
@Parameter(name = "delete", description = "是否删除")
|
@Parameter(name = "delete", description = "是否删除")
|
||||||
})
|
})
|
||||||
@GetMapping("/download")
|
@GetMapping("/download")
|
||||||
|
@Anonymous
|
||||||
public void fileDownload(
|
public void fileDownload(
|
||||||
@RequestParam("fileName") String fileName,
|
@RequestParam("fileName") String fileName,
|
||||||
@RequestParam("delete") Boolean delete,
|
@RequestParam("delete") Boolean delete,
|
||||||
@ -72,9 +69,10 @@ public class CommonController {
|
|||||||
|
|
||||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||||
FileUtils.setAttachmentResponseHeader(response, realFileName);
|
FileUtils.setAttachmentResponseHeader(response, realFileName);
|
||||||
FileUtils.writeBytes(filePath, response.getOutputStream());
|
// FileUtils.writeBytes(filePath, response.getOutputStream());
|
||||||
|
FileOperateUtils.downLoad(filePath, response.getOutputStream());
|
||||||
if (delete) {
|
if (delete) {
|
||||||
FileUtils.deleteFile(filePath);
|
FileOperateUtils.deleteFile(fileName);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("下载文件失败", e);
|
log.error("下载文件失败", e);
|
||||||
@ -86,12 +84,13 @@ public class CommonController {
|
|||||||
*/
|
*/
|
||||||
@Operation(summary = "通用上传请求(单个)")
|
@Operation(summary = "通用上传请求(单个)")
|
||||||
@PostMapping("/upload")
|
@PostMapping("/upload")
|
||||||
|
@Anonymous
|
||||||
public AjaxResult uploadFile(@RequestBody MultipartFile file) throws Exception {
|
public AjaxResult uploadFile(@RequestBody MultipartFile file) throws Exception {
|
||||||
try {
|
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;
|
String url = serverConfig.getUrl() + fileName;
|
||||||
AjaxResult ajax = AjaxResult.success();
|
AjaxResult ajax = AjaxResult.success();
|
||||||
ajax.put("url", url);
|
ajax.put("url", url);
|
||||||
@ -109,6 +108,7 @@ public class CommonController {
|
|||||||
*/
|
*/
|
||||||
@Operation(summary = "通用上传请求(多个)")
|
@Operation(summary = "通用上传请求(多个)")
|
||||||
@PostMapping("/uploads")
|
@PostMapping("/uploads")
|
||||||
|
@Anonymous
|
||||||
public AjaxResult uploadFiles(@RequestBody List<MultipartFile> files)
|
public AjaxResult uploadFiles(@RequestBody List<MultipartFile> files)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
try {
|
try {
|
||||||
@ -120,7 +120,7 @@ public class CommonController {
|
|||||||
List<String> originalFilenames = new ArrayList<String>();
|
List<String> originalFilenames = new ArrayList<String>();
|
||||||
for (MultipartFile file : files) {
|
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;
|
String url = serverConfig.getUrl() + fileName;
|
||||||
urls.add(url);
|
urls.add(url);
|
||||||
fileNames.add(fileName);
|
fileNames.add(fileName);
|
||||||
@ -143,6 +143,7 @@ public class CommonController {
|
|||||||
*/
|
*/
|
||||||
@Operation(summary = "本地资源通用下载")
|
@Operation(summary = "本地资源通用下载")
|
||||||
@GetMapping("/download/resource")
|
@GetMapping("/download/resource")
|
||||||
|
@Anonymous
|
||||||
public void resourceDownload(@Parameter(name = "resource", description = "资源名称") String resource,
|
public void resourceDownload(@Parameter(name = "resource", description = "资源名称") String resource,
|
||||||
HttpServletRequest request, HttpServletResponse response)
|
HttpServletRequest request, HttpServletResponse response)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
@ -157,8 +158,9 @@ public class CommonController {
|
|||||||
// 下载名称
|
// 下载名称
|
||||||
String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
|
String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
|
||||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||||
FileUtils.setAttachmentResponseHeader(response, downloadName);
|
FileUtils.setAttachmentResponseHeader(response, resource);
|
||||||
FileUtils.writeBytes(downloadPath, response.getOutputStream());
|
FileOperateUtils.downLoad(resource, response.getOutputStream());
|
||||||
|
// FileUtils.writeBytes(downloadPath, response.getOutputStream());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("下载文件失败", e);
|
log.error("下载文件失败", e);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,5 @@
|
|||||||
package com.ruoyi.web.controller.system;
|
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.annotation.Log;
|
||||||
import com.ruoyi.common.config.RuoYiConfig;
|
import com.ruoyi.common.config.RuoYiConfig;
|
||||||
import com.ruoyi.common.core.controller.BaseController;
|
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.enums.BusinessType;
|
||||||
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
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.common.utils.file.MimeTypeUtils;
|
||||||
import com.ruoyi.framework.web.service.TokenService;
|
import com.ruoyi.framework.web.service.TokenService;
|
||||||
import com.ruoyi.system.service.ISysUserService;
|
import com.ruoyi.system.service.ISysUserService;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
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
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@Tag(name = "个人信息" , description = "业务处理")
|
@Tag(name = "个人信息", description = "业务处理")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/system/user/profile")
|
@RequestMapping("/system/user/profile")
|
||||||
public class SysProfileController extends BaseController
|
public class SysProfileController extends BaseController {
|
||||||
{
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysUserService userService;
|
private ISysUserService userService;
|
||||||
|
|
||||||
@ -48,8 +42,7 @@ public class SysProfileController extends BaseController
|
|||||||
*/
|
*/
|
||||||
@Operation(summary = "个人信息")
|
@Operation(summary = "个人信息")
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public AjaxResult profile()
|
public AjaxResult profile() {
|
||||||
{
|
|
||||||
LoginUser loginUser = getLoginUser();
|
LoginUser loginUser = getLoginUser();
|
||||||
SysUser user = loginUser.getUser();
|
SysUser user = loginUser.getUser();
|
||||||
AjaxResult ajax = AjaxResult.success(user);
|
AjaxResult ajax = AjaxResult.success(user);
|
||||||
@ -64,25 +57,21 @@ public class SysProfileController extends BaseController
|
|||||||
@Operation(summary = "修改用户")
|
@Operation(summary = "修改用户")
|
||||||
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
|
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public AjaxResult updateProfile(@RequestBody SysUser user)
|
public AjaxResult updateProfile(@RequestBody SysUser user) {
|
||||||
{
|
|
||||||
LoginUser loginUser = getLoginUser();
|
LoginUser loginUser = getLoginUser();
|
||||||
SysUser sysUser = loginUser.getUser();
|
SysUser sysUser = loginUser.getUser();
|
||||||
user.setUserName(sysUser.getUserName());
|
user.setUserName(sysUser.getUserName());
|
||||||
if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
|
if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
|
||||||
{
|
|
||||||
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
|
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
|
if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
|
||||||
{
|
|
||||||
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
|
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
|
||||||
}
|
}
|
||||||
user.setUserId(sysUser.getUserId());
|
user.setUserId(sysUser.getUserId());
|
||||||
user.setPassword(null);
|
user.setPassword(null);
|
||||||
user.setAvatar(null);
|
user.setAvatar(null);
|
||||||
user.setDeptId(null);
|
user.setDeptId(null);
|
||||||
if (userService.updateUserProfile(user) > 0)
|
if (userService.updateUserProfile(user) > 0) {
|
||||||
{
|
|
||||||
// 更新缓存用户信息
|
// 更新缓存用户信息
|
||||||
sysUser.setNickName(user.getNickName());
|
sysUser.setNickName(user.getNickName());
|
||||||
sysUser.setPhonenumber(user.getPhonenumber());
|
sysUser.setPhonenumber(user.getPhonenumber());
|
||||||
@ -100,22 +89,18 @@ public class SysProfileController extends BaseController
|
|||||||
@Operation(summary = "重置密码")
|
@Operation(summary = "重置密码")
|
||||||
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
|
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
|
||||||
@PutMapping("/updatePwd")
|
@PutMapping("/updatePwd")
|
||||||
public AjaxResult updatePwd(String oldPassword, String newPassword)
|
public AjaxResult updatePwd(String oldPassword, String newPassword) {
|
||||||
{
|
|
||||||
LoginUser loginUser = getLoginUser();
|
LoginUser loginUser = getLoginUser();
|
||||||
String userName = loginUser.getUsername();
|
String userName = loginUser.getUsername();
|
||||||
String password = loginUser.getPassword();
|
String password = loginUser.getPassword();
|
||||||
if (!SecurityUtils.matchesPassword(oldPassword, password))
|
if (!SecurityUtils.matchesPassword(oldPassword, password)) {
|
||||||
{
|
|
||||||
return error("修改密码失败,旧密码错误");
|
return error("修改密码失败,旧密码错误");
|
||||||
}
|
}
|
||||||
if (SecurityUtils.matchesPassword(newPassword, password))
|
if (SecurityUtils.matchesPassword(newPassword, password)) {
|
||||||
{
|
|
||||||
return error("新密码不能与旧密码相同");
|
return error("新密码不能与旧密码相同");
|
||||||
}
|
}
|
||||||
newPassword = SecurityUtils.encryptPassword(newPassword);
|
newPassword = SecurityUtils.encryptPassword(newPassword);
|
||||||
if (userService.resetUserPwd(userName, newPassword) > 0)
|
if (userService.resetUserPwd(userName, newPassword) > 0) {
|
||||||
{
|
|
||||||
// 更新缓存用户密码
|
// 更新缓存用户密码
|
||||||
loginUser.getUser().setPassword(newPassword);
|
loginUser.getUser().setPassword(newPassword);
|
||||||
tokenService.setLoginUser(loginUser);
|
tokenService.setLoginUser(loginUser);
|
||||||
@ -130,14 +115,14 @@ public class SysProfileController extends BaseController
|
|||||||
@Operation(summary = "头像上传")
|
@Operation(summary = "头像上传")
|
||||||
@Log(title = "用户头像", businessType = BusinessType.UPDATE)
|
@Log(title = "用户头像", businessType = BusinessType.UPDATE)
|
||||||
@PostMapping("/avatar")
|
@PostMapping("/avatar")
|
||||||
public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception
|
public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception {
|
||||||
{
|
if (!file.isEmpty()) {
|
||||||
if (!file.isEmpty())
|
|
||||||
{
|
|
||||||
LoginUser loginUser = getLoginUser();
|
LoginUser loginUser = getLoginUser();
|
||||||
String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION);
|
String extractPath = loginUser.getUsername() + File.separator + loginUser.getUserId();
|
||||||
if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
|
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();
|
AjaxResult ajax = AjaxResult.success();
|
||||||
ajax.put("imgUrl", avatar);
|
ajax.put("imgUrl", avatar);
|
||||||
// 更新缓存用户头像
|
// 更新缓存用户头像
|
||||||
|
@ -25,7 +25,11 @@ spring:
|
|||||||
|
|
||||||
# Minio配置
|
# Minio配置
|
||||||
minio:
|
minio:
|
||||||
url: http://localhost:9000
|
enable: true
|
||||||
accessKey: minioadmin
|
downLoadLimit: 1024
|
||||||
secretKey: minioadmin
|
client:
|
||||||
bucketName: ruoyi
|
master:
|
||||||
|
url: http://localhost:9000
|
||||||
|
accessKey: root
|
||||||
|
secretKey: 123456
|
||||||
|
defaultBuket: ruoyi
|
||||||
|
@ -13,6 +13,8 @@ ruoyi:
|
|||||||
# 验证码类型 math 数组计算 char 字符验证
|
# 验证码类型 math 数组计算 char 字符验证
|
||||||
captchaType: math
|
captchaType: math
|
||||||
|
|
||||||
|
fileServer: minio
|
||||||
|
|
||||||
# 开发环境配置
|
# 开发环境配置
|
||||||
server:
|
server:
|
||||||
# 服务器的HTTP端口,默认为8080
|
# 服务器的HTTP端口,默认为8080
|
||||||
|
@ -5,7 +5,7 @@ import org.springframework.stereotype.Component;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取项目相关配置
|
* 读取项目相关配置
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@ -24,12 +24,17 @@ public class RuoYiConfig
|
|||||||
/** 上传路径 */
|
/** 上传路径 */
|
||||||
private static String profile;
|
private static String profile;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static String fileServer;
|
||||||
|
|
||||||
/** 获取地址开关 */
|
/** 获取地址开关 */
|
||||||
private static boolean addressEnabled;
|
private static boolean addressEnabled;
|
||||||
|
|
||||||
/** 验证码类型 */
|
/** 验证码类型 */
|
||||||
private static String captchaType;
|
private static String captchaType;
|
||||||
|
|
||||||
|
|
||||||
public String getName()
|
public String getName()
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
@ -88,6 +93,14 @@ public class RuoYiConfig
|
|||||||
RuoYiConfig.captchaType = captchaType;
|
RuoYiConfig.captchaType = captchaType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getFileServer() {
|
||||||
|
return fileServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileServer(String fileServer) {
|
||||||
|
RuoYiConfig.fileServer = fileServer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取导入上传路径
|
* 获取导入上传路径
|
||||||
*/
|
*/
|
||||||
|
@ -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 DiskFileUtil implements FileUtil {
|
||||||
|
|
||||||
|
private static String defaultBaseDir = RuoYiConfig.getProfile();
|
||||||
|
|
||||||
|
public static void setDefaultBaseDir(String defaultBaseDir) {
|
||||||
|
DiskFileUtil.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 FileUtil fileUtil = 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 fileUtil.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 fileUtil.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 = fileUtil.downLoad(fileUrl);
|
||||||
|
FileUtils.writeBytes(inputStream, outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据文件路径删除
|
||||||
|
*
|
||||||
|
* @param fileUrl 下载文件路径
|
||||||
|
* @return 是否成功
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static final boolean deleteFile(String fileUrl) throws Exception {
|
||||||
|
return fileUtil.deleteFile(fileUrl);
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
package com.ruoyi.common.utils.file;
|
package com.ruoyi.common.utils.file;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件类型工具类
|
* 文件类型工具类
|
||||||
*
|
*
|
||||||
@ -14,7 +15,7 @@ public class FileTypeUtils
|
|||||||
* 获取文件类型
|
* 获取文件类型
|
||||||
* <p>
|
* <p>
|
||||||
* 例如: ruoyi.txt, 返回: txt
|
* 例如: ruoyi.txt, 返回: txt
|
||||||
*
|
*
|
||||||
* @param file 文件名
|
* @param file 文件名
|
||||||
* @return 后缀(不含".")
|
* @return 后缀(不含".")
|
||||||
*/
|
*/
|
||||||
@ -47,7 +48,7 @@ public class FileTypeUtils
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取文件类型
|
* 获取文件类型
|
||||||
*
|
*
|
||||||
* @param photoByte 文件字节码
|
* @param photoByte 文件字节码
|
||||||
* @return 后缀(不含".")
|
* @return 后缀(不含".")
|
||||||
*/
|
*/
|
||||||
@ -73,4 +74,4 @@ public class FileTypeUtils
|
|||||||
}
|
}
|
||||||
return strFileExtendName;
|
return strFileExtendName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 FileUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件上传
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
}
|
@ -1,66 +1,63 @@
|
|||||||
package com.ruoyi.common.utils.file;
|
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.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.DateUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.common.utils.uuid.IdUtils;
|
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.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
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
public class FileUtils
|
public class FileUtils {
|
||||||
{
|
|
||||||
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
|
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认的文件名最大长度 100
|
||||||
|
*/
|
||||||
|
public static final int DEFAULT_FILE_NAME_LENGTH = 100;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输出指定文件的byte数组
|
* 输出指定文件的byte数组
|
||||||
*
|
*
|
||||||
* @param filePath 文件路径
|
|
||||||
* @param os 输出流
|
* @param os 输出流
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static void writeBytes(String filePath, OutputStream os) throws IOException
|
public static void writeBytes(InputStream inputStream, OutputStream os) throws IOException {
|
||||||
{
|
|
||||||
FileInputStream fis = null;
|
try {
|
||||||
try
|
|
||||||
{
|
|
||||||
File file = new File(filePath);
|
|
||||||
if (!file.exists())
|
|
||||||
{
|
|
||||||
throw new FileNotFoundException(filePath);
|
|
||||||
}
|
|
||||||
fis = new FileInputStream(file);
|
|
||||||
byte[] b = new byte[1024];
|
byte[] b = new byte[1024];
|
||||||
int length;
|
int length;
|
||||||
while ((length = fis.read(b)) > 0)
|
while ((length = inputStream.read(b)) > 0) {
|
||||||
{
|
|
||||||
os.write(b, 0, length);
|
os.write(b, 0, length);
|
||||||
}
|
}
|
||||||
}
|
} catch (IOException e) {
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
} finally {
|
||||||
finally
|
|
||||||
{
|
|
||||||
IOUtils.close(os);
|
IOUtils.close(os);
|
||||||
IOUtils.close(fis);
|
IOUtils.close(inputStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,51 +68,44 @@ public class FileUtils
|
|||||||
* @return 目标文件
|
* @return 目标文件
|
||||||
* @throws IOException IO异常
|
* @throws IOException IO异常
|
||||||
*/
|
*/
|
||||||
public static String writeImportBytes(byte[] data) throws IOException
|
public static String writeImportBytes(byte[] data) throws IOException {
|
||||||
{
|
|
||||||
return writeBytes(data, RuoYiConfig.getImportPath());
|
return writeBytes(data, RuoYiConfig.getImportPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 写数据到文件中
|
* 写数据到文件中
|
||||||
*
|
*
|
||||||
* @param data 数据
|
* @param data 数据
|
||||||
* @param uploadDir 目标文件
|
* @param uploadDir 目标文件
|
||||||
* @return 目标文件
|
* @return 目标文件
|
||||||
* @throws IOException IO异常
|
* @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;
|
FileOutputStream fos = null;
|
||||||
String pathName = "";
|
String pathName = "";
|
||||||
try
|
try {
|
||||||
{
|
|
||||||
String extension = getFileExtendName(data);
|
String extension = getFileExtendName(data);
|
||||||
pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
|
pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
|
||||||
File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName);
|
File file = FileUtils.getAbsoluteFile(uploadDir, pathName);
|
||||||
fos = new FileOutputStream(file);
|
fos = new FileOutputStream(file);
|
||||||
fos.write(data);
|
fos.write(data);
|
||||||
}
|
} finally {
|
||||||
finally
|
|
||||||
{
|
|
||||||
IOUtils.close(fos);
|
IOUtils.close(fos);
|
||||||
}
|
}
|
||||||
return FileUploadUtils.getPathFileName(uploadDir, pathName);
|
return FileUtils.getPathFileName(uploadDir, pathName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除文件
|
* 删除文件
|
||||||
*
|
*
|
||||||
* @param filePath 文件
|
* @param filePath 文件
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static boolean deleteFile(String filePath)
|
public static boolean deleteFile(String filePath) {
|
||||||
{
|
|
||||||
boolean flag = false;
|
boolean flag = false;
|
||||||
File file = new File(filePath);
|
File file = new File(filePath);
|
||||||
// 路径为文件且不为空则进行删除
|
// 路径为文件且不为空则进行删除
|
||||||
if (file.isFile() && file.exists())
|
if (file.isFile() && file.exists()) {
|
||||||
{
|
|
||||||
flag = file.delete();
|
flag = file.delete();
|
||||||
}
|
}
|
||||||
return flag;
|
return flag;
|
||||||
@ -123,32 +113,28 @@ public class FileUtils
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件名称验证
|
* 文件名称验证
|
||||||
*
|
*
|
||||||
* @param filename 文件名称
|
* @param filename 文件名称
|
||||||
* @return true 正常 false 非法
|
* @return true 正常 false 非法
|
||||||
*/
|
*/
|
||||||
public static boolean isValidFilename(String filename)
|
public static boolean isValidFilename(String filename) {
|
||||||
{
|
|
||||||
return filename.matches(FILENAME_PATTERN);
|
return filename.matches(FILENAME_PATTERN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查文件是否可下载
|
* 检查文件是否可下载
|
||||||
*
|
*
|
||||||
* @param resource 需要下载的文件
|
* @param resource 需要下载的文件
|
||||||
* @return true 正常 false 非法
|
* @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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查允许下载的文件规则
|
// 检查允许下载的文件规则
|
||||||
if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))
|
if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource))) {
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,33 +144,26 @@ public class FileUtils
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载文件名重新编码
|
* 下载文件名重新编码
|
||||||
*
|
*
|
||||||
* @param request 请求对象
|
* @param request 请求对象
|
||||||
* @param fileName 文件名
|
* @param fileName 文件名
|
||||||
* @return 编码后的文件名
|
* @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");
|
final String agent = request.getHeader("USER-AGENT");
|
||||||
String filename = fileName;
|
String filename = fileName;
|
||||||
if (agent.contains("MSIE"))
|
if (agent.contains("MSIE")) {
|
||||||
{
|
|
||||||
// IE浏览器
|
// IE浏览器
|
||||||
filename = URLEncoder.encode(filename, "utf-8");
|
filename = URLEncoder.encode(filename, "utf-8");
|
||||||
filename = filename.replace("+", " ");
|
filename = filename.replace("+", " ");
|
||||||
}
|
} else if (agent.contains("Firefox")) {
|
||||||
else if (agent.contains("Firefox"))
|
|
||||||
{
|
|
||||||
// 火狐浏览器
|
// 火狐浏览器
|
||||||
filename = new String(fileName.getBytes(), "ISO8859-1");
|
filename = new String(fileName.getBytes(), "ISO8859-1");
|
||||||
}
|
} else if (agent.contains("Chrome")) {
|
||||||
else if (agent.contains("Chrome"))
|
|
||||||
{
|
|
||||||
// google浏览器
|
// google浏览器
|
||||||
filename = URLEncoder.encode(filename, "utf-8");
|
filename = URLEncoder.encode(filename, "utf-8");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
// 其它浏览器
|
// 其它浏览器
|
||||||
filename = URLEncoder.encode(filename, "utf-8");
|
filename = URLEncoder.encode(filename, "utf-8");
|
||||||
}
|
}
|
||||||
@ -194,11 +173,11 @@ public class FileUtils
|
|||||||
/**
|
/**
|
||||||
* 下载文件名重新编码
|
* 下载文件名重新编码
|
||||||
*
|
*
|
||||||
* @param response 响应对象
|
* @param response 响应对象
|
||||||
* @param realFileName 真实文件名
|
* @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);
|
String percentEncodedFileName = percentEncode(realFileName);
|
||||||
|
|
||||||
StringBuilder contentDispositionValue = new StringBuilder();
|
StringBuilder contentDispositionValue = new StringBuilder();
|
||||||
@ -220,36 +199,27 @@ public class FileUtils
|
|||||||
* @param s 需要百分号编码的字符串
|
* @param s 需要百分号编码的字符串
|
||||||
* @return 百分号编码后的字符串
|
* @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());
|
String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
|
||||||
return encode.replaceAll("\\+", "%20");
|
return encode.replaceAll("\\+", "%20");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取图像后缀
|
* 获取图像后缀
|
||||||
*
|
*
|
||||||
* @param photoByte 图像数据
|
* @param photoByte 图像数据
|
||||||
* @return 后缀名
|
* @return 后缀名
|
||||||
*/
|
*/
|
||||||
public static String getFileExtendName(byte[] photoByte)
|
public static String getFileExtendName(byte[] photoByte) {
|
||||||
{
|
|
||||||
String strFileExtendName = "jpg";
|
String strFileExtendName = "jpg";
|
||||||
if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
|
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";
|
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";
|
strFileExtendName = "jpg";
|
||||||
}
|
} else if ((photoByte[0] == 66) && (photoByte[1] == 77)) {
|
||||||
else if ((photoByte[0] == 66) && (photoByte[1] == 77))
|
|
||||||
{
|
|
||||||
strFileExtendName = "bmp";
|
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";
|
strFileExtendName = "png";
|
||||||
}
|
}
|
||||||
return strFileExtendName;
|
return strFileExtendName;
|
||||||
@ -257,14 +227,12 @@ public class FileUtils
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png
|
* 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png
|
||||||
*
|
*
|
||||||
* @param fileName 路径名称
|
* @param fileName 路径名称
|
||||||
* @return 没有文件路径的名称
|
* @return 没有文件路径的名称
|
||||||
*/
|
*/
|
||||||
public static String getName(String fileName)
|
public static String getName(String fileName) {
|
||||||
{
|
if (fileName == null) {
|
||||||
if (fileName == null)
|
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int lastUnixPos = fileName.lastIndexOf('/');
|
int lastUnixPos = fileName.lastIndexOf('/');
|
||||||
@ -275,17 +243,144 @@ public class FileUtils
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi
|
* 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi
|
||||||
*
|
*
|
||||||
* @param fileName 路径名称
|
* @param fileName 路径名称
|
||||||
* @return 没有文件路径和后缀的名称
|
* @return 没有文件路径和后缀的名称
|
||||||
*/
|
*/
|
||||||
public static String getNameNotSuffix(String fileName)
|
public static String getNameNotSuffix(String fileName) {
|
||||||
{
|
if (fileName == null) {
|
||||||
if (fileName == null)
|
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String baseName = FilenameUtils.getBaseName(fileName);
|
String baseName = FilenameUtils.getBaseName(fileName);
|
||||||
return baseName;
|
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);
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
package com.ruoyi.common.utils.file;
|
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.ByteArrayInputStream;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.util.Arrays;
|
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 地址
|
* @param url 地址
|
||||||
* @return 字节数据
|
* @return 字节数据
|
||||||
*/
|
*/
|
||||||
|
@ -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<MinioClientEntity> getSlave() {
|
||||||
|
return slave;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSlave(List<MinioClientEntity> slave) {
|
||||||
|
this.slave = slave;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MinioClientEntity master;
|
||||||
|
|
||||||
|
private List<MinioClientEntity> 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() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,80 +1,68 @@
|
|||||||
package com.ruoyi.middleware.minio.config;
|
package com.ruoyi.middleware.minio.config;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
import io.minio.MinioClient;
|
import io.minio.MinioClient;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
/**
|
import java.util.List;
|
||||||
* Minio 配置信息
|
import java.util.Map;
|
||||||
*
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
* @author ruoyi
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
*/
|
|
||||||
@Configuration
|
@Configuration("MinioConfiguration")
|
||||||
@ConfigurationProperties(prefix = "minio")
|
@ConditionalOnProperty(prefix = "minio",name = {"enable"},havingValue = "true" , matchIfMissing = false)
|
||||||
public class MinioConfig {
|
public class MinioConfig {
|
||||||
|
|
||||||
/**
|
public int maxSize;
|
||||||
* 服务地址
|
|
||||||
*/
|
|
||||||
private static String url;
|
|
||||||
|
|
||||||
/**
|
public static String prefix="/minio";
|
||||||
* 用户名
|
@Autowired
|
||||||
*/
|
private MinioClientConfig minioClientConfig;
|
||||||
private static String accessKey;
|
|
||||||
|
|
||||||
/**
|
private Map<String, MinioClientConfig.MinioClientEntity> slaveClients = new ConcurrentHashMap<>();
|
||||||
* 密码
|
|
||||||
*/
|
|
||||||
private static String secretKey;
|
|
||||||
|
|
||||||
/**
|
private List<MinioClientConfig.MinioClientEntity> slaveClientsList = new CopyOnWriteArrayList<>();
|
||||||
* 存储桶名称
|
|
||||||
*/
|
|
||||||
private static String bucketName;
|
|
||||||
|
|
||||||
public static String getUrl() {
|
private MinioClientConfig.MinioClientEntity masterClient;
|
||||||
return url;
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
System.out.println(maxSize);
|
||||||
|
List<MinioClientConfig.MinioClientEntity> collect = minioClientConfig.getSlave().stream().map(item -> {
|
||||||
|
item.setClient(MinioClient.builder().endpoint(item.getUrl()).credentials(item.getAccessKey(), item.getSecretKey()).build());
|
||||||
|
return item;
|
||||||
|
}).toList();
|
||||||
|
collect.forEach(item->{
|
||||||
|
slaveClients.put(item.getName(),item);
|
||||||
|
slaveClientsList.add(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
MinioClientConfig.MinioClientEntity master = minioClientConfig.getMaster();
|
||||||
|
master.setClient(MinioClient.builder().credentials(master.getAccessKey(),master.getSecretKey()).endpoint(master.getUrl()).build());
|
||||||
|
masterClient = master;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUrl(String url) {
|
public int getMaxSize() {
|
||||||
MinioConfig.url = url;
|
return maxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getAccessKey() {
|
private void setMaxSize(int maxSize) {
|
||||||
return accessKey;
|
this.maxSize = maxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAccessKey(String accessKey) {
|
public List<MinioClientConfig.MinioClientEntity> getSlaveClientsList() {
|
||||||
MinioConfig.accessKey = accessKey;
|
return slaveClientsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getSecretKey() {
|
public Map<String, MinioClientConfig.MinioClientEntity> getSlaveClients() {
|
||||||
return secretKey;
|
return this.slaveClients;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSecretKey(String secretKey) {
|
public MinioClientConfig.MinioClientEntity getMasterClient() {
|
||||||
MinioConfig.secretKey = secretKey;
|
return this.masterClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getBucketName() {
|
|
||||||
return bucketName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBucketName(String bucketName) {
|
|
||||||
MinioConfig.bucketName = bucketName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public MinioClient getMinioClient() {
|
|
||||||
try {
|
|
||||||
return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
|
|
||||||
} catch (Exception e) {
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,44 @@
|
|||||||
package com.ruoyi.middleware.minio.controller;
|
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.annotation.Anonymous;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.common.utils.file.FileUtils;
|
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
|
@RestController
|
||||||
@RequestMapping("/minio")
|
@RequestMapping("/minio")
|
||||||
public class MinioController {
|
public class MinioController {
|
||||||
@PostMapping("/upload")
|
|
||||||
|
|
||||||
|
@GetMapping("/{buketName}")
|
||||||
@Anonymous
|
@Anonymous
|
||||||
public AjaxResult uploadFileMinio(MultipartFile file) throws Exception {
|
public void downLoadFile(HttpServletRequest request, HttpServletResponse response,
|
||||||
try {
|
@PathVariable("buketName") String buketName,
|
||||||
// 上传并返回新文件名称
|
@RequestParam("fileName") String fileName,
|
||||||
String fileName = FileUploadMinioUtils.uploadMinio(file);
|
@RequestParam(value = "clientName", required = false) String clientName) throws Exception {
|
||||||
AjaxResult ajax = AjaxResult.success();
|
|
||||||
ajax.put("url", fileName);
|
if (!StringUtils.isEmpty(clientName)) {
|
||||||
ajax.put("fileName", fileName);
|
MinioFileVO file = MinioUtil.SlaveClient.getFile(clientName, buketName, fileName);
|
||||||
ajax.put("newFileName", FileUtils.getName(fileName));
|
Headers headers = file.getHeaders();
|
||||||
ajax.put("originalFilename", file.getOriginalFilename());
|
|
||||||
return ajax;
|
String contentType = headers.get("content-Type");
|
||||||
} catch (Exception e) {
|
response.setContentType(contentType);
|
||||||
return AjaxResult.error(e.getMessage());
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.ruoyi.middleware.minio.exception;
|
||||||
|
|
||||||
|
public class MinioClientErrorException extends RuntimeException{
|
||||||
|
public MinioClientErrorException(String msg){
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
package com.ruoyi.middleware.minio.exception;
|
||||||
|
|
||||||
|
public class MinioClientNotFundException extends RuntimeException{
|
||||||
|
}
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,66 @@
|
|||||||
|
package com.ruoyi.middleware.minio.utils;
|
||||||
|
|
||||||
|
import com.ruoyi.common.config.RuoYiConfig;
|
||||||
|
import com.ruoyi.common.utils.DateUtils;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import com.ruoyi.common.utils.file.FileUtil;
|
||||||
|
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 MinioFileUtil implements FileUtil {
|
||||||
|
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 {
|
||||||
|
String absPath = RuoYiConfig.getProfile() + File.separator + filePath;
|
||||||
|
relativePath = FileUtils.getRelativePath(absPath);
|
||||||
|
}
|
||||||
|
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, "?filePath=");
|
||||||
|
MinioFileVO file = MinioUtil.getFile(minioConfig.getMasterClient().getDefaultBuket(), filePath);
|
||||||
|
return file.getFileInputSteam();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteFile(String fileUrl) throws Exception {
|
||||||
|
String filePath = StringUtils.substringAfter(fileUrl, "?filePath=");
|
||||||
|
MinioUtil.removeFile(minioConfig.getMasterClient().getDefaultBuket(), filePath);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -1,46 +1,277 @@
|
|||||||
package com.ruoyi.middleware.minio.utils;
|
package com.ruoyi.middleware.minio.utils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import com.ruoyi.common.exception.file.FileException;
|
||||||
import java.io.InputStream;
|
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 org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
import java.io.ByteArrayOutputStream;
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import io.minio.GetPresignedObjectUrlArgs;
|
import java.util.List;
|
||||||
import io.minio.MinioClient;
|
|
||||||
import io.minio.PutObjectArgs;
|
|
||||||
import io.minio.http.Method;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
public static String uploadFile(String buketName, String filePath,
|
||||||
{
|
String contentType, InputStream inputStream)
|
||||||
String url = "";
|
throws Exception {
|
||||||
MinioClient minioClient = SpringUtils.getBean(MinioClient.class);
|
PutObjectArgs build = PutObjectArgs.builder().contentType(contentType)
|
||||||
try (InputStream inputStream = multipartFile.getInputStream())
|
.stream(inputStream, inputStream.available(), -1)
|
||||||
{
|
.bucket(buketName).object(filePath).build();
|
||||||
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(inputStream, multipartFile.getSize(), -1).contentType(multipartFile.getContentType()).build());
|
return uploadFile(build);
|
||||||
url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(fileName).method(Method.GET).build());
|
}
|
||||||
url = url.substring(0, url.indexOf('?'));
|
|
||||||
return ServletUtils.urlDecode(url);
|
/**
|
||||||
|
* 文件上传
|
||||||
|
*
|
||||||
|
* @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());
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
{
|
}
|
||||||
throw new IOException(e.getMessage(), e);
|
|
||||||
|
/**
|
||||||
|
* 文件上传(从节点递归,直到上传成功)
|
||||||
|
*
|
||||||
|
* @param index 开始递归的从节点索引
|
||||||
|
* @param putObjectArgs Minio上传文件参数
|
||||||
|
* @return 返回上传成功的文件路径
|
||||||
|
*/
|
||||||
|
private static String uploadFileIterator(int index, PutObjectArgs putObjectArgs) {
|
||||||
|
List<MinioClientConfig.MinioClientEntity> 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<Result<DeleteError>> 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<Result<DeleteError>> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user