1、文件上传功能重构

2、实现签到删除
3、实现签到表格处弹性布局
4、库存删除问题修正
This commit is contained in:
2024-12-16 08:02:05 +08:00
parent ba0d565424
commit de37820973
28 changed files with 1292 additions and 91 deletions

View File

@@ -0,0 +1,169 @@
package com.ruoyi.web.controller.common;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.framework.config.ServerConfig;
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.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
/**
* 通用请求处理
*
* @author industry
*/
@RestController
@RequestMapping("/common")
public class CommonController
{
private static final Logger log = LoggerFactory.getLogger(CommonController.class);
@Autowired
private ServerConfig serverConfig;
private static final String FILE_DELIMETER = ",";
/**
* 通用下载请求
*
* @param fileName 文件名称
* @param delete 是否删除
*/
@GetMapping("/download")
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
{
try
{
if (!FileUtils.checkAllowDownload(fileName))
{
throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
}
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
String filePath = RuoYiConfig.getDownloadPath() + fileName;
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, realFileName);
FileUtils.writeBytes(filePath, response.getOutputStream());
if (delete)
{
FileUtils.deleteFile(filePath);
}
}
catch (Exception e)
{
log.error("下载文件失败", e);
}
}
/**
* 通用上传请求(单个)
*/
@PostMapping("/upload")
public AjaxResult uploadFile(MultipartFile file) throws Exception
{
try
{
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
System.out.println(fileName);
String url = serverConfig.getUrl() + fileName;
AjaxResult ajax = AjaxResult.success();
ajax.put("url", url);
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());
}
}
/**
* 通用上传请求(多个)
*/
@PostMapping("/uploads")
public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception
{
try
{
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
List<String> urls = new ArrayList<String>();
List<String> fileNames = new ArrayList<String>();
List<String> newFileNames = new ArrayList<String>();
List<String> originalFilenames = new ArrayList<String>();
for (MultipartFile file : files)
{
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
urls.add(url);
fileNames.add(fileName);
newFileNames.add(FileUtils.getName(fileName));
originalFilenames.add(file.getOriginalFilename());
}
AjaxResult ajax = AjaxResult.success();
ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER));
ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER));
ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER));
ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER));
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
/**
* 本地资源通用下载
*/
@GetMapping("/download/resource")
public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
throws Exception
{
try
{
if (!FileUtils.checkAllowDownload(resource))
{
throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
}
// 本地资源路径
String localPath = RuoYiConfig.getProfile();
// 数据库资源地址
String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
// 下载名称
String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, downloadName);
FileUtils.writeBytes(downloadPath, response.getOutputStream());
}
catch (Exception e)
{
log.error("下载文件失败", e);
}
}
}

View File

@@ -12,6 +12,8 @@ ruoyi:
addressEnabled: true
# 缓存懒加载
cacheLazy: false
# 文件路径
profile: D:/code/java_work/fad_ad/uploadPath
captcha:
# 页面 <参数设置> 可开启关闭 验证码校验

View File

@@ -41,6 +41,10 @@ public class RuoYiConfig {
*/
private boolean cacheLazy;
/** 上传路径 */
@Getter
private static String profile = "/home/wy/oa/uploadPath";
/**
* 获取地址开关
*/
@@ -51,4 +55,37 @@ public class RuoYiConfig {
RuoYiConfig.addressEnabled = addressEnabled;
}
/**
* 获取导入上传路径
*/
public static String getImportPath()
{
return getProfile() + "/import";
}
/**
* 获取头像上传路径
*/
public static String getAvatarPath()
{
return getProfile() + "/avatar";
}
/**
* 获取下载路径
*/
public static String getDownloadPath()
{
return getProfile() + "/download/";
}
/**
* 获取上传路径
*/
public static String getUploadPath()
{
return getProfile() + "/upload";
}
}

View File

@@ -72,5 +72,11 @@ public interface Constants {
*/
String TOKEN = "token";
/**
* 资源映射路径 前缀
*/
public static final String RESOURCE_PREFIX = "/profile";
}

View File

@@ -0,0 +1,216 @@
package com.ruoyi.common.core;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.utils.StringUtils;
import java.util.HashMap;
import java.util.Objects;
/**
* 操作消息提醒
*
* @author industry
*/
public class AjaxResult extends HashMap<String, Object>
{
private static final long serialVersionUID = 1L;
/** 状态码 */
public static final String CODE_TAG = "code";
/** 返回内容 */
public static final String MSG_TAG = "msg";
/** 数据对象 */
public static final String DATA_TAG = "data";
/**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
public AjaxResult()
{
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
*/
public AjaxResult(int code, String msg)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
* @param data 数据对象
*/
public AjaxResult(int code, String msg, Object data)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
if (StringUtils.isNotNull(data))
{
super.put(DATA_TAG, data);
}
}
/**
* 返回成功消息
*
* @return 成功消息
*/
public static AjaxResult success()
{
return AjaxResult.success("操作成功");
}
/**
* 返回成功数据
*
* @return 成功消息
*/
public static AjaxResult success(Object data)
{
return AjaxResult.success("操作成功", data);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @return 成功消息
*/
public static AjaxResult success(String msg)
{
return AjaxResult.success(msg, null);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 成功消息
*/
public static AjaxResult success(String msg, Object data)
{
return new AjaxResult(HttpStatus.SUCCESS, msg, data);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult warn(String msg)
{
return AjaxResult.warn(msg, null);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static AjaxResult warn(String msg, Object data)
{
return new AjaxResult(HttpStatus.WARN, msg, data);
}
/**
* 返回错误消息
*
* @return 错误消息
*/
public static AjaxResult error()
{
return AjaxResult.error("操作失败");
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @return 错误消息
*/
public static AjaxResult error(String msg)
{
return AjaxResult.error(msg, null);
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 错误消息
*/
public static AjaxResult error(String msg, Object data)
{
return new AjaxResult(HttpStatus.ERROR, msg, data);
}
/**
* 返回错误消息
*
* @param code 状态码
* @param msg 返回内容
* @return 错误消息
*/
public static AjaxResult error(int code, String msg)
{
return new AjaxResult(code, msg, null);
}
/**
* 是否为成功消息
*
* @return 结果
*/
public boolean isSuccess()
{
return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG));
}
/**
* 是否为警告消息
*
* @return 结果
*/
public boolean isWarn()
{
return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG));
}
/**
* 是否为错误消息
*
* @return 结果
*/
public boolean isError()
{
return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG));
}
/**
* 方便链式调用
*
* @param key 键
* @param value 值
* @return 数据对象
*/
@Override
public AjaxResult put(String key, Object value)
{
super.put(key, value);
return this;
}
}

View File

@@ -0,0 +1,61 @@
package com.ruoyi.common.exception.file;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* 文件上传异常类
*
* @author industry
*/
public class FileUploadException extends Exception
{
private static final long serialVersionUID = 1L;
private final Throwable cause;
public FileUploadException()
{
this(null, null);
}
public FileUploadException(final String msg)
{
this(msg, null);
}
public FileUploadException(String msg, Throwable cause)
{
super(msg);
this.cause = cause;
}
@Override
public void printStackTrace(PrintStream stream)
{
super.printStackTrace(stream);
if (cause != null)
{
stream.println("Caused by:");
cause.printStackTrace(stream);
}
}
@Override
public void printStackTrace(PrintWriter writer)
{
super.printStackTrace(writer);
if (cause != null)
{
writer.println("Caused by:");
cause.printStackTrace(writer);
}
}
@Override
public Throwable getCause()
{
return cause;
}
}

View File

@@ -0,0 +1,81 @@
package com.ruoyi.common.exception.file;
import java.util.Arrays;
/**
* 文件上传 误异常类
*
* @author industry
*/
public class InvalidExtensionException extends FileUploadException
{
private static final long serialVersionUID = 1L;
private String[] allowedExtension;
private String extension;
private String filename;
public InvalidExtensionException(String[] allowedExtension, String extension, String filename)
{
super("文件[" + filename + "]后缀[" + extension + "]不正确,请上传" + Arrays.toString(allowedExtension) + "格式");
this.allowedExtension = allowedExtension;
this.extension = extension;
this.filename = filename;
}
public String[] getAllowedExtension()
{
return allowedExtension;
}
public String getExtension()
{
return extension;
}
public String getFilename()
{
return filename;
}
public static class InvalidImageExtensionException extends InvalidExtensionException
{
private static final long serialVersionUID = 1L;
public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename)
{
super(allowedExtension, extension, filename);
}
}
public static class InvalidFlashExtensionException extends InvalidExtensionException
{
private static final long serialVersionUID = 1L;
public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename)
{
super(allowedExtension, extension, filename);
}
}
public static class InvalidMediaExtensionException extends InvalidExtensionException
{
private static final long serialVersionUID = 1L;
public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename)
{
super(allowedExtension, extension, filename);
}
}
public static class InvalidVideoExtensionException extends InvalidExtensionException
{
private static final long serialVersionUID = 1L;
public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename)
{
super(allowedExtension, extension, filename);
}
}
}

View File

@@ -322,4 +322,28 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
.collect(Collectors.toList());
}
/**
* * 判断一个对象是否为空
*
* @param object Object
* @return true为空 false非空
*/
public static boolean isNull(Object object)
{
return object == null;
}
/**
* * 判断一个对象是否非空
*
* @param object Object
* @return true非空 false
*/
public static boolean isNotNull(Object object)
{
return !isNull(object);
}
}

View File

@@ -0,0 +1,76 @@
package com.ruoyi.common.utils.file;
import java.io.File;
import org.apache.commons.lang3.StringUtils;
/**
* 文件类型工具类
*
* @author industry
*/
public class FileTypeUtils
{
/**
* 获取文件类型
* <p>
* 例如: industry.txt, 返回: txt
*
* @param file 文件名
* @return 后缀(不含".")
*/
public static String getFileType(File file)
{
if (null == file)
{
return StringUtils.EMPTY;
}
return getFileType(file.getName());
}
/**
* 获取文件类型
* <p>
* 例如: industry.txt, 返回: txt
*
* @param fileName 文件名
* @return 后缀(不含".")
*/
public static String getFileType(String fileName)
{
int separatorIndex = fileName.lastIndexOf(".");
if (separatorIndex < 0)
{
return "";
}
return fileName.substring(separatorIndex + 1).toLowerCase();
}
/**
* 获取文件类型
*
* @param photoByte 文件字节码
* @return 后缀(不含".")
*/
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))
{
strFileExtendName = "GIF";
}
else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))
{
strFileExtendName = "JPG";
}
else if ((photoByte[0] == 66) && (photoByte[1] == 77))
{
strFileExtendName = "BMP";
}
else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))
{
strFileExtendName = "PNG";
}
return strFileExtendName;
}
}

View File

@@ -0,0 +1,233 @@
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 industry
*/
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;
}
}

View File

@@ -1,11 +1,14 @@
package com.ruoyi.common.utils.file;
import cn.hutool.core.io.FileUtil;
import com.ruoyi.common.utils.StringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@@ -49,4 +52,82 @@ public class FileUtils extends FileUtil {
String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
return encode.replaceAll("\\+", "%20");
}
/**
* 检查文件是否可下载
*
* @param resource 需要下载的文件
* @return true 正常 false 非法
*/
public static boolean checkAllowDownload(String resource)
{
// 禁止目录上跳级别
if (StringUtils.contains(resource, ".."))
{
return false;
}
// 检查允许下载的文件规则
if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))
{
return true;
}
// 不在允许下载的文件规则
return false;
}
/**
* 删除文件
*
* @param filePath 文件
* @return
*/
public static boolean deleteFile(String filePath)
{
boolean flag = false;
File file = new File(filePath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists())
{
flag = file.delete();
}
return flag;
}
/**
* 输出指定文件的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);
byte[] b = new byte[1024];
int length;
while ((length = fis.read(b)) > 0)
{
os.write(b, 0, length);
}
}
catch (IOException e)
{
throw e;
}
finally
{
IOUtils.close(os);
IOUtils.close(fis);
}
}
}

View File

@@ -37,4 +37,23 @@ public class MimeTypeUtils {
// pdf
"pdf"};
public static String getExtension(String prefix)
{
switch (prefix)
{
case IMAGE_PNG:
return "png";
case IMAGE_JPG:
return "jpg";
case IMAGE_JPEG:
return "jpeg";
case IMAGE_BMP:
return "bmp";
case IMAGE_GIF:
return "gif";
default:
return "";
}
}
}

View File

@@ -0,0 +1,87 @@
package com.ruoyi.common.utils.uuid;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author industry 序列生成类
*/
public class Seq
{
// 通用序列类型
public static final String commSeqType = "COMMON";
// 上传序列类型
public static final String uploadSeqType = "UPLOAD";
// 通用接口序列数
private static AtomicInteger commSeq = new AtomicInteger(1);
// 上传接口序列数
private static AtomicInteger uploadSeq = new AtomicInteger(1);
// 机器标识
private static final String machineCode = "A";
/**
* 获取通用序列号
*
* @return 序列值
*/
public static String getId()
{
return getId(commSeqType);
}
/**
* 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
*
* @return 序列值
*/
public static String getId(String type)
{
AtomicInteger atomicInt = commSeq;
if (uploadSeqType.equals(type))
{
atomicInt = uploadSeq;
}
return getId(atomicInt, 3);
}
/**
* 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
*
* @param atomicInt 序列数
* @param length 数值长度
* @return 序列值
*/
public static String getId(AtomicInteger atomicInt, int length)
{
String result = DateUtils.dateTimeNow();
result += machineCode;
result += getSeq(atomicInt, length);
return result;
}
/**
* 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数
*
* @return 序列值
*/
private synchronized static String getSeq(AtomicInteger atomicInt, int length)
{
// 先取值再+1
int value = atomicInt.getAndIncrement();
// 如果更新后值>=10 的 (length)幂次方则重置为1
int maxSeq = (int) Math.pow(10, length);
if (atomicInt.get() >= maxSeq)
{
atomicInt.set(1);
}
// 转字符串用0左补齐
return StringUtils.padl(value, length);
}
}

View File

@@ -0,0 +1,34 @@
package com.ruoyi.framework.config;
import javax.servlet.http.HttpServletRequest;
import com.ruoyi.common.utils.ServletUtils;
import org.springframework.stereotype.Component;
/**
* 服务相关配置
*
* @author industry
*/
@Component
public class ServerConfig
{
/**
* 获取完整的请求路径,包括:域名,端口,上下文访问路径
*
* @return 服务地址
*/
public String getUrl()
{
HttpServletRequest request = ServletUtils.getRequest();
return getDomain(request);
}
public static String getDomain(HttpServletRequest request)
{
StringBuffer url = request.getRequestURL();
String contextPath = request.getServletContext().getContextPath();
return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
}
}

View File

@@ -28,7 +28,7 @@
<!-- 文件列表 -->
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
<li :key="file.url" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
<el-link :href="`${file.url}`" :underline="false" target="_blank">
<el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank">
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
</el-link>
<div class="ele-upload-list__item-content-action">
@@ -41,7 +41,6 @@
<script>
import { getToken } from "@/utils/auth";
import { listByIds, delOss } from "@/api/system/oss";
export default {
name: "FileUpload",
@@ -56,12 +55,12 @@ export default {
// 大小限制(MB)
fileSize: {
type: Number,
default: 100,
default: 5,
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["doc", "docx", "xls","pdf","xlsx"],
default: () => ["doc", "xls", "ppt", "txt", "pdf","docx", "xlsx"],
},
// 是否显示提示
isShowTip: {
@@ -74,7 +73,7 @@ export default {
number: 0,
uploadList: [],
baseUrl: process.env.VUE_APP_BASE_API,
uploadFileUrl: process.env.VUE_APP_BASE_API + "/system/oss/upload", // 上传文件服务器地址
uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传文件服务器地址
headers: {
Authorization: "Bearer " + getToken(),
},
@@ -83,24 +82,16 @@ export default {
},
watch: {
value: {
async handler(val) {
handler(val) {
if (val) {
let temp = 1;
// 首先将值转为数组
let list;
if (Array.isArray(val)) {
list = val;
} else {
await listByIds(val).then(res => {
list = res.data.map(oss => {
oss = { name: oss.originalName, url: oss.url, ossId: oss.ossId };
return oss;
});
})
}
const list = Array.isArray(val) ? val : this.value.split(',');
// 然后将数组转为对象数组
this.fileList = list.map(item => {
item = { name: item.name, url: item.url, ossId: item.ossId };
if (typeof item === "string") {
item = { name: item, url: item };
}
item.uid = item.uid || new Date().getTime() + temp++;
return item;
});
@@ -156,7 +147,7 @@ export default {
// 上传成功回调
handleUploadSuccess(res, file) {
if (res.code === 200) {
this.uploadList.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
this.uploadList.push({ name: res.fileName, url: res.fileName });
this.uploadedSuccessfully();
} else {
this.number--;
@@ -168,8 +159,6 @@ export default {
},
// 删除文件
handleDelete(index) {
let ossId = this.fileList[index].ossId;
delOss(ossId);
this.fileList.splice(index, 1);
this.$emit("input", this.listToString(this.fileList));
},
@@ -197,11 +186,11 @@ export default {
let strs = "";
separator = separator || ",";
for (let i in list) {
strs += list[i].ossId + separator;
strs += list[i].url + separator;
}
return strs != "" ? strs.substr(0, strs.length - 1) : "";
},
},
return strs != '' ? strs.substr(0, strs.length - 1) : '';
}
}
};
</script>

View File

@@ -44,7 +44,6 @@
<script>
import { getToken } from "@/utils/auth";
import { listByIds, delOss } from "@/api/system/oss";
export default {
props: {
@@ -56,7 +55,7 @@ export default {
},
// 大小限制(MB)
fileSize: {
type: Number,
type: Number,
default: 5,
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
@@ -78,7 +77,7 @@ export default {
dialogVisible: false,
hideUpload: false,
baseUrl: process.env.VUE_APP_BASE_API,
uploadImgUrl: process.env.VUE_APP_BASE_API + "/system/oss/upload", // 上传的图片服务器地址
uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传的图片服务器地址
headers: {
Authorization: "Bearer " + getToken(),
},
@@ -87,21 +86,19 @@ export default {
},
watch: {
value: {
async handler(val) {
handler(val) {
if (val) {
// 首先将值转为数组
let list;
if (Array.isArray(val)) {
list = val;
} else {
await listByIds(val).then(res => {
list = res.data;
})
}
const list = Array.isArray(val) ? val : this.value.split(',');
// 然后将数组转为对象数组
this.fileList = list.map(item => {
// 此处name使用ossId 防止删除出现重名
item = { name: item.ossId, url: item.url, ossId: item.ossId };
if (typeof item === "string") {
if (item.indexOf(this.baseUrl) === -1) {
item = { name: this.baseUrl + item, url: this.baseUrl + item };
} else {
item = { name: item, url: item };
}
}
return item;
});
} else {
@@ -128,7 +125,7 @@ export default {
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
}
isImg = this.fileType.some((type) => {
isImg = this.fileType.some(type => {
if (file.type.indexOf(type) > -1) return true;
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
@@ -158,7 +155,7 @@ export default {
// 上传成功回调
handleUploadSuccess(res, file) {
if (res.code === 200) {
this.uploadList.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
this.uploadList.push({name: res.fileName, url: res.fileName});
this.uploadedSuccessfully();
} else {
this.number--;
@@ -171,15 +168,13 @@ export default {
// 删除图片
handleDelete(file) {
const findex = this.fileList.map(f => f.name).indexOf(file.name);
if(findex > -1) {
let ossId = this.fileList[findex].ossId;
delOss(ossId);
if (findex > -1) {
this.fileList.splice(findex, 1);
this.$emit("input", this.listToString(this.fileList));
}
},
// 上传失败
handleUploadError(res) {
handleUploadError() {
this.$modal.msgError("上传图片失败,请重试");
this.$modal.closeLoading();
},
@@ -203,11 +198,11 @@ export default {
let strs = "";
separator = separator || ",";
for (let i in list) {
if (list[i].ossId) {
strs += list[i].ossId + separator;
if (list[i].url) {
strs += list[i].url.replace(this.baseUrl, "") + separator;
}
}
return strs != "" ? strs.substr(0, strs.length - 1) : "";
return strs != '' ? strs.substr(0, strs.length - 1) : '';
}
}
};
@@ -215,12 +210,13 @@ export default {
<style scoped lang="scss">
// .el-upload--picture-card 控制加号部分
::v-deep.hide .el-upload--picture-card {
display: none;
display: none;
}
// 去掉动画效果
::v-deep .el-list-enter-active,
::v-deep .el-list-leave-active {
transition: all 0s;
transition: all 0s;
}
::v-deep .el-list-enter, .el-list-leave-active {

View File

@@ -9,8 +9,44 @@ const baseURL = process.env.VUE_APP_BASE_API
let downloadLoadingInstance;
export default {
oss(ossId) {
var url = baseURL + '/system/oss/download/' + ossId
name(name, isDelete = false) {
var url = baseURL + "/common/download?fileName=" + encodeURIComponent(name) + "&delete=" + isDelete
axios({
method: 'get',
url: url,
responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() }
}).then((res) => {
const isBlob = blobValidate(res.data);
if (isBlob) {
const blob = new Blob([res.data])
this.saveAs(blob, decodeURIComponent(res.headers['download-filename']))
} else {
this.printErrMsg(res.data);
}
})
},
resource(resource) {
console.log(resource)
var url = baseURL + "/common/download/resource?resource=" + encodeURIComponent(resource);
console.log(url)
axios({
method: 'get',
url: url,
responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() }
}).then((res) => {
const isBlob = blobValidate(res.data);
if (isBlob) {
const blob = new Blob([res.data])
this.saveAs(blob, decodeURIComponent(res.headers['download-filename']))
} else {
this.printErrMsg(res.data);
}
})
},
zip(url, name) {
var url = baseURL + url
downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
axios({
method: 'get',
@@ -20,8 +56,8 @@ export default {
}).then((res) => {
const isBlob = blobValidate(res.data);
if (isBlob) {
const blob = new Blob([res.data], { type: 'application/octet-stream' })
this.saveAs(blob, decodeURIComponent(res.headers['download-filename']))
const blob = new Blob([res.data], { type: 'application/zip' })
this.saveAs(blob, name)
} else {
this.printErrMsg(res.data);
}
@@ -32,26 +68,6 @@ export default {
downloadLoadingInstance.close();
})
},
zip(url, name) {
var url = baseURL + url
axios({
method: 'get',
url: url,
responseType: 'blob',
headers: {
'Authorization': 'Bearer ' + getToken(),
'datasource': localStorage.getItem("dataName")
}
}).then((res) => {
const isBlob = blobValidate(res.data);
if (isBlob) {
const blob = new Blob([res.data], { type: 'application/zip' })
this.saveAs(blob, name)
} else {
this.printErrMsg(res.data);
}
})
},
saveAs(text, name, opts) {
saveAs(text, name, opts);
},

View File

@@ -170,7 +170,7 @@ export default {
};
// 点击文件列表中已上传的文件时的钩子
cur['on-preview'] = (file) => {
this.$download.oss(file.ossId)
this.$download(file.ossId)
}
}
if (config.children) {

View File

@@ -574,7 +574,9 @@
<el-descriptions-item label="附件" :span="3" :labelStyle="lableBg">
<!--附件-->
<template v-if="form.accessory">
<ImageOss :name="form.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -1217,6 +1219,11 @@ export default {
this.loading = false;
});
},
/** 下载文件 */
downloadFile(filePath){
this.$download.resource(filePath)
},
// 多选框选中数据
/* handleSelectionChange(selection) {

View File

@@ -454,7 +454,9 @@
<el-descriptions-item label="附件" :span="4" :labelStyle="lableBg">
<!--附件-->
<template v-if="form.accessory">
<ImageOss :name="form.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -1335,6 +1337,11 @@ export default {
this.download('oa/finance/export', {
...this.queryParams
}, `finance_${new Date().getTime()}.xlsx`)
},
/** 下载文件 */
downloadFile(filePath){
this.$download.resource(filePath)
}
}
};

View File

@@ -422,7 +422,9 @@
<!--附件-->
<template v-if="form.accessory">
<ImageOss :name="form.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -876,6 +878,11 @@ export default {
this.loading = false;
});
},
/** 下载文件 */
downloadFile(filePath){
this.$download.resource(filePath)
},
//tabs标签
handleClick(tab, event) {
// console.log(tab, event);

View File

@@ -235,7 +235,9 @@
</template>
<!--附件-->
<template v-if="form.accessory">
<ImageOss :name="form.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -519,6 +521,11 @@ export default {
this.title = "修改合同管理";
});
},
/** 下载文件 */
downloadFile(filePath){
this.$download.resource(filePath)
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {

View File

@@ -225,7 +225,9 @@
</template>
<!--附件-->
<template v-if="form.accessory">
<ImageOss :name="form.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -585,7 +587,9 @@
</template>
<!--附件-->
<template v-if="form.accessory">
<ImageOss :name="form.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -742,6 +746,7 @@ export default {
//点击添加按钮状态
addBottomStatus: false,
openForm: false,
downLoadUrl :process.env.VUE_APP_BASE_API+'/common/download' ,
// 表单参数
form: {},
// 按钮loading
@@ -1069,6 +1074,12 @@ export default {
} else {
callback()
}
},
/** 下载文件 */
downloadFile(filePath){
this.$download.resource(filePath)
}
}
}

View File

@@ -313,7 +313,9 @@
</template>
<!--附件-->
<template v-if="form.accessory">
<ImageOss :name="form.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -634,7 +636,9 @@
</template>
<!--附件-->
<template v-if="item.accessory">
<ImageOss :name="item.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -887,7 +891,9 @@
</template>
<!--附件-->
<template v-if="contractForm.accessory">
<ImageOss :name="contractForm.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -1165,7 +1171,9 @@
</template>
<!--附件-->
<template v-if="contractForm.accessory">
<ImageOss :name="contractForm.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -1520,6 +1528,11 @@ export default {
this.queryParams.pageNum = 1;
this.getList();
},
/** 下载文件 */
downloadFile(filePath){
this.$download.resource(filePath)
},
/** 重置按钮操作 */
resetQuery() {
this.searchTime = [];

View File

@@ -156,7 +156,9 @@
<el-descriptions-item label="附件" span="4" :labelStyle="lableBg">
<!--附件-->
<template v-if="formQuery.accessory">
<ImageOss :name="formQuery.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -341,6 +343,11 @@ export default {
this.resetForm("queryForm");
this.handleQuery();
},
/** 下载文件 */
downloadFile(filePath){
this.$download.resource(filePath)
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.purposeId)

View File

@@ -146,7 +146,9 @@
</template>
<!--附件-->
<template v-if="lookRemind.accessory">
<ImageOss :name="lookRemind.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -186,7 +188,9 @@
</template>
<!--附件-->
<template v-if="form.accessory">
<ImageOss :name="form.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -470,7 +474,11 @@ export default {
this.openTask = false;
this.reset();
},
/** 下载文件 */
downloadFile(filePath){
this.$download.resource(filePath)
},
}
}

View File

@@ -151,7 +151,9 @@
<el-descriptions-item label="附件" :labelStyle="lableBg" span="4">
<!--附件-->
<template v-if="formLook.accessory">
<ImageOss :name="formLook.accessory"/>
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
</el-tooltip>
</template>
<template v-else>
<span style="color: #999999">暂无附件</span>
@@ -415,6 +417,11 @@ export default {
this.download('oa/remind/export', {
...this.queryParams
}, `remind_${new Date().getTime()}.xlsx`)
},
/** 下载文件 */
downloadFile(filePath){
this.$download.resource(filePath)
}
}
};

View File

@@ -383,7 +383,7 @@ export default {
},
/** 下载按钮操作 */
handleDownload(row) {
this.$download.oss(row.ossId)
this.$download(row.ossId)
},
/** 删除按钮操作 */
handleDelete(row) {