Browse Source

[fix] 通用模块管理

全局日期工具类增加 LocalDateTime ==> Date
全局日期工具类增加增加 LocalDate ==> Date
新增 Excel数据格式处理适配器,用于格式化: value 单元格数据值、excel注解args参数组、 cell 单元格对象、 wb 工作簿对象
修改全局文件上传工具类:修改文件上传方法、编码文件名方法、文件大小校验方法、获取文件后缀方法
新增序列生成类seq: 新增 获取通用序列号方法、默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串方法、通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串方法、序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数方法
修改通用处理字符串类型的工具类:新增 处理数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符的方法。新增:处理字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符的方法。
通用excelUtil工具类:
新增 用于dictType属性数据存储,避免重复查缓存方法
新增 当前行号
新增 标题
新增 合并后最后行数方法
新增 合并后开始行数方法
新增 对象的子列表方法方法
新增 对象的子列表属性方法
新增 需要排除列属性方法
新增 隐藏Excel中列属性方法
新增 创建excel第一行标题方法
新增 创建对象的子列表名称方法
新增 对excel表单默认第一个索引名转换成list方法(两个参数)
修改 对excel表单默认第一个索引名转换成list方法(一个参数)
修改 对excel表单指定表格索引名转换成list(三个参数)
新增 对list数据源将其里面的数据导入到excel表单(三个参数)
新增 对list数据源将其里面的数据导入到excel表单(两个参数)
新增 对list数据源将其里面的数据导入到excel表单(设置请求头参数)
新增 对list数据源将其里面的数据导入到excel表单(设置操作类型)
新增 对list数据源将其里面的数据导入到excel表单 (设置表格头)
新增 对list数据源将其里面的数据导入到excel表单(设置导入异常处理)
修改 旧版对list数据源将其里面的数据导入到excel表单方法,加入对子表的处理
修改 旧版创建写入数据到Sheet方法,加入对子表的处理
修改 旧版 填充excel数据,加入对子表的处理
修改 旧版创建表格样式,加入对子表的处理
新增 根据Excel注解创建表格头样式方法
修改 旧版根据Excel注解创建表格列样式
修改 旧版创建单元格方法,加入对子表的处理
修改 旧版设置单元格信息,加入对子表的处理
修改 旧版创建表格样式:加入:如果下拉数大于15或字符串长度大于255,则使用一个新sheet存储,避免生成的模板下拉值获取不到;提示信息或只能选择不能输入的列内容
修改 旧版添加单元格,加入对子表的处理
修改 设置 POI XSSFSheet 单元格提示或选择框方法:新增如果设置了提示信息则鼠标放上去提示;处理Excel兼容性问题
修改 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框)方法:新增 判断创建名称,可被其他单元格引用;新增 加载下拉列表内容;新增如果设置了提示信息则鼠标放上去提示;新增 设置hiddenSheet隐藏
新增 数据处理器方法,处理格式化数据
修改 旧版创建统计行方法:新增统计行的单元格位置判断
新增 得到所有定义字段方法
新增 获取字段注解信息方法:分单注解和多注解
修改 根据注解获取最大行高方法:采用新的统计方法
修改 创建一个工作簿方法,采用新的创建单元格和表头方法
新增 修改创建工作表方法,采用新的创建单元格和表头方法
新增 获取Excel2003图片方法
新增 获取Excel2007图片方法
新增 格式化不同类型的日期对象方法
新增 是否有对象的子列表方法
新增 是否有对象的子列表,集合不为空方法
新增 获取集合的值方法
新增 获取对象的子列表方法

Excel接口类:
新增 导出时在excel中每个列的高度抽象方法
新增 导出时在excel中每个列的宽度抽象方法
新增 是否需要纵向合并单元格,应对需求:含有list集合单元格)抽象方法
新增 导出类型(0数字 1字符串 2图片)抽象方法
新增 导出列头背景颜色抽象方法
新增 导出列头字体颜色抽象方法
新增 导出单元格背景颜色抽象方法
新增 导出单元格字体颜色抽象方法
新增 导出字段对齐方式抽象方法
新增 自定义数据处理器抽象方法
新增 自定义数据处理器参数抽象方法
若依全局配置类:新增 获取导入上传路径方法
dev
liuxiaoxu 1 week ago
parent
commit
49dad1f911
  1. 70
      ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
  2. 10
      ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
  3. 20
      ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
  4. 50
      ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
  5. 48
      ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java
  6. 132
      ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
  7. 24
      ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelHandlerAdapter.java
  8. 1098
      ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
  9. 87
      ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/Seq.java

70
ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java

@ -5,10 +5,13 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.math.BigDecimal;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import com.ruoyi.common.utils.poi.ExcelHandlerAdapter;
/**
* 自定义导出Excel数据注解
*
*
* @author ruoyi
*/
@Retention(RetentionPolicy.RUNTIME)
@ -56,17 +59,12 @@ public @interface Excel
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
/**
* 导出类型0数字 1字符串
*/
public ColumnType cellType() default ColumnType.STRING;
/**
* 导出时在excel中每个列的高度 单位为字符
* 导出时在excel中每个列的高度
*/
public double height() default 14;
/**
* 导出时在excel中每个列的宽 单位为字符
* 导出时在excel中每个列的宽度
*/
public double width() default 16;
@ -90,6 +88,11 @@ public @interface Excel
*/
public String[] combo() default {};
/**
* 是否需要纵向合并单元格,应对需求:含有list集合单元格)
*/
public boolean needMerge() default false;
/**
* 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
*/
@ -106,25 +109,44 @@ public @interface Excel
public boolean isStatistics() default false;
/**
* 导出字段对齐方式0默认1靠左2居中3靠右
* 导出类型0数字 1字符串 2图片
*/
Align align() default Align.AUTO;
public ColumnType cellType() default ColumnType.STRING;
public enum Align
{
AUTO(0), LEFT(1), CENTER(2), RIGHT(3);
private final int value;
/**
* 导出列头背景颜色
*/
public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
Align(int value)
{
this.value = value;
}
/**
* 导出列头字体颜色
*/
public IndexedColors headerColor() default IndexedColors.WHITE;
public int value()
{
return this.value;
}
}
/**
* 导出单元格背景颜色
*/
public IndexedColors backgroundColor() default IndexedColors.WHITE;
/**
* 导出单元格字体颜色
*/
public IndexedColors color() default IndexedColors.BLACK;
/**
* 导出字段对齐方式
*/
public HorizontalAlignment align() default HorizontalAlignment.CENTER;
/**
* 自定义数据处理器
*/
public Class<?> handler() default ExcelHandlerAdapter.class;
/**
* 自定义数据处理器参数
*/
public String[] args() default {};
/**
* 字段类型0导出导入1仅导出2仅导入
@ -149,7 +171,7 @@ public @interface Excel
public enum ColumnType
{
NUMERIC(0), STRING(1), IMAGE(2);
NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
private final int value;
ColumnType(int value)

10
ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java

@ -5,7 +5,7 @@ import org.springframework.stereotype.Component;
/**
* 全局配置类
*
*
* @author ruoyi
*/
@Component
@ -90,6 +90,14 @@ public class RuoYiConfig
RuoYiConfig.addressEnabled = addressEnabled;
}
/**
* 获取导入上传路径
*/
public static String getImportPath()
{
return getProfile() + "/import";
}
/**
* 获取头像上传路径
*/

20
ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java

@ -3,6 +3,7 @@ package com.ruoyi.common.utils;
import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.Date;
import org.apache.commons.lang3.time.DateFormatUtils;
@ -160,4 +161,23 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
// long sec = diff % nd % nh % nm / ns;
return day + "天" + hour + "小时" + min + "分钟";
}
/**
* 增加 LocalDateTime ==> Date
*/
public static Date toDate(LocalDateTime temporalAccessor)
{
ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
/**
* 增加 LocalDate ==> Date
*/
public static Date toDate(LocalDate temporalAccessor)
{
LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
}

50
ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java

@ -405,4 +405,54 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
{
return (T) obj;
}
/**
* 数字左边补齐0使之达到指定长度注意如果数字转换为字符串后长度大于size则只保留 最后size个字符
*
* @param num 数字对象
* @param size 字符串指定长度
* @return 返回数字的字符串格式该字符串为指定长度
*/
public static final String padl(final Number num, final int size)
{
return padl(num.toString(), size, '0');
}
/**
* 字符串左补齐如果原始字符串s长度大于size则只保留最后size个字符
*
* @param s 原始字符串
* @param size 字符串指定长度
* @param c 用于补齐的字符
* @return 返回指定长度的字符串由原字符串左补齐或截取得到
*/
public static final String padl(final String s, final int size, final char c)
{
final StringBuilder sb = new StringBuilder(size);
if (s != null)
{
final int len = s.length();
if (s.length() <= size)
{
for (int i = size - len; i > 0; i--)
{
sb.append(c);
}
sb.append(s);
}
else
{
return s.substring(len - size, len);
}
}
else
{
for (int i = size; i > 0; i--)
{
sb.append(c);
}
}
return sb.toString();
}
}

48
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java

@ -1,5 +1,11 @@
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;
@ -7,16 +13,11 @@ import com.ruoyi.common.exception.file.FileSizeLimitExceededException;
import com.ruoyi.common.exception.file.InvalidExtensionException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import com.ruoyi.common.utils.uuid.Seq;
/**
* 文件上传工具类
*
*
* @author ruoyi
*/
public class FileUploadUtils
@ -101,8 +102,8 @@ public class FileUploadUtils
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
InvalidExtensionException
{
int fileNamelength = file.getOriginalFilename().length();
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length();
if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
{
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
}
@ -111,10 +112,9 @@ public class FileUploadUtils
String fileName = extractFilename(file);
File desc = getAbsoluteFile(baseDir, fileName);
file.transferTo(desc);
String pathFileName = getPathFileName(baseDir, fileName);
return pathFileName;
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
file.transferTo(Paths.get(absPath));
return getPathFileName(baseDir, fileName);
}
/**
@ -122,15 +122,11 @@ public class FileUploadUtils
*/
public static final String extractFilename(MultipartFile file)
{
String fileName = file.getOriginalFilename();
fileName = file.getOriginalFilename().substring(0,fileName.lastIndexOf("."));
String extension = getExtension(file);
fileName = DateUtils.datePath() + "/" + fileName+"-"+IdUtils.fastUUID() + "." + extension;
return fileName;
return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
}
private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
{
File desc = new File(uploadDir + File.separator + fileName);
@ -144,13 +140,11 @@ public class FileUploadUtils
return desc;
}
private static final String getPathFileName(String uploadDir, String fileName) throws IOException
public static final String getPathFileName(String uploadDir, String fileName) throws IOException
{
int dirLastIndex = RuoYiConfig.getProfile().length() + 1;
String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
// String pathFileName = "/" + fileName;
String pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
return pathFileName;
return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
}
/**
@ -165,7 +159,7 @@ public class FileUploadUtils
throws FileSizeLimitExceededException, InvalidExtensionException
{
long size = file.getSize();
if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE)
if (size > DEFAULT_MAX_SIZE)
{
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
}
@ -222,7 +216,7 @@ public class FileUploadUtils
/**
* 获取文件名的后缀
*
*
* @param file 表单文件
* @return 后缀名
*/
@ -231,7 +225,7 @@ public class FileUploadUtils
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
if (StringUtils.isEmpty(extension))
{
extension = MimeTypeUtils.getExtension(file.getContentType());
extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
}
return extension;
}

132
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java

@ -3,6 +3,7 @@ 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;
@ -10,21 +11,26 @@ import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
/**
* 文件处理工具类
*
*
* @author ruoyi
*/
public class FileUtils extends org.apache.commons.io.FileUtils
public class FileUtils
{
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
/**
* 输出指定文件的byte数组
*
*
* @param filePath 文件路径
* @param os 输出流
* @return
@ -53,34 +59,53 @@ public class FileUtils extends org.apache.commons.io.FileUtils
}
finally
{
if (os != null)
{
try
{
os.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
if (fis != null)
{
try
{
fis.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
IOUtils.close(os);
IOUtils.close(fis);
}
}
/**
* 写数据到文件中
*
* @param data 数据
* @return 目标文件
* @throws IOException IO异常
*/
public static String writeImportBytes(byte[] data) throws IOException
{
return writeBytes(data, RuoYiConfig.getImportPath());
}
/**
* 写数据到文件中
*
* @param data 数据
* @param uploadDir 目标文件
* @return 目标文件
* @throws IOException IO异常
*/
public static String writeBytes(byte[] data, String uploadDir) throws IOException
{
FileOutputStream fos = null;
String pathName = "";
try
{
String extension = getFileExtendName(data);
pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName);
fos = new FileOutputStream(file);
fos.write(data);
}
finally
{
IOUtils.close(fos);
}
return FileUploadUtils.getPathFileName(uploadDir, pathName);
}
/**
* 删除文件
*
*
* @param filePath 文件
* @return
*/
@ -91,15 +116,14 @@ public class FileUtils extends org.apache.commons.io.FileUtils
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists())
{
file.delete();
flag = true;
flag = file.delete();
}
return flag;
}
/**
* 文件名称验证
*
*
* @param filename 文件名称
* @return true 正常 false 非法
*/
@ -110,7 +134,7 @@ public class FileUtils extends org.apache.commons.io.FileUtils
/**
* 检查文件是否可下载
*
*
* @param resource 需要下载的文件
* @return true 正常 false 非法
*/
@ -134,7 +158,7 @@ public class FileUtils extends org.apache.commons.io.FileUtils
/**
* 下载文件名重新编码
*
*
* @param request 请求对象
* @param fileName 文件名
* @return 编码后的文件名
@ -201,6 +225,35 @@ public class FileUtils extends org.apache.commons.io.FileUtils
return encode.replaceAll("\\+", "%20");
}
/**
* 获取图像后缀
*
* @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;
}
/**
* 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png
*
@ -218,4 +271,21 @@ public class FileUtils extends org.apache.commons.io.FileUtils
int index = Math.max(lastUnixPos, lastWindowsPos);
return fileName.substring(index + 1);
}
/**
* 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi
*
* @param fileName 路径名称
* @return 没有文件路径和后缀的名称
*/
public static String getNameNotSuffix(String fileName)
{
if (fileName == null)
{
return null;
}
String baseName = FilenameUtils.getBaseName(fileName);
return baseName;
}
}

24
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelHandlerAdapter.java

@ -0,0 +1,24 @@
package com.ruoyi.common.utils.poi;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Workbook;
/**
* Excel数据格式处理适配器
*
* @author ruoyi
*/
public interface ExcelHandlerAdapter
{
/**
* 格式化
*
* @param value 单元格数据值
* @param args excel注解args参数组
* @param cell 单元格对象
* @param wb 工作簿对象
*
* @return 处理后的值
*/
Object format(Object value, String[] args, Cell cell, Workbook wb);
}

1098
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java

File diff suppressed because it is too large

87
ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/Seq.java

@ -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 ruoyi 序列生成类
*/
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);
}
}
Loading…
Cancel
Save