Commit 474978a7 authored by thinkgem's avatar thinkgem
Browse files

Merge branch 'v4.2_dev'

# Conflicts:
#	common/pom.xml
#	common/src/main/java/com/jeesite/common/web/http/ServletUtils.java
#	common/src/main/resources/static/laydate/5.0/laydate.js
#	modules/core/pom.xml
#	modules/core/src/main/java/com/jeesite/common/shiro/filter/FormAuthenticationFilter.java
#	modules/core/src/main/java/com/jeesite/modules/sys/db/InitCoreData.xlsx
#	modules/core/src/main/java/com/jeesite/modules/sys/web/LoginController.java
#	modules/core/src/main/resources/config/jeesite-core.yml
#	modules/core/src/main/resources/db/upgrade/core/versions
#	modules/core/src/main/resources/templates/modules/gen/include/searchForm.html
#	modules/core/src/main/resources/views/modules/msg/msgInnerList.html
#	modules/core/src/main/resources/views/modules/sys/account/registerUser.html
#	modules/core/src/main/resources/views/modules/sys/logList.html
#	modules/template/pom.xml
#	parent/pom.xml
#	root/pom.xml
#	web/pom.xml
#	web/src/main/resources/config/application.yml
#	web/src/main/resources/views/modules/demo/demoDataGridEditGrid.html
#	web/src/main/resources/views/modules/demo/demoDataGridGroupGrid.html
#	web/src/main/resources/views/modules/test/testDataForm.html
#	web/src/main/resources/views/modules/test/testDataList.html
#	web/src/test/java/com/jeesite/test/InitData.java
parents ada241f8 03a1a48e
Showing with 363 additions and 267 deletions
+363 -267
......@@ -12,11 +12,10 @@ JeeSite 4.x 的升级,作者结合了多年总结和经验,以及各方面
## 技术选型
* 主框架:Spring Boot 2.0、Spring Framework 5.0、Apache Shiro 1.4、J2Cache
* 持久层:Apache MyBatis 3.4、Hibernate Validation 6.0、Alibaba Druid 1.1
* 视图层:Spring MVC 5.0、Beetl 3.0(替换JSP)、Bootstrap 3.3、AdminLTE 2.4
* 前端组件:jQuery 1.12、jqGrid 4.7、layer 3.1、zTree 3.5、jquery-validation
* 工具组件:Apache Commons、Jackson 2.10、POI 3.16、Quartz 2.3
* 主框架:Spring Boot 2.2、Spring Framework 5.2、Apache Shiro 1.5、J2Cache
* 持久层:Apache MyBatis 3.5、Hibernate Validator 6.0、Alibaba Druid 1.1
* 视图层:Spring MVC 5.2、Beetl 3.1(替换JSP)、Bootstrap 3.3、AdminLTE 2.4
* 前端组件:jQuery 3.4、jqGrid 4.7、layer 3.1、zTree 3.5、jquery validation
* 工作流引擎:Flowable 6.5、符合 BPMN 规范、在线流程设计器、中国式工作流
* 技术选型详情:<http://jeesite.com/?t=273599>
......@@ -40,7 +39,7 @@ JeeSite 4.x 的升级,作者结合了多年总结和经验,以及各方面
### 本地运行
1. 环境准备:`JDK 1.8``Maven 3.3``MySQL 5.7`
1. 环境准备:`JDK 1.8 or 11``Maven 3.6+``MySQL 5.7 or 8.0`
2. 下载源码:<https://gitee.com/thinkgem/jeesite4/attach_files>
3. 打开文件:/web`/src/main/resources/config/application.yml` 配置JDBC连接
4. 执行脚本:/web`/bin/init-data.bat` 初始化数据库
......@@ -63,7 +62,8 @@ JeeSite 4.x 的升级,作者结合了多年总结和经验,以及各方面
2. 您可以免费使用、修改和衍生代码,但不允许修改后和衍生的代码做为闭源软件发布。
3. 修改后和衍生的代码必须也按照AGPL协议进行流通,对修改后和衍生的代码必须向社会公开。
4. 如果您修改了代码,需要在被修改的文件中进行说明,并遵守代码格式规范,帮助他人更好的理解您的用意。
5. 在延伸的代码中(修改和有源代码衍生的代码中)需要带有原来代码中的协议、版权声明和其他原作者规定需要包含的说明(请尊重原作者的著作权,不要删除或修改文件中的`@author`信息)。
5. 在延伸的代码中(修改和有源代码衍生的代码中)需要带有原来代码中的协议、版权声明和其他原作者规定
需要包含的说明(请尊重原作者的著作权,不要删除或修改文件中的`@author`信息)。
6. 您可以应用于商业软件,但必须遵循以上条款原则(请协助改进本作品)。
7. 关系平台的发展战略考虑,底层部分代码暂未开源,但这不影响您的二次开发。
8. 请知悉社区版,用户数不可超过100个,最大允许20个用户同时在线(不含匿名)。
......@@ -71,12 +71,12 @@ JeeSite 4.x 的升级,作者结合了多年总结和经验,以及各方面
## 技术服务与支持
* 没有资金的支撑就很难得到发展,特别是一个好的产品,如果 JeeSite 帮助了您,请为我们点赞。支持我们,您可以得到一些回报,有了这些我们会把公益事业做的更好,回报社区和社会,请给我们一些动力吧,在此非常感谢已支持我们的朋友!
* **联系方式(官方商务)QQ:[1766571055](http://sighttp.qq.com/msgrd?v=1&uin=1766571055)**
* **联系方式(官方商务)QQ:[1766571055](http://wpa.qq.com/msgrd?v=3&uin=1766571055&site=qq&menu=yes)**
* 技术服务支持网页:<http://s.jeesite.com>
# 技术交流方式
* QQ 群号:`127515876``209330483``223507718``709534275``730390092``183903863(外包)`
* QQ 群号:`127515876``209330483``223507718``709534275``730390092``1373527``183903863(外包)`
* 问题反馈:<https://gitee.com/thinkgem/jeesite4/issues>  [【新手必读】](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md)
* 码云Gitee:<https://gitee.com/thinkgem/jeesite4>
* GitHub:<https://github.com/thinkgem/jeesite4>
......@@ -84,21 +84,19 @@ JeeSite 4.x 的升级,作者结合了多年总结和经验,以及各方面
* **技术服务:**<http://s.jeesite.com>
* 官方网站:<http://jeesite.com>
* 官方论坛:<http://jeesite.net>
* 微信公众号:
* 微信公众号(关注动态)
![JeeSite4微信公众号](https://static.oschina.net/uploads/space/2018/0302/145133_OGZf_941661.jpg "JeeSite4微信公众号")
## 今后如何升级?
尽量不修改web项目以外的源码项目,如 jeesite-common、jeesite-modele-core,如果修改了,请 Pull Requests 上来,否则代码编码将与官方不同步,将对你的日后升级带来困难
尽量不修改 web 项目以外的源码项目,如 jeesite-common、jeesite-modele-core,如果修改了,请 Pull Requests 上来,否则代码与官方不同步,将对你的日后升级增加难度
JeeSite的小版本(4.1.x)升级是非常便捷的,你只需要将 pom.xml 文件中的 parent.version 版本修改到最新版本即可,同版本下你可进行 Maven 快照强制更新,即可将最新版的依赖 jar 更新到本地,下面以 Eclipse 举例,介绍如何操作:
如果您修改了依赖模块代码,也没关系,这时你需要利用 Git 版本控制工具,与官方仓库代码进行同步,合并代码即可。
在 web 项目上右键,选择菜单 -> Maven -> Update Project...(或按Alt+F5) -> 点击 Select All 按钮 -> 选择 Force Update of Snapshots/Releases 复选框 -> 点击OK按钮即可
每个版本升级,我们都会附带详细更新日志:<http://jeesite.com/?t=273830>
如果您修改了其它依赖模块代码,这时你需要利用 Git 版本控制工具,与官方仓库代码进行同步,合并代码即可。
如果进行相对大的版本(4.x.x)升级这里我们会附加一个声明,帮助你进行迁移操作,更新日志:<http://jeesite.com/?t=273830>
在这里,你可以看到 JeeSite 新增哪些新功能和改进,在每个版本下都有对应升级方法。
# Git 全局设置技巧
......
......@@ -6,7 +6,7 @@
<parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>4.1.9-SNAPSHOT</version>
<version>4.2.0-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
......@@ -67,20 +67,6 @@
<version>${fst.version}</version>
</dependency>
<!-- Json in java -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>${json.version}</version>
</dependency>
<!-- Fast json -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- Jackson json -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
......@@ -95,10 +81,18 @@
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<!-- Fast json -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- Java xml -->
<dependency>
<groupId>dom4j</groupId>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>${dom4j.version}</version>
</dependency>
<!-- XPath xml -->
......@@ -301,39 +295,6 @@
<plugins>
</plugins>
<pluginManagement>
<plugins>
<!-- YUI Compressor (CSS/JS压缩) -->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>compress</goal>
</goals>
</execution>
</executions>
<configuration>
<encoding>UTF-8</encoding>
<jswarn>false</jswarn>
<nosuffix>true</nosuffix>
<linebreakpos>30000</linebreakpos>
<force>true</force>
<includes>
<include>**/*.js</include>
<include>**/*.css</include>
</includes>
<excludes>
<exclude>**/*.min.js</exclude>
<exclude>**/*.min.css</exclude>
<exclude>**/jquery-*.js</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<developers>
......
......@@ -25,6 +25,9 @@ public class DesUtils {
if (StringUtils.isBlank(data)){
return "";
}
if ("Base64".equals(secretKey)) {
return EncodeUtils.encodeBase64(data);
}
String[] ks = StringUtils.split(secretKey, ",");
if (ks.length >= 3){
return desCore.strEnc(data, ks[0], ks[1], ks[2]);
......@@ -39,6 +42,9 @@ public class DesUtils {
if (StringUtils.isBlank(data)){
return "";
}
if ("Base64".equals(secretKey)) {
return EncodeUtils.decodeBase64String(data);
}
String[] ks = StringUtils.split(secretKey, ",");
if (ks.length >= 3){
return desCore.strDec(data, ks[0], ks[1], ks[2]);
......
......@@ -198,7 +198,8 @@ public class EncodeUtils {
Pattern.compile("(<\\s*(script|link|style|iframe)([\\s\\S]*?)(>|<\\/\\s*\\1\\s*>))|(</\\s*(script|link|style|iframe)\\s*>)", Pattern.CASE_INSENSITIVE),
Pattern.compile("\\s*(href|src)\\s*=\\s*(\"\\s*(javascript|vbscript):[^\"]+\"|'\\s*(javascript|vbscript):[^']+'|(javascript|vbscript):[^\\s]+)\\s*(?=>)", Pattern.CASE_INSENSITIVE),
Pattern.compile("\\s*on[a-z]+\\s*=\\s*(\"[^\"]+\"|'[^']+'|[^\\s]+)\\s*(?=>)", Pattern.CASE_INSENSITIVE),
Pattern.compile("(eval\\((.*?)\\)|xpression\\((.*?)\\))", Pattern.CASE_INSENSITIVE)
Pattern.compile("(eval\\((.*?)\\)|xpression\\((.*?)\\))", Pattern.CASE_INSENSITIVE),
Pattern.compile("^(javascript:|vbscript:)", Pattern.CASE_INSENSITIVE)
);
/**
......@@ -260,7 +261,10 @@ public class EncodeUtils {
}
// 预编译SQL过滤正则表达式
private static Pattern sqlPattern = Pattern.compile("(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\\b(select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute|case when)\\b)", Pattern.CASE_INSENSITIVE);
private static Pattern sqlPattern = Pattern.compile(
"(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|((extractvalue|updatexml)([\\s]*?)\\()|"
+ "(\\b(select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute|case when)\\b)",
Pattern.CASE_INSENSITIVE);
/**
* SQL过滤,防止注入,传入参数输入有select相关代码,替换空。
......
......@@ -84,7 +84,7 @@ public class MapUtils extends org.apache.commons.collections.MapUtils {
* @param clazz
* @param list
*/
public static <T, V> List<T> toObjectList(Class<T> clazz, List<HashMap<String, V>> list) throws IllegalAccessException,
public static <T, V> List<T> toObjectList(Class<T> clazz, List<HashMap<String, V>> list) throws Exception,
InvocationTargetException, NoSuchMethodException, InstantiationException {
List<T> retList = new ArrayList<T>();
if (list != null && !list.isEmpty()) {
......@@ -100,9 +100,9 @@ public class MapUtils extends org.apache.commons.collections.MapUtils {
* @param clazz 目标对象的类
* @param map 待转换Map
*/
public static <T, V> T toObject(Class<T> clazz, Map<String, V> map) throws InstantiationException, IllegalAccessException,
public static <T, V> T toObject(Class<T> clazz, Map<String, V> map) throws Exception,
InvocationTargetException {
T object = clazz.newInstance();
T object = clazz.getDeclaredConstructor().newInstance();
return toObject(object, map);
}
......@@ -112,9 +112,9 @@ public class MapUtils extends org.apache.commons.collections.MapUtils {
* @param map 待转换Map
* @param toCamelCase 是否去掉下划线
*/
public static <T, V> T toObject(Class<T> clazz, Map<String, V> map, boolean toCamelCase) throws InstantiationException, IllegalAccessException,
public static <T, V> T toObject(Class<T> clazz, Map<String, V> map, boolean toCamelCase) throws Exception,
InvocationTargetException {
T object = clazz.newInstance();
T object = clazz.getDeclaredConstructor().newInstance();
return toObject(object, map, toCamelCase);
}
......
......@@ -14,7 +14,7 @@ import com.jeesite.common.lang.StringUtils;
* @author ThinkGem
* @version 2014-8-19
*/
public class IdGenerate {
public class IdGen {
private static SecureRandom random = new SecureRandom();
private static IdWorker idWorker = new IdWorker(-1, -1);
......
......@@ -33,8 +33,11 @@ public class PropertiesUtils {
// 默认加载的文件,可通过继承覆盖(若有相同Key,优先加载后面的)
public static final String[] DEFAULT_CONFIG_FILE = new String[]{
"classpath:config/bootstrap.yml", "classpath:bootstrap.yml",
"classpath:config/application.yml", "classpath:application.yml"};
"classpath:application.yml", "classpath:config/application.yml",
"classpath:bootstrap.yml", "classpath:config/bootstrap.yml",
"file:application.yml", "file:config/application.yml",
"file:bootstrap.yml", "file:config/bootstrap.yml",
};
private static Logger logger = PropertiesUtils.initLogger();
private final Set<String> configSet = SetUtils.newLinkedHashSet();
......@@ -95,7 +98,7 @@ public class PropertiesUtils {
}
}
configFiles = configSet.toArray(new String[configSet.size()]);
logger.debug("Loading jeesite config: {}", (Object)configFiles);
logger.debug("Trying: {}", (Object)configFiles);
INSTANCE = new PropertiesUtils(configFiles);
}
}
......
......@@ -9,31 +9,40 @@ import java.util.List;
import java.util.Properties;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.core.Ordered;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import com.alibaba.fastjson.parser.ParserConfig;
/**
* 配置文件加载(Boot)
* @author ThinkGem
* @version 2018-10-16
*/
public class PropertyLoader implements org.springframework.boot.env.PropertySourceLoader{
public class PropertyLoader implements org.springframework.boot.env.PropertySourceLoader, Ordered{
private static boolean isLoadPropertySource = false;
@Override
public String[] getFileExtensions() {
return new String[] { "properties", "yml" };
return new String[] { "properties", "yml", "yaml" };
}
@Override
public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
if (!isLoadPropertySource){
isLoadPropertySource = true;
ParserConfig.getGlobalInstance().setSafeMode(true); // 开启 FastJSON 安全模式
Properties properties = PropertiesUtils.getInstance().getProperties();
return Collections.singletonList(new OriginTrackedMapPropertySource("jeesite", properties));
}
return Collections.emptyList();
}
@Override
public int getOrder() {
return Integer.MIN_VALUE;
}
}
......@@ -4,6 +4,7 @@
package com.jeesite.common.lang;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
/**
......@@ -72,7 +73,7 @@ public class NumberUtils extends org.apache.commons.lang3.math.NumberUtils {
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
}
/**
......@@ -81,7 +82,7 @@ public class NumberUtils extends org.apache.commons.lang3.math.NumberUtils {
*/
public static String formatDouble(Double b) {
BigDecimal bg = new BigDecimal(b);
return bg.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
return bg.setScale(2, RoundingMode.HALF_UP).toString();
}
/**
......@@ -90,7 +91,7 @@ public class NumberUtils extends org.apache.commons.lang3.math.NumberUtils {
*/
public static String formatScale(double one, long total) {
BigDecimal bg = new BigDecimal(one * 100 / total);
return bg.setScale(0, BigDecimal.ROUND_HALF_UP).toString();
return bg.setScale(0, RoundingMode.HALF_UP).toString();
}
/**
......
......@@ -7,7 +7,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
......@@ -17,14 +17,14 @@ import org.springframework.beans.BeanUtils;
import org.springframework.core.NamedThreadLocal;
/**
* 对象操作工具类, 继承org.apache.commons.lang3.ObjectUtils类
* 对象操作工具类继承 org.apache.commons.lang3.ObjectUtils
* @author ThinkGem
* @version 2018-08-11
* @version 2020-3-29
*/
public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {
/**
* 转换为Double类型
* 转换为 Double 类型
*/
public static Double toDouble(final Object val) {
if (val == null) {
......@@ -38,28 +38,29 @@ public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {
}
/**
* 转换为Float类型
* 转换为 Float 类型
*/
public static Float toFloat(final Object val) {
return toDouble(val).floatValue();
}
/**
* 转换为Long类型
* 转换为 Long 类型
*/
public static Long toLong(final Object val) {
return toDouble(val).longValue();
}
/**
* 转换为Integer类型
* 转换为 Integer 类型
*/
public static Integer toInteger(final Object val) {
return toLong(val).intValue();
}
/**
* 转换为Boolean类型 'true', 'on', 'y', 't', 'yes' or '1' (case insensitive) will return true. Otherwise, false is returned.
* 转换为 Boolean 类型 'true', 'on', 'y', 't', 'yes' or '1'
* (case insensitive) will return true. Otherwise, false is returned.
*/
public static Boolean toBoolean(final Object val) {
if (val == null) {
......@@ -70,43 +71,35 @@ public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {
/**
* 转换为字符串
* @param obj
* @return
*/
public static String toString(final Object obj) {
return toString(obj, StringUtils.EMPTY);
}
/**
* 如果对象为空,则使用defaultVal值
* @param obj
* @param defaultVal
* @return
* 转换为字符串,如果对象为空,则使用 defaultVal 值
*/
public static String toString(final Object obj, final String defaultVal) {
return obj == null ? defaultVal : obj.toString();
}
/**
* 空转空字符串("" to "" ; null to "" ; "null" to "" ; "NULL" to "" ; "Null" to "")
* @param val 需转换的值
* @return 返回转换后的值
* 转换为字符串,忽略空值。如 null 字符串,则被认为空值,如下:
* "" to "" ; null to "" ; "null" to "" ; "NULL" to "" ; "Null" to ""
*/
public static String toStringIgnoreNull(final Object val) {
return ObjectUtils.toStringIgnoreNull(val, StringUtils.EMPTY);
}
/**
* 空对象转空字符串 ("" to defaultVal ; null to defaultVal ; "null" to defaultVal ; "NULL" to defaultVal ; "Null" to defaultVal)
* @param val 需转换的值
* @param defaultVal 默认值
* @return 返回转换后的值
* 转换为字符串,忽略空值。如 null 字符串,则被认为空值,如下:
* "" to defaultVal ; null to defaultVal ; "null" to defaultVal ; "NULL" to defaultVal ; "Null" to defaultVal
*/
public static String toStringIgnoreNull(final Object val, String defaultVal) {
String str = ObjectUtils.toString(val);
return !"".equals(str) && !"null".equals(str.trim().toLowerCase()) ? str : defaultVal;
}
/**
* 拷贝一个对象(但是子对象无法拷贝)
* @param source
......@@ -117,40 +110,26 @@ public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {
return null;
}
try {
Object target = source.getClass().newInstance();
Object target = source.getClass().getDeclaredConstructor().newInstance();
BeanUtils.copyProperties(source, target, ignoreProperties);
return target;
} catch (InstantiationException | IllegalAccessException e) {
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
throw ExceptionUtils.unchecked(e);
}
}
/**
* 注解到对象复制,只复制能匹配上的方法。 硕正组件用。
* @param annotation
* @param object
* 克隆一个对象(完全拷贝)
* @param source
*/
public static void annotationToObject(Object annotation, Object object) {
if (annotation != null && object != null) {
Class<?> annotationClass = annotation.getClass();
Class<?> objectClass = object.getClass();
for (Method m : objectClass.getMethods()) {
if (StringUtils.startsWith(m.getName(), "set")) {
try {
String s = StringUtils.uncapitalize(StringUtils.substring(m.getName(), 3));
Object obj = annotationClass.getMethod(s).invoke(annotation);
if (obj != null && !"".equals(obj.toString())) {
// if (object == null){
// object = objectClass.newInstance();
// }
m.invoke(object, obj);
}
} catch (Exception e) {
// 忽略所有设置失败方法
}
}
}
public static Object cloneBean(Object source){
if (source == null){
return null;
}
byte[] bytes = ObjectUtils.serialize(source);
Object target = ObjectUtils.unserialize(bytes);
return target;
}
/**
......@@ -159,6 +138,24 @@ public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {
* @return
*/
public static byte[] serialize(Object object) {
return ObjectUtils.serializeFst(object);
}
/**
* 反序列化对象
* @param bytes
* @return
*/
public static Object unserialize(byte[] bytes) {
return ObjectUtils.unserializeFst(bytes);
}
/**
* 序列化对象
* @param object
* @return
*/
public static byte[] serializeJava(Object object) {
if (object == null){
return null;
}
......@@ -183,7 +180,7 @@ public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {
* @param bytes
* @return
*/
public static Object unserialize(byte[] bytes) {
public static Object unserializeJava(byte[] bytes) {
if (bytes == null){
return null;
}
......@@ -204,8 +201,8 @@ public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {
return object;
}
// FST序列化配置对象
private static ThreadLocal<FSTConfiguration> fst = new NamedThreadLocal<FSTConfiguration>("FSTConfiguration") {
private static ThreadLocal<FSTConfiguration> fstConfiguration =
new NamedThreadLocal<FSTConfiguration>("FSTConfiguration") {
public FSTConfiguration initialValue() {
return FSTConfiguration.createDefaultConfiguration();
}
......@@ -221,7 +218,7 @@ public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {
return null;
}
long beginTime = System.currentTimeMillis();
byte[] bytes = fst.get().asByteArray(object);
byte[] bytes = fstConfiguration.get().asByteArray(object);
long totalTime = System.currentTimeMillis() - beginTime;
if (totalTime > 3000){
System.out.println("Fst serialize time: " + TimeUtils.formatDateAgo(totalTime));
......@@ -239,25 +236,66 @@ public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {
return null;
}
long beginTime = System.currentTimeMillis();
Object object = fst.get().asObject(bytes);
Object object = fstConfiguration.get().asObject(bytes);
long totalTime = System.currentTimeMillis() - beginTime;
if (totalTime > 3000){
System.out.println("Fst unserialize time: " + TimeUtils.formatDateAgo(totalTime));
}
return object;
}
/**
* 克隆一个对象(完全拷贝)
* @param source
*/
public static Object cloneBean(Object source){
if (source == null){
return null;
}
byte[] bytes = ObjectUtils.serializeFst(source);
Object target = ObjectUtils.unserializeFst(bytes);
return target;
}
// private static Pool<Kryo> kryoPool = new Pool<Kryo>(true, false, 8) {
// protected Kryo create() {
// Kryo kryo = new Kryo();
// kryo.setRegistrationRequired(false);
// kryo.setReferences(false);
// return kryo;
// }
// };
// private static Pool<Output> outputPool = new Pool<Output>(true, false, 16) {
// protected Output create() {
// return new Output(1024, -1);
// }
// };
// private static Pool<Input> inputPool = new Pool<Input>(true, false, 16) {
// protected Input create() {
// return new Input(1024);
// }
// };
//
// /**
// * Kryo 序列化对象
// * @param object
// * @return
// */
// public static byte[] serializeKryo(Object object) {
// Kryo kryo = kryoPool.obtain();
// Output output = outputPool.obtain();
// try {
// output.reset();
// kryo.writeClassAndObject(output, object);
// return output.toBytes();
// } finally {
// kryoPool.free(kryo);
// outputPool.free(output);
// }
// }
//
// /**
// * Kryo 反序列化对象
// * @param bytes
// * @return
// */
// public static Object unserializeKryo(byte[] bytes) {
// Kryo kryo = kryoPool.obtain();
// Input input = inputPool.obtain();
// try {
// input.setBuffer(bytes);
// return kryo.readClassAndObject(input);
// } finally {
// kryoPool.free(kryo);
// inputPool.free(input);
// }
// }
}
......@@ -387,9 +387,9 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
if ("true".equals(isShowCode) || "1".equals(isShowCode)) {
return "(" + code + ") " + StringUtils.replace(name, " ", "");
} else if ("2".equals(isShowCode)) {
return StringUtils.replace(name, " ", "") + " (" + code + ")";
return name/*StringUtils.replace(name, " ", "")*/ + " (" + code + ")";
} else {
return StringUtils.replace(name, " ", "");
return name/*StringUtils.replace(name, " ", "")*/;
}
}
......
......@@ -108,6 +108,20 @@ public class JsonMapper extends ObjectMapper {
return null;
}
}
/**
* Object可以是POJO,也可以是Collection或数组。
* 如果对象为Null, 返回"null".
* 如果集合为空集合, 返回"[]".(根据 JsonView 渲染)
*/
public String toJsonString(Object object, Class<?> jsonView) {
try {
return this.writerWithView(jsonView).writeValueAsString(object);
} catch (IOException e) {
logger.warn("write to json string error:" + object, e);
return null;
}
}
/**
* 输出JSONP格式数据.
......@@ -218,6 +232,13 @@ public class JsonMapper extends ObjectMapper {
return JsonMapper.getInstance().toJsonString(object);
}
/**
* 对象转换为JSON字符串(根据 JsonView 渲染)
*/
public static String toJson(Object object, Class<?> jsonView){
return JsonMapper.getInstance().toJsonString(object, jsonView);
}
/**
* 对象转换为JSONP字符串
*/
......
......@@ -67,6 +67,18 @@ public class XmlMapper extends com.fasterxml.jackson.dataformat.xml.XmlMapper{
}
}
/**
* Object可以是POJO,也可以是Collection或数组。(根据 JsonView 渲染)
*/
public String toXmlString(Object object, Class<?> jsonView) {
try {
return this.writerWithView(jsonView).writeValueAsString(object);
} catch (IOException e) {
logger.warn("write to xml string error:" + object, e);
return null;
}
}
/**
* 反序列化POJO或简单Collection如List<String>.
* @see #fromJson(String, JavaType)
......@@ -97,6 +109,13 @@ public class XmlMapper extends com.fasterxml.jackson.dataformat.xml.XmlMapper{
return XmlMapper.getInstance().toXmlString(object);
}
/**
* 对象转换为XML字符串(根据 JsonView 渲染)
*/
public static String toXml(Object object, Class<?> jsonView){
return XmlMapper.getInstance().toXmlString(object, jsonView);
}
/**
* XML字符串转换为对象
*/
......@@ -167,7 +186,6 @@ public class XmlMapper extends com.fasterxml.jackson.dataformat.xml.XmlMapper{
* @param element
* @return
*/
@SuppressWarnings("unchecked")
private static Object xmlToMap(Element element) {
// System.out.println(element.getName());
Map<String, Object> map = new LinkedHashMap<String, Object>();
......@@ -212,7 +230,6 @@ public class XmlMapper extends com.fasterxml.jackson.dataformat.xml.XmlMapper{
* @param element
* @return
*/
@SuppressWarnings("unchecked")
private static Object xmlToMapWithAttr(Element element) {
// System.out.println(element.getName());
Map<String, Object> map = new LinkedHashMap<String, Object>();
......
......@@ -288,14 +288,12 @@ abstract class VFS {
for (int i = 0; vfs == null || !vfs.isValid(); i++) {
Class<? extends VFS> impl = impls.get(i);
try {
vfs = impl.newInstance();
vfs = impl.getDeclaredConstructor().newInstance();
if (vfs == null || !vfs.isValid()) {
log.debug("VFS implementation " + impl.getName() + " is not valid in this environment.");
}
} catch (InstantiationException e) {
log.error("Failed to instantiate " + impl, e);
return null;
} catch (IllegalAccessException e) {
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
log.error("Failed to instantiate " + impl, e);
return null;
}
......@@ -458,7 +456,7 @@ class DefaultVFS extends VFS {
// Some versions of JBoss VFS might give a JAR stream even if the resource
// referenced by the URL isn't actually a JAR
is = url.openStream();
@SuppressWarnings("resource")
// @SuppressWarnings("resource")
JarInputStream jarInput = new JarInputStream(is);
log.debug("Listing " + url);
for (JarEntry entry; (entry = jarInput.getNextJarEntry()) != null;) {
......@@ -475,21 +473,22 @@ class DefaultVFS extends VFS {
* then we assume the current resource is not a directory.
*/
is = url.openStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
List<String> lines = new ArrayList<String>();
for (String line; (line = reader.readLine()) != null;) {
log.debug("Reader entry: " + line);
lines.add(line);
if (getResources(path + "/" + line).isEmpty()) {
lines.clear();
break;
try(BufferedReader reader = new BufferedReader(new InputStreamReader(is))){
List<String> lines = new ArrayList<String>();
for (String line; (line = reader.readLine()) != null;) {
log.debug("Reader entry: " + line);
lines.add(line);
if (getResources(path + "/" + line).isEmpty()) {
lines.clear();
break;
}
}
}
if (!lines.isEmpty()) {
log.debug("Listing " + url);
children.addAll(lines);
}
if (!lines.isEmpty()) {
log.debug("Listing " + url);
children.addAll(lines);
}
};
}
} catch (FileNotFoundException e) {
/*
......
......@@ -97,14 +97,16 @@ public class ReflectUtils {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
//throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
if (obj != null) {
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
}
return null;
}
E result = null;
try {
result = (E)field.get(obj);
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常{}", e.getMessage());
logger.error("不可能抛出的异常: {}", e.getMessage());
}
return result;
}
......@@ -141,7 +143,9 @@ public class ReflectUtils {
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
//throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
logger.debug("在 [" + (obj.getClass() == Class.class ? obj : obj.getClass()) + "] 中,没有找到 [" + methodName + "] 方法 ");
if (obj != null) {
logger.debug("在 [" + (obj.getClass() == Class.class ? obj : obj.getClass()) + "] 中,没有找到 [" + methodName + "] 方法 ");
}
return null;
}
try {
......@@ -164,7 +168,9 @@ public class ReflectUtils {
if (method == null) {
// 如果为空不报错,直接返回空。
// throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
logger.debug("在 [" + (obj.getClass() == Class.class ? obj : obj.getClass()) + "] 中,没有找到 [" + methodName + "] 方法 ");
if (obj != null) {
logger.debug("在 [" + (obj.getClass() == Class.class ? obj : obj.getClass()) + "] 中,没有找到 [" + methodName + "] 方法 ");
}
return null;
}
try {
......
......@@ -121,7 +121,7 @@ public class BinaryUploader {
// 先截图
if (v.cutPic()){
// 开启进程,在转换视频文件
new Thread(new Runnable() {
Thread thread = new Thread("video-convert") {
@Override
public void run() {
try {
......@@ -131,7 +131,9 @@ public class BinaryUploader {
e.printStackTrace();
}
}
}).start();
};
thread.setDaemon(true);
thread.start();
storageState.putInfo("url", ctx + PathFormat.format(savePath) + "." + v.getOutputFileExtension());
storageState.putInfo("type", "." + v.getOutputFileExtension());
storageState.putInfo("original", originFileName +"."+ v.getInputFileExtension());
......
......@@ -7,7 +7,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import com.jeesite.common.idgen.IdGenerate;
import com.jeesite.common.idgen.IdGen;
import com.jeesite.common.io.FileUtils;
import com.jeesite.common.io.PropertiesUtils;
import com.jeesite.common.lang.StringUtils;
......@@ -174,7 +174,7 @@ public class StorageManager {
File tmpDir = new File(System.getProperty("java.io.tmpdir"));
// String tmpFileName = (Math.random() * 10000 + "").replace(".", "");
// return new File(tmpDir, tmpFileName);
return new File(tmpDir, IdGenerate.randomBase62(10));
return new File(tmpDir, IdGen.randomBase62(10));
}
private static State saveTmpFile(File tmpFile, String path) {
......
......@@ -9,16 +9,15 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletResponse;
......@@ -41,10 +40,9 @@ import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.collect.SetUtils;
import com.jeesite.common.collect.MapUtils;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.reflect.ReflectUtils;
......@@ -52,11 +50,12 @@ import com.jeesite.common.utils.excel.annotation.ExcelField;
import com.jeesite.common.utils.excel.annotation.ExcelField.Align;
import com.jeesite.common.utils.excel.annotation.ExcelField.Type;
import com.jeesite.common.utils.excel.annotation.ExcelFields;
import com.jeesite.common.utils.excel.fieldtype.FieldType;
/**
* 导出Excel文件(导出“XLSX”格式,支持大数据量导出 @see org.apache.poi.ss.SpreadsheetVersion)
* @author ThinkGem
* @version 2020-2-19
* @version 2020-3-5
*/
public class ExcelExport implements Closeable{
......@@ -88,9 +87,9 @@ public class ExcelExport implements Closeable{
private List<Object[]> annotationList;
/**
* 用于清理缓存
* 存储字段类型临时数据
*/
private Set<Class<?>> fieldTypes = SetUtils.newHashSet();
private Map<Class<? extends FieldType>, FieldType> fieldTypes = MapUtils.newHashMap();
/**
* 构造函数
......@@ -231,8 +230,8 @@ public class ExcelExport implements Closeable{
Collections.sort(annotationList, new Comparator<Object[]>() {
@Override
public int compare(Object[] o1, Object[] o2) {
return new Integer(((ExcelField)o1[0]).sort()).compareTo(
new Integer(((ExcelField)o2[0]).sort()));
return Integer.valueOf(((ExcelField)o1[0]).sort()).compareTo(
Integer.valueOf(((ExcelField)o2[0]).sort()));
};
});
// Initialize
......@@ -249,7 +248,11 @@ public class ExcelExport implements Closeable{
}
}
headerList.add(headerTitle);
headerWidthList.add(ef.width());
if (ef.words() != -1) {
headerWidthList.add(ef.words() * 256);
}else {
headerWidthList.add(ef.width());
}
}
// 创建工作表
this.createSheet(sheetName, title, headerList, headerWidthList);
......@@ -426,7 +429,7 @@ public class ExcelExport implements Closeable{
* @return 单元格对象
*/
public Cell addCell(Row row, int column, Object val){
return this.addCell(row, column, val, Align.AUTO, Class.class, null);
return this.addCell(row, column, val, Align.AUTO, FieldType.class, null);
}
/**
......@@ -438,20 +441,17 @@ public class ExcelExport implements Closeable{
* @param dataFormat 数值格式(例如:0.00,yyyy-MM-dd)
* @return 单元格对象
*/
public Cell addCell(Row row, int column, Object val, Align align, Class<?> fieldType, String dataFormat){
@SuppressWarnings("unchecked")
public Cell addCell(Row row, int column, Object val, Align align, Class<? extends FieldType> fieldType, String dataFormat){
Cell cell = row.createCell(column);
String defaultDataFormat = "@";
String defaultDataFormat = null;
try {
if(val == null){
cell.setCellValue("");
}else if(fieldType != Class.class){
fieldTypes.add(fieldType); // 先存起来,方便完成后清理缓存
cell.setCellValue((String)fieldType.getMethod("setValue", Object.class).invoke(null, val));
try{
defaultDataFormat = (String)fieldType.getMethod("getDataFormat").invoke(null);
} catch (Exception ex) {
defaultDataFormat = "@";
}
cell.setCellValue(StringUtils.EMPTY);
}else if(fieldType != FieldType.class){
FieldType ft = getFieldType(fieldType);
cell.setCellValue(ft.setValue(val));
defaultDataFormat = ft.getDataFormat();
}else{
if(val instanceof String) {
cell.setCellValue((String) val);
......@@ -474,10 +474,11 @@ public class ExcelExport implements Closeable{
defaultDataFormat = "yyyy-MM-dd HH:mm";
}else {
// 如果没有指定 fieldType,切自行根据类型查找相应的转换类(com.jeesite.common.utils.excel.fieldtype.值的类名+Type)
Class<?> fieldType2 = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
fieldType = (Class<? extends FieldType>)Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
"fieldtype."+val.getClass().getSimpleName()+"Type"));
fieldTypes.add(fieldType2); // 先存起来,方便完成后清理缓存
cell.setCellValue((String)fieldType2.getMethod("setValue", Object.class).invoke(null, val));
FieldType ft = getFieldType(fieldType);
cell.setCellValue(ft.setValue(val));
defaultDataFormat = ft.getDataFormat();
}
}
// if (val != null){
......@@ -485,9 +486,12 @@ public class ExcelExport implements Closeable{
if (style == null){
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"+(align.value()>=1&&align.value()<=3?align.value():"")));
if (dataFormat != null){
if (StringUtils.isNotBlank(dataFormat)){
defaultDataFormat = dataFormat;
}
if (defaultDataFormat == null) {
defaultDataFormat = "@";
}
style.setDataFormat(wb.createDataFormat().getFormat(defaultDataFormat));
styles.put("data_column_" + column, style);
}
......@@ -499,6 +503,15 @@ public class ExcelExport implements Closeable{
}
return cell;
}
private FieldType getFieldType(Class<? extends FieldType> fieldType) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
FieldType ft = fieldTypes.get(fieldType);
if (ft == null) {
ft = fieldType.getDeclaredConstructor().newInstance();
fieldTypes.put(fieldType, ft);
}
return ft;
}
/**
* 添加数据(通过annotation.ExportField添加数据)
......@@ -526,7 +539,7 @@ public class ExcelExport implements Closeable{
// If is dict, get dict label
if (StringUtils.isNotBlank(ef.dictType())){
Class<?> dictUtils = Class.forName("com.jeesite.modules.sys.utils.DictUtils");
val = dictUtils.getMethod("getDictLabel", String.class, String.class,
val = dictUtils.getMethod("getDictLabels", String.class, String.class,
String.class).invoke(null, ef.dictType(), val==null?"":val.toString(), "");
//val = DictUtils.getDictLabel(val==null?"":val.toString(), ef.dictType(), "");
}
......@@ -535,17 +548,20 @@ public class ExcelExport implements Closeable{
log.info(ex.toString());
val = "";
}
String dataFormat = ef.dataFormat();
try {
// 获取Json格式化注解的格式化参数
JsonFormat jf = e.getClass().getMethod("get"+StringUtils.capitalize(ef.attrName())).getAnnotation(JsonFormat.class);
if (jf != null && jf.pattern() != null){
dataFormat = jf.pattern();
}
} catch (Exception e1) {
// 如果获取失败,则使用默认。
}
this.addCell(row, colunm++, val, ef.align(), ef.fieldType(), dataFormat);
// // 如果没有设置格式,则获取Json格式化注解的格式化参数(建议使用 ef.dataFormat 指定格式)
// String dataFormat = ef.dataFormat();
// if (StringUtils.isBlank(dataFormat)) {
// try {
// JsonFormat jf = e.getClass().getMethod("get"+StringUtils.capitalize(ef.attrName()))
// .getAnnotation(JsonFormat.class);
// if (jf != null && jf.pattern() != null){
// dataFormat = jf.pattern();
// }
// } catch (Exception e1) {
// // 如果获取失败,则使用默认。
// }
// }
this.addCell(row, colunm++, val, ef.align(), ef.fieldType(), ef.dataFormat());
sb.append(val + ", ");
}
log.debug("Write success: ["+row.getRowNum()+"] "+sb.toString());
......@@ -607,17 +623,14 @@ public class ExcelExport implements Closeable{
@Override
public void close() {
fieldTypes.clear();
if (wb instanceof SXSSFWorkbook){
((SXSSFWorkbook)wb).dispose();
}
Iterator<Class<?>> it = fieldTypes.iterator();
while(it.hasNext()){
Class<?> clazz = it.next();
try {
clazz.getMethod("clearCache").invoke(null);
} catch (Exception e) {
// 报错忽略,有可能没实现此方法
}
try {
wb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
......
......@@ -9,16 +9,17 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Map;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.formula.eval.ErrorEval;
......@@ -37,7 +38,7 @@ import org.springframework.web.multipart.MultipartFile;
import com.jeesite.common.callback.MethodCallback;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.collect.SetUtils;
import com.jeesite.common.collect.MapUtils;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.lang.StringUtils;
......@@ -45,11 +46,12 @@ import com.jeesite.common.reflect.ReflectUtils;
import com.jeesite.common.utils.excel.annotation.ExcelField;
import com.jeesite.common.utils.excel.annotation.ExcelField.Type;
import com.jeesite.common.utils.excel.annotation.ExcelFields;
import com.jeesite.common.utils.excel.fieldtype.FieldType;
/**
* 导入Excel文件(支持“XLS”和“XLSX”格式)
* @author ThinkGem
* @version 2020-2-19
* @version 2020-3-5
*/
public class ExcelImport implements Closeable {
......@@ -71,9 +73,9 @@ public class ExcelImport implements Closeable {
private int headerNum;
/**
* 用于清理缓存
* 存储字段类型临时数据
*/
private Set<Class<?>> fieldTypes = SetUtils.newHashSet();
private Map<Class<? extends FieldType>, FieldType> fieldTypes = MapUtils.newHashMap();
/**
* 构造函数
......@@ -263,9 +265,9 @@ public class ExcelImport implements Closeable {
try{
Cell cell = row.getCell(column);
if (cell != null){
if (cell.getCellTypeEnum() == CellType.NUMERIC){
if (cell.getCellType() == CellType.NUMERIC){
val = cell.getNumericCellValue();
if (HSSFDateUtil.isCellDateFormatted(cell)) {
if (DateUtil.isCellDateFormatted(cell)) {
val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
}else{
if ((Double) val % 1 > 0){
......@@ -274,17 +276,17 @@ public class ExcelImport implements Closeable {
val = new DecimalFormat("0").format(val);
}
}
}else if (cell.getCellTypeEnum() == CellType.STRING) {
}else if (cell.getCellType() == CellType.STRING) {
val = cell.getStringCellValue();
}else if (cell.getCellTypeEnum() == CellType.FORMULA){
}else if (cell.getCellType() == CellType.FORMULA){
try {
val = cell.getStringCellValue();
} catch (Exception e) {
FormulaEvaluator evaluator = cell.getSheet().getWorkbook()
.getCreationHelper().createFormulaEvaluator();
evaluator.evaluateFormulaCellEnum(cell);
evaluator.evaluateFormulaCell(cell);
CellValue cellValue = evaluator.evaluate(cell);
switch (cellValue.getCellTypeEnum()) {
switch (cellValue.getCellType()) {
case NUMERIC:
val = cellValue.getNumberValue();
break;
......@@ -301,9 +303,9 @@ public class ExcelImport implements Closeable {
val = cell.getCellFormula();
}
}
}else if (cell.getCellTypeEnum() == CellType.BOOLEAN){
}else if (cell.getCellType() == CellType.BOOLEAN){
val = cell.getBooleanCellValue();
}else if (cell.getCellTypeEnum() == CellType.ERROR){
}else if (cell.getCellType() == CellType.ERROR){
val = cell.getErrorCellValue();
}
}
......@@ -318,7 +320,7 @@ public class ExcelImport implements Closeable {
* @param cls 导入对象类型
* @param groups 导入分组
*/
public <E> List<E> getDataList(Class<E> cls, String... groups) throws InstantiationException, IllegalAccessException{
public <E> List<E> getDataList(Class<E> cls, String... groups) throws Exception{
return getDataList(cls, false, groups);
}
......@@ -328,7 +330,7 @@ public class ExcelImport implements Closeable {
* @param isThrowException 遇见错误是否抛出异常
* @param groups 导入分组
*/
public <E> List<E> getDataList(Class<E> cls, final boolean isThrowException, String... groups) throws InstantiationException, IllegalAccessException{
public <E> List<E> getDataList(Class<E> cls, final boolean isThrowException, String... groups) throws Exception{
return getDataList(cls, new MethodCallback() {
@Override
public Object execute(Object... params) {
......@@ -348,7 +350,8 @@ public class ExcelImport implements Closeable {
* @param isThrowException 遇见错误是否抛出异常
* @param groups 导入分组
*/
public <E> List<E> getDataList(Class<E> cls, MethodCallback exceptionCallback, String... groups) throws InstantiationException, IllegalAccessException{
@SuppressWarnings("unchecked")
public <E> List<E> getDataList(Class<E> cls, MethodCallback exceptionCallback, String... groups) throws Exception{
List<Object[]> annotationList = ListUtils.newArrayList();
// Get annotation field
Field[] fs = cls.getDeclaredFields();
......@@ -378,15 +381,15 @@ public class ExcelImport implements Closeable {
Collections.sort(annotationList, new Comparator<Object[]>() {
@Override
public int compare(Object[] o1, Object[] o2) {
return new Integer(((ExcelField)o1[0]).sort()).compareTo(
new Integer(((ExcelField)o2[0]).sort()));
return Integer.valueOf(((ExcelField)o1[0]).sort()).compareTo(
Integer.valueOf(((ExcelField)o2[0]).sort()));
};
});
//log.debug("Import column count:"+annotationList.size());
// Get excel data
List<E> dataList = ListUtils.newArrayList();
for (int i = this.getDataRowNum(); i < this.getLastDataRowNum(); i++) {
E e = (E)cls.newInstance();
E e = (E)cls.getDeclaredConstructor().newInstance();
Row row = this.getRow(i);
if (row == null){
continue;
......@@ -402,7 +405,7 @@ public class ExcelImport implements Closeable {
if (StringUtils.isNotBlank(ef.dictType())){
try{
Class<?> dictUtils = Class.forName("com.jeesite.modules.sys.utils.DictUtils");
val = dictUtils.getMethod("getDictValue", String.class, String.class,
val = dictUtils.getMethod("getDictValues", String.class, String.class,
String.class).invoke(null, ef.dictType(), val.toString(), "");
} catch (Exception ex) {
log.info("Get cell value ["+i+","+column+"] error: " + ex.toString());
......@@ -426,9 +429,9 @@ public class ExcelImport implements Closeable {
//log.debug("Import value type: ["+i+","+column+"] " + valType);
try {
if (StringUtils.isNotBlank(ef.attrName())){
if (ef.fieldType() != Class.class){
fieldTypes.add(ef.fieldType()); // 先存起来,方便完成后清理缓存
val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val);
if (ef.fieldType() != FieldType.class){
FieldType ft = getFieldType(ef.fieldType());
val = ft.getValue(ObjectUtils.toString(val));
}
}else{
if (val != null){
......@@ -447,6 +450,8 @@ public class ExcelImport implements Closeable {
val = Double.valueOf(val.toString());
}else if (valType == Float.class){
val = Float.valueOf(val.toString());
}else if (valType == BigDecimal.class){
val = new BigDecimal(val.toString());
}else if (valType == Date.class){
if (val instanceof String){
val = DateUtils.parseDate(val);
......@@ -454,15 +459,15 @@ public class ExcelImport implements Closeable {
val = DateUtil.getJavaDate((Double)val); // POI Excel 日期格式转换
}
}else{
if (ef.fieldType() != Class.class){
fieldTypes.add(ef.fieldType()); // 先存起来,方便完成后清理缓存
val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val.toString());
if (ef.fieldType() != FieldType.class){
FieldType ft = getFieldType(ef.fieldType());
val = ft.getValue(ObjectUtils.toString(val));
}else{
// 如果没有指定 fieldType,切自行根据类型查找相应的转换类(com.jeesite.common.utils.excel.fieldtype.值的类名+Type)
Class<?> fieldType2 = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
Class<? extends FieldType> fieldType = (Class<? extends FieldType>)Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
"fieldtype."+valType.getSimpleName()+"Type"));
fieldTypes.add(fieldType2); // 先存起来,方便完成后清理缓存
val = fieldType2.getMethod("getValue", String.class).invoke(null, val.toString());
FieldType ft = getFieldType(fieldType);
val = ft.getValue(ObjectUtils.toString(val));
}
}
}
......@@ -496,16 +501,22 @@ public class ExcelImport implements Closeable {
return dataList;
}
private FieldType getFieldType(Class<? extends FieldType> fieldType) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
FieldType ft = fieldTypes.get(fieldType);
if (ft == null) {
ft = fieldType.getDeclaredConstructor().newInstance();
fieldTypes.put(fieldType, ft);
}
return ft;
}
@Override
public void close() {
Iterator<Class<?>> it = fieldTypes.iterator();
while(it.hasNext()){
Class<?> clazz = it.next();
try {
clazz.getMethod("clearCache").invoke(null);
} catch (Exception e) {
// 报错忽略,有可能没实现此方法
}
public void close() throws IOException {
fieldTypes.clear();
try {
wb.close();
} catch (IOException e) {
e.printStackTrace();
}
}
......
......@@ -8,10 +8,12 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.jeesite.common.utils.excel.fieldtype.FieldType;
/**
* Excel注解定义
* @author ThinkGem
* @version 2013-03-10
* @version 2020-3-5
*/
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
......@@ -59,6 +61,11 @@ public @interface ExcelField {
*/
int width() default -1;
/**
* 指定导出列宽可以显示的字符个数(words*256=width,1个汉字占2个字符) v4.2.0
*/
int words() default -1;
/**
* 导出字段字段排序(升序)
*/
......@@ -79,12 +86,12 @@ public @interface ExcelField {
* MoneyType.class 金额类型转换(保留两位)
* DateTimeType.class 日期时间类型转换 yyyy-MM-dd HH:mm:ss
*/
Class<?> fieldType() default Class.class;
Class<? extends FieldType> fieldType() default FieldType.class;
/**
* 数值格式(例如:数值:0.00;日期:yyyy-MM-dd;金额:¥#,##0.00)
*/
String dataFormat() default "@";
String dataFormat() default "";
/**
* 字段归属组(针对每一种业务的导入、导出) imp、exp
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment