destinationClass) {
+ if (sourceList == null || sourceList.isEmpty() || destinationClass == null) {
+ return Collections.emptyList();
+ }
+ return sourceList.parallelStream()
+ .filter(Objects::nonNull)
+ .map(source -> toBean(source, destinationClass)).collect(Collectors.toList());
+ }
}
diff --git a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/bean/BeanValidators.java b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/bean/BeanValidators.java
index 9d67f77..f5bf375 100644
--- a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/bean/BeanValidators.java
+++ b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/bean/BeanValidators.java
@@ -1,9 +1,9 @@
package com.tcctyn.common.core.utils.bean;
-import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
+import java.util.Set;
/**
* bean对象属性验证
diff --git a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/FileTypeUtils.java b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/FileTypeUtils.java
index 24291b4..e77a6c3 100644
--- a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/FileTypeUtils.java
+++ b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/FileTypeUtils.java
@@ -1,11 +1,12 @@
package com.tcctyn.common.core.utils.file;
-import java.io.File;
-import java.util.Objects;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;
+import java.io.File;
+import java.util.Objects;
+
/**
* 文件类型工具类
*
@@ -17,7 +18,7 @@ public class FileTypeUtils
* 获取文件类型
*
* 例如: tcctyn.txt, 返回: txt
- *
+ *
* @param file 文件名
* @return 后缀(不含".")
*/
@@ -50,7 +51,7 @@ public class FileTypeUtils
/**
* 获取文件名的后缀
- *
+ *
* @param file 表单文件
* @return 后缀名
*/
@@ -66,7 +67,7 @@ public class FileTypeUtils
/**
* 获取文件类型
- *
+ *
* @param photoByte 文件字节码
* @return 后缀(不含".")
*/
diff --git a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/FileUploadUtils.java b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/FileUploadUtils.java
new file mode 100644
index 0000000..cc98007
--- /dev/null
+++ b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/FileUploadUtils.java
@@ -0,0 +1,233 @@
+package com.tcctyn.common.core.utils.file;
+
+import com.tcctyn.common.core.config.TcctynConfig;
+import com.tcctyn.common.core.constant.Constants;
+import com.tcctyn.common.core.exception.file.FileNameLengthLimitExceededException;
+import com.tcctyn.common.core.exception.file.FileSizeLimitExceededException;
+import com.tcctyn.common.core.exception.file.InvalidExtensionException;
+import com.tcctyn.common.core.utils.DateUtils;
+import com.tcctyn.common.core.utils.StringUtils;
+import com.tcctyn.common.core.utils.uuid.Seq;
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.Objects;
+
+/**
+ * 文件上传工具类
+ *
+ * @author tcctyn
+ */
+public class FileUploadUtils
+{
+ /**
+ * 默认大小 50M
+ */
+ public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024L;
+
+ /**
+ * 默认的文件名最大长度 100
+ */
+ public static final int DEFAULT_FILE_NAME_LENGTH = 100;
+
+ /**
+ * 默认上传的地址
+ */
+ private static String defaultBaseDir = TcctynConfig.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 = TcctynConfig.getProfile().length() + 1;
+ String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
+ return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
+ }
+
+ /**
+ * 文件大小校验
+ *
+ * @param file 上传的文件
+ * @return
+ * @throws FileSizeLimitExceededException 如果超出最大大小
+ * @throws InvalidExtensionException
+ */
+ public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
+ throws FileSizeLimitExceededException, InvalidExtensionException
+ {
+ long size = file.getSize();
+ if (size > DEFAULT_MAX_SIZE)
+ {
+ throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
+ }
+
+ String fileName = file.getOriginalFilename();
+ String extension = getExtension(file);
+ if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
+ {
+ if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
+ {
+ throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
+ fileName);
+ }
+ else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
+ {
+ throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
+ fileName);
+ }
+ else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
+ {
+ throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
+ fileName);
+ }
+ else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
+ {
+ throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
+ fileName);
+ }
+ else
+ {
+ throw new InvalidExtensionException(allowedExtension, extension, fileName);
+ }
+ }
+ }
+
+ /**
+ * 判断MIME类型是否是允许的MIME类型
+ *
+ * @param extension
+ * @param allowedExtension
+ * @return
+ */
+ public static final boolean isAllowedExtension(String extension, String[] allowedExtension)
+ {
+ for (String str : allowedExtension)
+ {
+ if (str.equalsIgnoreCase(extension))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 获取文件名的后缀
+ *
+ * @param file 表单文件
+ * @return 后缀名
+ */
+ public static final String getExtension(MultipartFile file)
+ {
+ String extension = FilenameUtils.getExtension(file.getOriginalFilename());
+ if (StringUtils.isEmpty(extension))
+ {
+ extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
+ }
+ return extension;
+ }
+}
diff --git a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/FileUtils.java b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/FileUtils.java
index 6680230..f73ce16 100644
--- a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/FileUtils.java
+++ b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/FileUtils.java
@@ -1,17 +1,18 @@
package com.tcctyn.common.core.utils.file;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
+import com.tcctyn.common.core.config.TcctynConfig;
+import com.tcctyn.common.core.utils.DateUtils;
+import com.tcctyn.common.core.utils.StringUtils;
+import com.tcctyn.common.core.utils.uuid.IdUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.ArrayUtils;
+
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.lang3.ArrayUtils;
-import com.tcctyn.common.core.utils.StringUtils;
+import java.io.*;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
/**
* 文件处理工具类
@@ -20,12 +21,6 @@ import com.tcctyn.common.core.utils.StringUtils;
*/
public class FileUtils
{
- /** 字符常量:斜杠 {@code '/'} */
- public static final char SLASH = '/';
-
- /** 字符常量:反斜杠 {@code '\\'} */
- public static final char BACKSLASH = '\\';
-
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
/**
@@ -59,31 +54,50 @@ public class 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, TcctynConfig.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);
+ }
+
/**
* 删除文件
*
@@ -126,8 +140,15 @@ public class FileUtils
{
return false;
}
- // 判断是否在允许下载的文件规则内
- return ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource));
+
+ // 检查允许下载的文件规则
+ if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))
+ {
+ return true;
+ }
+
+ // 不在允许下载的文件规则
+ return false;
}
/**
@@ -165,63 +186,11 @@ public class FileUtils
return filename;
}
- /**
- * 返回文件名
- *
- * @param filePath 文件
- * @return 文件名
- */
- public static String getName(String filePath)
- {
- if (null == filePath)
- {
- return null;
- }
- int len = filePath.length();
- if (0 == len)
- {
- return filePath;
- }
- if (isFileSeparator(filePath.charAt(len - 1)))
- {
- // 以分隔符结尾的去掉结尾分隔符
- len--;
- }
-
- int begin = 0;
- char c;
- for (int i = len - 1; i > -1; i--)
- {
- c = filePath.charAt(i);
- if (isFileSeparator(c))
- {
- // 查找最后一个路径分隔符(/或者\)
- begin = i + 1;
- break;
- }
- }
-
- return filePath.substring(begin, len);
- }
-
- /**
- * 是否为Windows或者Linux(Unix)文件分隔符
- * Windows平台下分隔符为\,Linux(Unix)为/
- *
- * @param c 字符
- * @return 是否为Windows或者Linux(Unix)文件分隔符
- */
- public static boolean isFileSeparator(char c)
- {
- return SLASH == c || BACKSLASH == c;
- }
-
/**
* 下载文件名重新编码
*
* @param response 响应对象
* @param realFileName 真实文件名
- * @return
*/
public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException
{
@@ -235,6 +204,7 @@ public class FileUtils
.append("utf-8''")
.append(percentEncodedFileName);
+ response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
response.setHeader("Content-disposition", contentDispositionValue.toString());
response.setHeader("download-filename", percentEncodedFileName);
}
@@ -250,4 +220,67 @@ public class FileUtils
String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
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/tcctyn.png -- tcctyn.png
+ *
+ * @param fileName 路径名称
+ * @return 没有文件路径的名称
+ */
+ public static String getName(String fileName)
+ {
+ if (fileName == null)
+ {
+ return null;
+ }
+ int lastUnixPos = fileName.lastIndexOf('/');
+ int lastWindowsPos = fileName.lastIndexOf('\\');
+ int index = Math.max(lastUnixPos, lastWindowsPos);
+ return fileName.substring(index + 1);
+ }
+
+ /**
+ * 获取不带后缀文件名称 /profile/upload/2022/04/16/tcctyn.png -- tcctyn
+ *
+ * @param fileName 路径名称
+ * @return 没有文件路径和后缀的名称
+ */
+ public static String getNameNotSuffix(String fileName)
+ {
+ if (fileName == null)
+ {
+ return null;
+ }
+ String baseName = FilenameUtils.getBaseName(fileName);
+ return baseName;
+ }
}
diff --git a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/ImageUtils.java b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/ImageUtils.java
index 3a76190..dd573e3 100644
--- a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/ImageUtils.java
+++ b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/ImageUtils.java
@@ -1,13 +1,18 @@
package com.tcctyn.common.core.utils.file;
+import com.tcctyn.common.core.config.TcctynConfig;
+import com.tcctyn.common.core.constant.Constants;
+import com.tcctyn.common.core.utils.StringUtils;
+import org.apache.poi.util.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
-import org.apache.poi.util.IOUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* 图片处理工具类
@@ -62,18 +67,28 @@ public class ImageUtils
InputStream in = null;
try
{
- // 网络地址
- URL urlObj = new URL(url);
- URLConnection urlConnection = urlObj.openConnection();
- urlConnection.setConnectTimeout(30 * 1000);
- urlConnection.setReadTimeout(60 * 1000);
- urlConnection.setDoInput(true);
- in = urlConnection.getInputStream();
+ if (url.startsWith("http"))
+ {
+ // 网络地址
+ URL urlObj = new URL(url);
+ URLConnection urlConnection = urlObj.openConnection();
+ urlConnection.setConnectTimeout(30 * 1000);
+ urlConnection.setReadTimeout(60 * 1000);
+ urlConnection.setDoInput(true);
+ in = urlConnection.getInputStream();
+ }
+ else
+ {
+ // 本机地址
+ String localPath = TcctynConfig.getProfile();
+ String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX);
+ in = new FileInputStream(downloadPath);
+ }
return IOUtils.toByteArray(in);
}
catch (Exception e)
{
- log.error("访问文件异常 {}", e);
+ log.error("获取文件路径异常 {}", e);
return null;
}
finally
diff --git a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/MimeTypeUtils.java b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/MimeTypeUtils.java
index 1d8ee8b..2fbc30c 100644
--- a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/MimeTypeUtils.java
+++ b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/file/MimeTypeUtils.java
@@ -16,7 +16,7 @@ public class MimeTypeUtils
public static final String IMAGE_BMP = "image/bmp";
public static final String IMAGE_GIF = "image/gif";
-
+
public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" };
public static final String[] FLASH_EXTENSION = { "swf", "flv" };
diff --git a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/html/HTMLFilter.java b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/html/HTMLFilter.java
index 8bc8cd9..b732b85 100644
--- a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/html/HTMLFilter.java
+++ b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/html/HTMLFilter.java
@@ -1,10 +1,6 @@
package com.tcctyn.common.core.utils.html;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
diff --git a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/http/HttpHelper.java b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/http/HttpHelper.java
new file mode 100644
index 0000000..52645a3
--- /dev/null
+++ b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/http/HttpHelper.java
@@ -0,0 +1,56 @@
+package com.tcctyn.common.core.utils.http;
+
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 通用http工具封装
+ *
+ * @author tcctyn
+ */
+public class HttpHelper
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(HttpHelper.class);
+
+ public static String getBodyString(ServletRequest request)
+ {
+ StringBuilder sb = new StringBuilder();
+ BufferedReader reader = null;
+ try (InputStream inputStream = request.getInputStream())
+ {
+ reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+ String line = "";
+ while ((line = reader.readLine()) != null)
+ {
+ sb.append(line);
+ }
+ }
+ catch (IOException e)
+ {
+ LOGGER.warn("getBodyString出现问题!");
+ }
+ finally
+ {
+ if (reader != null)
+ {
+ try
+ {
+ reader.close();
+ }
+ catch (IOException e)
+ {
+ LOGGER.error(ExceptionUtils.getMessage(e));
+ }
+ }
+ }
+ return sb.toString();
+ }
+}
diff --git a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/http/HttpUtils.java b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/http/HttpUtils.java
new file mode 100644
index 0000000..be8a3e1
--- /dev/null
+++ b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/http/HttpUtils.java
@@ -0,0 +1,266 @@
+package com.tcctyn.common.core.utils.http;
+
+import com.tcctyn.common.core.constant.Constants;
+import com.tcctyn.common.core.utils.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.*;
+import java.io.*;
+import java.net.ConnectException;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.X509Certificate;
+
+/**
+ * 通用http发送方法
+ *
+ * @author tcctyn
+ */
+public class HttpUtils
+{
+ private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
+
+ /**
+ * 向指定 URL 发送GET方法的请求
+ *
+ * @param url 发送请求的 URL
+ * @return 所代表远程资源的响应结果
+ */
+ public static String sendGet(String url)
+ {
+ return sendGet(url, StringUtils.EMPTY);
+ }
+
+ /**
+ * 向指定 URL 发送GET方法的请求
+ *
+ * @param url 发送请求的 URL
+ * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+ * @return 所代表远程资源的响应结果
+ */
+ public static String sendGet(String url, String param)
+ {
+ return sendGet(url, param, Constants.UTF8);
+ }
+
+ /**
+ * 向指定 URL 发送GET方法的请求
+ *
+ * @param url 发送请求的 URL
+ * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+ * @param contentType 编码类型
+ * @return 所代表远程资源的响应结果
+ */
+ public static String sendGet(String url, String param, String contentType)
+ {
+ StringBuilder result = new StringBuilder();
+ BufferedReader in = null;
+ try
+ {
+ String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
+ log.info("sendGet - {}", urlNameString);
+ URL realUrl = new URL(urlNameString);
+ URLConnection connection = realUrl.openConnection();
+ connection.setRequestProperty("accept", "*/*");
+ connection.setRequestProperty("connection", "Keep-Alive");
+ connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
+ connection.connect();
+ in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
+ String line;
+ while ((line = in.readLine()) != null)
+ {
+ result.append(line);
+ }
+ log.info("recv - {}", result);
+ }
+ catch (ConnectException e)
+ {
+ log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
+ }
+ catch (SocketTimeoutException e)
+ {
+ log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
+ }
+ catch (IOException e)
+ {
+ log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
+ }
+ catch (Exception e)
+ {
+ log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
+ }
+ finally
+ {
+ try
+ {
+ if (in != null)
+ {
+ in.close();
+ }
+ }
+ catch (Exception ex)
+ {
+ log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
+ }
+ }
+ return result.toString();
+ }
+
+ /**
+ * 向指定 URL 发送POST方法的请求
+ *
+ * @param url 发送请求的 URL
+ * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+ * @return 所代表远程资源的响应结果
+ */
+ public static String sendPost(String url, String param)
+ {
+ PrintWriter out = null;
+ BufferedReader in = null;
+ StringBuilder result = new StringBuilder();
+ try
+ {
+ log.info("sendPost - {}", url);
+ URL realUrl = new URL(url);
+ URLConnection conn = realUrl.openConnection();
+ conn.setRequestProperty("accept", "*/*");
+ conn.setRequestProperty("connection", "Keep-Alive");
+ conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
+ conn.setRequestProperty("Accept-Charset", "utf-8");
+ conn.setRequestProperty("contentType", "utf-8");
+ conn.setDoOutput(true);
+ conn.setDoInput(true);
+ out = new PrintWriter(conn.getOutputStream());
+ out.print(param);
+ out.flush();
+ in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
+ String line;
+ while ((line = in.readLine()) != null)
+ {
+ result.append(line);
+ }
+ log.info("recv - {}", result);
+ }
+ catch (ConnectException e)
+ {
+ log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
+ }
+ catch (SocketTimeoutException e)
+ {
+ log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
+ }
+ catch (IOException e)
+ {
+ log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
+ }
+ catch (Exception e)
+ {
+ log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
+ }
+ finally
+ {
+ try
+ {
+ if (out != null)
+ {
+ out.close();
+ }
+ if (in != null)
+ {
+ in.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
+ }
+ }
+ return result.toString();
+ }
+
+ public static String sendSSLPost(String url, String param)
+ {
+ StringBuilder result = new StringBuilder();
+ String urlNameString = url + "?" + param;
+ try
+ {
+ log.info("sendSSLPost - {}", urlNameString);
+ SSLContext sc = SSLContext.getInstance("SSL");
+ sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
+ URL console = new URL(urlNameString);
+ HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
+ conn.setRequestProperty("accept", "*/*");
+ conn.setRequestProperty("connection", "Keep-Alive");
+ conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
+ conn.setRequestProperty("Accept-Charset", "utf-8");
+ conn.setRequestProperty("contentType", "utf-8");
+ conn.setDoOutput(true);
+ conn.setDoInput(true);
+
+ conn.setSSLSocketFactory(sc.getSocketFactory());
+ conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
+ conn.connect();
+ InputStream is = conn.getInputStream();
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ String ret = "";
+ while ((ret = br.readLine()) != null)
+ {
+ if (ret != null && !"".equals(ret.trim()))
+ {
+ result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
+ }
+ }
+ log.info("recv - {}", result);
+ conn.disconnect();
+ br.close();
+ }
+ catch (ConnectException e)
+ {
+ log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
+ }
+ catch (SocketTimeoutException e)
+ {
+ log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
+ }
+ catch (IOException e)
+ {
+ log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
+ }
+ catch (Exception e)
+ {
+ log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
+ }
+ return result.toString();
+ }
+
+ private static class TrustAnyTrustManager implements X509TrustManager
+ {
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ {
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ {
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers()
+ {
+ return new X509Certificate[] {};
+ }
+ }
+
+ private static class TrustAnyHostnameVerifier implements HostnameVerifier
+ {
+ @Override
+ public boolean verify(String hostname, SSLSession session)
+ {
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/ip/AddressUtils.java b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/ip/AddressUtils.java
new file mode 100644
index 0000000..5b08036
--- /dev/null
+++ b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/ip/AddressUtils.java
@@ -0,0 +1,56 @@
+package com.tcctyn.common.core.utils.ip;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.tcctyn.common.core.config.TcctynConfig;
+import com.tcctyn.common.core.constant.Constants;
+import com.tcctyn.common.core.utils.StringUtils;
+import com.tcctyn.common.core.utils.http.HttpUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 获取地址类
+ *
+ * @author tcctyn
+ */
+public class AddressUtils
+{
+ private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);
+
+ // IP地址查询
+ public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
+
+ // 未知地址
+ public static final String UNKNOWN = "XX XX";
+
+ public static String getRealAddressByIP(String ip)
+ {
+ // 内网不查询
+ if (IpUtils.internalIp(ip))
+ {
+ return "内网IP";
+ }
+ if (TcctynConfig.isAddressEnabled())
+ {
+ try
+ {
+ String rspStr = HttpUtils.sendGet(IP_URL, "ip=" + ip + "&json=true", Constants.GBK);
+ if (StringUtils.isEmpty(rspStr))
+ {
+ log.error("获取地理位置异常 {}", ip);
+ return UNKNOWN;
+ }
+ JSONObject obj = JSON.parseObject(rspStr);
+ String region = obj.getString("pro");
+ String city = obj.getString("city");
+ return String.format("%s %s", region, city);
+ }
+ catch (Exception e)
+ {
+ log.error("获取地理位置异常 {}", ip);
+ }
+ }
+ return UNKNOWN;
+ }
+}
diff --git a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/ip/IpUtils.java b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/ip/IpUtils.java
index 74a31ca..4fcfdfc 100644
--- a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/ip/IpUtils.java
+++ b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/ip/IpUtils.java
@@ -1,11 +1,12 @@
package com.tcctyn.common.core.utils.ip;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import javax.servlet.http.HttpServletRequest;
import com.tcctyn.common.core.utils.ServletUtils;
import com.tcctyn.common.core.utils.StringUtils;
+import javax.servlet.http.HttpServletRequest;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
/**
* 获取IP方法
*
diff --git a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/mqtt/JavaDemoMQTTV3.java b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/mqtt/JavaDemoMQTTV3.java
new file mode 100644
index 0000000..7d313eb
--- /dev/null
+++ b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/mqtt/JavaDemoMQTTV3.java
@@ -0,0 +1,51 @@
+package com.tcctyn.common.core.utils.mqtt;
+
+public class JavaDemoMQTTV3 {
+
+ public static void main(String[] args) {
+ String broker = "tcp://47.109.202.121:1883";
+ String clientId = "hqyjDemo";
+ String topic = "topic/hqyj";
+ int subQos = 1;
+ int pubQos = 1;
+ String msg = "Hello MQTT";
+
+
+
+// try {
+// MqttClient client = new MqttClient(broker, clientId);
+// MqttConnectOptions options = new MqttConnectOptions();
+// client.connect(options);
+//
+// if (client.isConnected()) {
+// client.setCallback(new MqttCallback() {
+// public void messageArrived(String topic, MqttMessage message) throws Exception {
+// System.out.println("topic: " + topic);
+// System.out.println("qos: " + message.getQos());
+// System.out.println("message content: " + new String(message.getPayload()));
+// }
+//
+// public void connectionLost(Throwable cause) {
+// System.out.println("connectionLost: " + cause.getMessage());
+// }
+//
+// public void deliveryComplete(IMqttDeliveryToken token) {
+// System.out.println("deliveryComplete: " + token.isComplete());
+// }
+// });
+//
+// client.subscribe(topic, subQos);
+//
+// MqttMessage message = new MqttMessage(msg.getBytes());
+// message.setQos(pubQos);
+// client.publish(topic, message);
+// }
+//
+// client.disconnect();
+// client.close();
+//
+// } catch (MqttException e) {
+// e.printStackTrace();
+// }
+ }
+}
diff --git a/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/mqtt/MqttConfig.java b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/mqtt/MqttConfig.java
new file mode 100644
index 0000000..14c6b4e
--- /dev/null
+++ b/tcctyn-common/tcctyn-common-core/src/main/java/com/tcctyn/common/core/utils/mqtt/MqttConfig.java
@@ -0,0 +1,63 @@
+package com.tcctyn.common.core.utils.mqtt;
+
+import com.tcctyn.common.core.utils.StringUtils;
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties("spring.mqtt")
+@Data
+public class MqttConfig {
+
+ @Autowired
+ private MqttPushClient mqttPushClient;
+
+ /**
+ * 用户名
+ */
+ private String username;
+ /**
+ * 密码
+ */
+ private String password;
+ /**
+ * 连接地址
+ */
+ private String hostUrl;
+ /**
+ * 客户Id
+ */
+ private String clientId;
+ /**
+ * 默认连接话题
+ */
+ private String defaultTopic;
+ /**
+ * 超时时间
+ */
+ private int timeout;
+ /**
+ * 保持连接数
+ */
+ private int keepalive;
+ /**
+ * mqtt功能使能
+ */
+ private boolean enabled;
+
+ @Bean
+ public MqttPushClient getMqttPushClient() {
+ if(enabled == true){
+ String mqtt_topic[] = StringUtils.split(defaultTopic, ",");
+ mqttPushClient.connect(hostUrl, clientId, username, password, timeout, keepalive);//连接
+ for(int i=0; i
@@ -77,6 +55,11 @@ public class ExcelUtil
public static final String[] FORMULA_STR = { "=", "-", "+", "@" };
+ /**
+ * 用于dictType属性数据存储,避免重复查缓存
+ */
+ public Map sysDictMap = new HashMap();
+
/**
* Excel sheet最大行数,默认65536
*/
@@ -167,11 +150,6 @@ public class ExcelUtil
*/
public Class clazz;
- /**
- * 需要显示列属性
- */
- public String[] includeFields;
-
/**
* 需要排除列属性
*/
@@ -182,20 +160,11 @@ public class ExcelUtil
this.clazz = clazz;
}
- /**
- * 仅在Excel中显示列属性
- *
- * @param fields 列属性名 示例[单个"name"/多个"id","name"]
- */
- public void showColumn(String... fields)
- {
- this.includeFields = fields;
- }
-
/**
* 隐藏Excel中列属性
*
* @param fields 列属性名 示例[单个"name"/多个"id","name"]
+ * @throws Exception
*/
public void hideColumn(String... fields)
{
@@ -225,6 +194,8 @@ public class ExcelUtil
{
if (StringUtils.isNotEmpty(title))
{
+ subMergedFirstRowNum++;
+ subMergedLastRowNum++;
int titleLastCol = this.fields.size() - 1;
if (isSubList())
{
@@ -235,7 +206,7 @@ public class ExcelUtil
Cell titleCell = titleRow.createCell(0);
titleCell.setCellStyle(styles.get("title"));
titleCell.setCellValue(title);
- sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), 0, titleLastCol));
+ sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), titleLastCol));
}
}
@@ -246,31 +217,23 @@ public class ExcelUtil
{
if (isSubList())
{
+ subMergedFirstRowNum++;
+ subMergedLastRowNum++;
Row subRow = sheet.createRow(rownum);
- int column = 0;
- int subFieldSize = subFields != null ? subFields.size() : 0;
+ int excelNum = 0;
for (Object[] objects : fields)
{
- Field field = (Field) objects[0];
Excel attr = (Excel) objects[1];
- if (Collection.class.isAssignableFrom(field.getType()))
- {
- Cell cell = subRow.createCell(column);
- cell.setCellValue(attr.name());
- cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
- if (subFieldSize > 1)
- {
- CellRangeAddress cellAddress = new CellRangeAddress(rownum, rownum, column, column + subFieldSize - 1);
- sheet.addMergedRegion(cellAddress);
- }
- column += subFieldSize;
- }
- else
- {
- Cell cell = subRow.createCell(column++);
- cell.setCellValue(attr.name());
- cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
- }
+ Cell headCell1 = subRow.createCell(excelNum);
+ headCell1.setCellValue(attr.name());
+ headCell1.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
+ excelNum++;
+ }
+ int headFirstRow = excelNum - 1;
+ int headLastRow = headFirstRow + subFields.size() - 1;
+ if (headLastRow > headFirstRow)
+ {
+ sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, headFirstRow, headLastRow));
}
rownum++;
}
@@ -283,23 +246,11 @@ public class ExcelUtil
* @return 转换后集合
*/
public List importExcel(InputStream is)
- {
- return importExcel(is, 0);
- }
-
- /**
- * 对excel表单默认第一个索引名转换成list
- *
- * @param is 输入流
- * @param titleNum 标题占用行数
- * @return 转换后集合
- */
- public List importExcel(InputStream is, int titleNum)
{
List list = null;
try
{
- list = importExcel(StringUtils.EMPTY, is, titleNum);
+ list = importExcel(is, 0);
}
catch (Exception e)
{
@@ -313,6 +264,18 @@ public class ExcelUtil
return list;
}
+ /**
+ * 对excel表单默认第一个索引名转换成list
+ *
+ * @param is 输入流
+ * @param titleNum 标题占用行数
+ * @return 转换后集合
+ */
+ public List importExcel(InputStream is, int titleNum) throws Exception
+ {
+ return importExcel(StringUtils.EMPTY, is, titleNum);
+ }
+
/**
* 对excel表单指定表格索引名转换成list
*
@@ -332,7 +295,16 @@ public class ExcelUtil
{
throw new IOException("文件sheet不存在");
}
-
+ boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook);
+ Map pictures;
+ if (isXSSFWorkbook)
+ {
+ pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb);
+ }
+ else
+ {
+ pictures = getSheetPictures03((HSSFSheet) sheet, (HSSFWorkbook) wb);
+ }
// 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1
int rows = sheet.getLastRowNum();
if (rows > 0)
@@ -390,7 +362,7 @@ public class ExcelUtil
if (String.class == fieldType)
{
String s = Convert.toStr(val);
- if (s.matches("^\\d+\\.0$"))
+ if (StringUtils.endsWith(s, ".0"))
{
val = StringUtils.substringBefore(s, ".0");
}
@@ -453,10 +425,32 @@ public class ExcelUtil
{
val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
}
+ else if (StringUtils.isNotEmpty(attr.dictType()))
+ {
+ if (!sysDictMap.containsKey(attr.dictType() + val))
+ {
+ String dictValue = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());
+ sysDictMap.put(attr.dictType() + val, dictValue);
+ }
+ val = sysDictMap.get(attr.dictType() + val);
+ }
else if (!attr.handler().equals(ExcelHandlerAdapter.class))
{
val = dataFormatHandlerAdapter(val, attr, null);
}
+ else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures))
+ {
+ PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey());
+ if (image == null)
+ {
+ val = "";
+ }
+ else
+ {
+ byte[] data = image.getData();
+ val = FileUtils.writeImportBytes(data);
+ }
+ }
ReflectUtils.invokeSetter(entity, propertyName, val);
}
}
@@ -468,7 +462,33 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
+ * @param list 导出数据集合
+ * @param sheetName 工作表的名称
+ * @return 结果
+ */
+ public AjaxResult exportExcel(List list, String sheetName)
+ {
+ return exportExcel(list, sheetName, StringUtils.EMPTY);
+ }
+
+ /**
+ * 对list数据源将其里面的数据导入到excel表单
+ *
+ * @param list 导出数据集合
+ * @param sheetName 工作表的名称
+ * @param title 标题
+ * @return 结果
+ */
+ public AjaxResult exportExcel(List list, String sheetName, String title)
+ {
+ this.init(list, sheetName, title, Type.EXPORT);
+ return exportExcel();
+ }
+
+ /**
+ * 对list数据源将其里面的数据导入到excel表单
+ *
* @param response 返回数据
* @param list 导出数据集合
* @param sheetName 工作表的名称
@@ -481,7 +501,7 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
* @param response 返回数据
* @param list 导出数据集合
* @param sheetName 工作表的名称
@@ -498,7 +518,31 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
+ * @param sheetName 工作表的名称
+ * @return 结果
+ */
+ public AjaxResult importTemplateExcel(String sheetName)
+ {
+ return importTemplateExcel(sheetName, StringUtils.EMPTY);
+ }
+
+ /**
+ * 对list数据源将其里面的数据导入到excel表单
+ *
+ * @param sheetName 工作表的名称
+ * @param title 标题
+ * @return 结果
+ */
+ public AjaxResult importTemplateExcel(String sheetName, String title)
+ {
+ this.init(null, sheetName, title, Type.IMPORT);
+ return exportExcel();
+ }
+
+ /**
+ * 对list数据源将其里面的数据导入到excel表单
+ *
* @param sheetName 工作表的名称
* @return 结果
*/
@@ -509,7 +553,7 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
* @param sheetName 工作表的名称
* @param title 标题
* @return 结果
@@ -544,6 +588,34 @@ public class ExcelUtil
}
}
+ /**
+ * 对list数据源将其里面的数据导入到excel表单
+ *
+ * @return 结果
+ */
+ public AjaxResult exportExcel()
+ {
+ OutputStream out = null;
+ try
+ {
+ writeSheet();
+ String filename = encodingFilename(sheetName);
+ out = new FileOutputStream(getAbsoluteFile(filename));
+ wb.write(out);
+ return AjaxResult.success(filename);
+ }
+ catch (Exception e)
+ {
+ log.error("导出Excel异常{}", e.getMessage());
+ throw new UtilException("导出Excel失败,请联系网站管理员!");
+ }
+ finally
+ {
+ IOUtils.closeQuietly(wb);
+ IOUtils.closeQuietly(out);
+ }
+ }
+
/**
* 创建写入数据到Sheet
*/
@@ -595,91 +667,64 @@ public class ExcelUtil
{
int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size());
- int currentRowNum = rownum + 1; // 从标题行后开始
-
+ int rowNo = (1 + rownum) - startNo;
for (int i = startNo; i < endNo; i++)
{
- row = sheet.createRow(currentRowNum);
+ rowNo = isSubList() ? (i > 1 ? rowNo + 1 : rowNo + i) : i + 1 + rownum - startNo;
+ row = sheet.createRow(rowNo);
+ // 得到导出对象.
T vo = (T) list.get(i);
+ Collection> subList = null;
+ if (isSubList())
+ {
+ if (isSubListValue(vo))
+ {
+ subList = getListCellValue(vo);
+ subMergedLastRowNum = subMergedLastRowNum + subList.size();
+ }
+ else
+ {
+ subMergedFirstRowNum++;
+ subMergedLastRowNum++;
+ }
+ }
int column = 0;
- int maxSubListSize = getCurrentMaxSubListSize(vo);
for (Object[] os : fields)
{
Field field = (Field) os[0];
Excel excel = (Excel) os[1];
- if (Collection.class.isAssignableFrom(field.getType()))
+ if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList))
{
- try
+ boolean subFirst = false;
+ for (Object obj : subList)
{
- Collection> subList = (Collection>) getTargetValue(vo, field, excel);
- if (subList != null && !subList.isEmpty())
+ if (subFirst)
{
- int subIndex = 0;
- for (Object subVo : subList)
- {
- Row subRow = sheet.getRow(currentRowNum + subIndex);
- if (subRow == null)
- {
- subRow = sheet.createRow(currentRowNum + subIndex);
- }
-
- int subColumn = column;
- for (Field subField : subFields)
- {
- Excel subExcel = subField.getAnnotation(Excel.class);
- addCell(subExcel, subRow, (T) subVo, subField, subColumn++);
- }
- subIndex++;
- }
- column += subFields.size();
+ rowNo++;
+ row = sheet.createRow(rowNo);
}
+ List subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class);
+ int subIndex = 0;
+ for (Field subField : subFields)
+ {
+ if (subField.isAnnotationPresent(Excel.class))
+ {
+ subField.setAccessible(true);
+ Excel attr = subField.getAnnotation(Excel.class);
+ this.addCell(attr, row, (T) obj, subField, column + subIndex);
+ }
+ subIndex++;
+ }
+ subFirst = true;
}
- catch (Exception e)
- {
- log.error("填充集合数据失败", e);
- }
+ this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size();
}
else
{
- // 创建单元格并设置值
- addCell(excel, row, vo, field, column);
- if (maxSubListSize > 1 && excel.needMerge())
- {
- sheet.addMergedRegion(new CellRangeAddress(currentRowNum, currentRowNum + maxSubListSize - 1, column, column));
- }
- column++;
- }
- }
- currentRowNum += maxSubListSize;
- }
- }
-
- /**
- * 获取子列表最大数
- */
- private int getCurrentMaxSubListSize(T vo)
- {
- int maxSubListSize = 1;
- for (Object[] os : fields)
- {
- Field field = (Field) os[0];
- if (Collection.class.isAssignableFrom(field.getType()))
- {
- try
- {
- Collection> subList = (Collection>) getTargetValue(vo, field, (Excel) os[1]);
- if (subList != null && !subList.isEmpty())
- {
- maxSubListSize = Math.max(maxSubListSize, subList.size());
- }
- }
- catch (Exception e)
- {
- log.error("获取集合大小失败", e);
+ this.addCell(excel, row, vo, field, column++);
}
}
}
- return maxSubListSize;
}
/**
@@ -814,7 +859,7 @@ public class ExcelUtil
*/
public void annotationDataStyles(Map styles, Field field, Excel excel)
{
- String key = StringUtils.format("data_{}_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType(), excel.wrapText());
+ String key = StringUtils.format("data_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType());
if (!styles.containsKey(key))
{
CellStyle style = wb.createCellStyle();
@@ -830,7 +875,6 @@ public class ExcelUtil
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setFillForegroundColor(excel.backgroundColor().getIndex());
- style.setWrapText(excel.wrapText());
Font dataFont = wb.createFont();
dataFont.setFontName("Arial");
dataFont.setFontHeightInPoints((short) 10);
@@ -859,7 +903,7 @@ public class ExcelUtil
if (isSubList())
{
// 填充默认样式,防止合并单元格样式失效
- sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
+ sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType())));
if (attr.needMerge())
{
sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column));
@@ -954,17 +998,28 @@ public class ExcelUtil
// 设置列宽
sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
}
- if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0)
+ if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0 || attr.comboReadDict())
{
- if (attr.combo().length > 15 || StringUtils.join(attr.combo()).length() > 255)
+ String[] comboArray = attr.combo();
+ if (attr.comboReadDict())
+ {
+ if (!sysDictMap.containsKey("combo_" + attr.dictType()))
+ {
+ String labels = DictUtils.getDictLabels(attr.dictType());
+ sysDictMap.put("combo_" + attr.dictType(), labels);
+ }
+ String val = sysDictMap.get("combo_" + attr.dictType());
+ comboArray = StringUtils.split(val, DictUtils.SEPARATOR);
+ }
+ if (comboArray.length > 15 || StringUtils.join(comboArray).length() > 255)
{
// 如果下拉数大于15或字符串长度大于255,则使用一个新sheet存储,避免生成的模板下拉值获取不到
- setXSSFValidationWithHidden(sheet, attr.combo(), attr.prompt(), 1, 100, column, column);
+ setXSSFValidationWithHidden(sheet, comboArray, attr.prompt(), 1, 100, column, column);
}
else
{
// 提示信息或只能选择不能输入的列内容.
- setPromptOrValidation(sheet, attr.combo(), attr.prompt(), 1, 100, column, column);
+ setPromptOrValidation(sheet, comboArray, attr.prompt(), 1, 100, column, column);
}
}
}
@@ -986,27 +1041,34 @@ public class ExcelUtil
cell = row.createCell(column);
if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge())
{
- if (subMergedLastRowNum >= subMergedFirstRowNum)
- {
- sheet.addMergedRegion(new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column));
- }
+ CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column);
+ sheet.addMergedRegion(cellAddress);
}
- cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
+ cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType())));
// 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr);
String dateFormat = attr.dateFormat();
String readConverterExp = attr.readConverterExp();
String separator = attr.separator();
+ String dictType = attr.dictType();
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
{
- cell.getCellStyle().setDataFormat(this.wb.getCreationHelper().createDataFormat().getFormat(dateFormat));
cell.setCellValue(parseDateToStr(dateFormat, value));
}
else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
{
cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator));
}
+ else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value))
+ {
+ if (!sysDictMap.containsKey(dictType + value))
+ {
+ String lable = convertDictByExp(Convert.toStr(value), dictType, separator);
+ sysDictMap.put(dictType + value, lable);
+ }
+ cell.setCellValue(sysDictMap.get(dictType + value));
+ }
else if (value instanceof BigDecimal && -1 != attr.scale())
{
cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue());
@@ -1193,9 +1255,35 @@ public class ExcelUtil
return StringUtils.stripEnd(propertyString.toString(), separator);
}
+ /**
+ * 解析字典值
+ *
+ * @param dictValue 字典值
+ * @param dictType 字典类型
+ * @param separator 分隔符
+ * @return 字典标签
+ */
+ public static String convertDictByExp(String dictValue, String dictType, String separator)
+ {
+ return DictUtils.getDictLabel(dictType, dictValue, separator);
+ }
+
+ /**
+ * 反向解析值字典值
+ *
+ * @param dictLabel 字典标签
+ * @param dictType 字典类型
+ * @param separator 分隔符
+ * @return 字典值
+ */
+ public static String reverseDictByExp(String dictLabel, String dictType, String separator)
+ {
+ return DictUtils.getDictValue(dictType, dictLabel, separator);
+ }
+
/**
* 数据处理器
- *
+ *
* @param value 数据值
* @param excel 数据注解
* @return
@@ -1261,9 +1349,34 @@ public class ExcelUtil
}
}
+ /**
+ * 编码文件名
+ */
+ public String encodingFilename(String filename)
+ {
+ filename = UUID.randomUUID() + "_" + filename + ".xlsx";
+ return filename;
+ }
+
+ /**
+ * 获取下载路径
+ *
+ * @param filename 文件名称
+ */
+ public String getAbsoluteFile(String filename)
+ {
+ String downloadPath = TcctynConfig.getDownloadPath() + filename;
+ File desc = new File(downloadPath);
+ if (!desc.getParentFile().exists())
+ {
+ desc.getParentFile().mkdirs();
+ }
+ return downloadPath;
+ }
+
/**
* 获取bean中的属性值
- *
+ *
* @param vo 实体对象
* @param field 字段
* @param excel 注解
@@ -1272,7 +1385,6 @@ public class ExcelUtil
*/
private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
{
- field.setAccessible(true);
Object o = field.get(vo);
if (StringUtils.isNotEmpty(excel.targetAttr()))
{
@@ -1295,7 +1407,7 @@ public class ExcelUtil
/**
* 以类的属性的get方法方法形式获取值
- *
+ *
* @param o
* @param name
* @return value
@@ -1332,85 +1444,48 @@ public class ExcelUtil
List tempFields = new ArrayList<>();
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
- if (StringUtils.isNotEmpty(includeFields))
+ for (Field field : tempFields)
{
- for (Field field : tempFields)
+ if (!ArrayUtils.contains(this.excludeFields, field.getName()))
{
- if (ArrayUtils.contains(this.includeFields, field.getName()) || field.isAnnotationPresent(Excels.class))
+ // 单注解
+ if (field.isAnnotationPresent(Excel.class))
{
- addField(fields, field);
+ Excel attr = field.getAnnotation(Excel.class);
+ if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
+ {
+ field.setAccessible(true);
+ fields.add(new Object[] { field, attr });
+ }
+ if (Collection.class.isAssignableFrom(field.getType()))
+ {
+ subMethod = getSubMethod(field.getName(), clazz);
+ ParameterizedType pt = (ParameterizedType) field.getGenericType();
+ Class> subClass = (Class>) pt.getActualTypeArguments()[0];
+ this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
+ }
}
- }
- }
- else if (StringUtils.isNotEmpty(excludeFields))
- {
- for (Field field : tempFields)
- {
- if (!ArrayUtils.contains(this.excludeFields, field.getName()))
+
+ // 多注解
+ if (field.isAnnotationPresent(Excels.class))
{
- addField(fields, field);
+ Excels attrs = field.getAnnotation(Excels.class);
+ Excel[] excels = attrs.value();
+ for (Excel attr : excels)
+ {
+ if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
+ && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
+ {
+ field.setAccessible(true);
+ fields.add(new Object[] { field, attr });
+ }
+ }
}
}
}
- else
- {
- for (Field field : tempFields)
- {
- addField(fields, field);
- }
- }
return fields;
}
- /**
- * 添加字段信息
- */
- public void addField(List