Compare commits

...

64 Commits

Author SHA1 Message Date
thinkgem
dc10f8670b update 2023-04-06 23:59:56 +08:00
thinkgem
f429bf1c83 5.3.1 2023-04-06 15:09:33 +08:00
thinkgem
3086736d4e update 2023-04-05 18:53:38 +08:00
thinkgem
5562a98a0e update 2023-04-04 11:32:23 +08:00
thinkgem
cd4fc57eb8 update 2023-04-03 11:27:43 +08:00
thinkgem
bdfd9d8b28 修正cloud工程生成模板的启动脚本路径问题 2023-04-03 11:27:33 +08:00
thinkgem
8336b993ac 优化空值针容错 2023-04-03 11:26:54 +08:00
thinkgem
6757958342 update 2023-03-28 09:42:23 +08:00
thinkgem
b40de7ec25 update README.md 2023-03-28 09:40:47 +08:00
thinkgem
c2e71cb80a 登录超时提示信息调整 2023-03-27 09:50:31 +08:00
thinkgem
8b0453b0c0 细节优化 2023-03-25 11:43:03 +08:00
thinkgem
532a20ed6f upgrade spring boot 2.7.10 2023-03-24 23:45:08 +08:00
thinkgem
f3b2e2204b 默认不继承上级任务的优先级,根据需要模型里设置,或每次审批的时候根据需要指定。 2023-03-20 15:27:39 +08:00
thinkgem
09a57cb928 增加 mybatis.scanTypeAliasesBasePackage 配置 2023-03-20 15:21:56 +08:00
thinkgem
c59564b393 修正oauth2绑定账号后的没有跳转到vue页面的问题 2023-03-20 13:12:29 +08:00
thinkgem
0a2c29abc3 update README.md 2023-03-17 15:42:17 +08:00
thinkgem
3b04eff399 增加子表编辑的另一种实现例子 2023-03-16 20:19:41 +08:00
thinkgem
ee3adf6fee update //<% 2023-03-16 19:20:27 +08:00
thinkgem
b9f614479b update sysDesktop.html 2023-03-15 16:59:25 +08:00
thinkgem
563fa84f49 优化CMS各种url生成调用 2023-03-15 11:59:31 +08:00
thinkgem
513fd4ca50 优化vue代码生成模板子表验证提示信息 2023-03-13 17:44:14 +08:00
thinkgem
1e4c9914fa update 2023-03-08 17:39:20 +08:00
thinkgem
44d14f495b CMS网站主题优化 2023-03-07 13:50:57 +08:00
thinkgem
07ac6b98b1 CookieUtils增加Cookie参数配置,SameSite可为空 2023-03-07 10:42:12 +08:00
thinkgem
71ed21c0a3 5.3.0 2023-03-06 10:23:43 +08:00
thinkgem
71126077d8 update README.md 2023-03-06 10:22:13 +08:00
thinkgem
87181377ea update 2023-03-06 10:21:45 +08:00
thinkgem
b02783e0da productVersion: V5.3 2023-03-06 10:21:14 +08:00
thinkgem
5214f55208 jeesite client 2023-03-06 10:19:05 +08:00
thinkgem
97d19ab350 update 2023-03-06 10:18:30 +08:00
thinkgem
2bf55f1db1 排除刷新主框架页日志记录 2023-03-06 09:58:28 +08:00
thinkgem
c7b2512a72 visual v2.5 2023-03-05 22:12:25 +08:00
thinkgem
82e98f563f upgrade spring boot 2.7.9 2023-03-02 09:33:07 +08:00
thinkgem
f75746435e 修正内容管理文字扩展字段不能保存问题 #I6IBXO 2023-03-02 09:32:44 +08:00
thinkgem
d14e5259bf 分离端登录页增加租户选择框(当租户内账号唯一的情况下使用) 2023-02-28 20:10:56 +08:00
thinkgem
689438d704 消息推送开启状态反馈给分离前端 2023-02-28 11:50:45 +08:00
thinkgem
0954638b3a 当只给用户 内容发布 菜单授权时,栏目树没有权限加载问题 2023-02-27 12:28:42 +08:00
thinkgem
c81d96a6d4 CmsUtils.getArticleList 的 isQueryArticleData 参数不生效问题 #I6HN74 2023-02-27 10:35:35 +08:00
thinkgem
0a95c15ff0 新增自动扫描@Table的列注释到Swagger在线文档,并补充字段说明。 2023-02-27 09:59:45 +08:00
thinkgem
b6e9151be5 默认点击重置按钮即查询 2023-02-27 09:57:47 +08:00
thinkgem
de61f75eaa update 2023-02-27 09:55:11 +08:00
thinkgem
d3d338cc70 Page 增加构造,传递 isPaging 可快速设置是否分页 2023-02-26 23:06:07 +08:00
thinkgem
a5361bf1e4 删除过时方法 2023-02-24 16:06:13 +08:00
thinkgem
2683533a50 语法变更 getSqlMap() 替换为 sqlMap() 2023-02-23 19:32:45 +08:00
thinkgem
b22f4cd5de 语法变更 getCurrentUser、setCurrentUser 函数替换为 currentUser 2023-02-23 19:08:00 +08:00
thinkgem
b658ac5473 新增参数 oauth2.successUrl 2023-02-22 10:23:52 +08:00
thinkgem
a955847d06 代码优化 2023-02-22 10:23:31 +08:00
thinkgem
d24e70d69c 支持带域名的地址外部跳转 2023-02-22 10:23:15 +08:00
thinkgem
19e4f86fe6 update 2023-02-22 10:22:29 +08:00
thinkgem
668c124126 优化帮助提示 2023-02-21 10:03:55 +08:00
thinkgem
66e4e47c4a format code 2023-02-21 10:03:34 +08:00
thinkgem
fa39e1f593 修正CAS中央认证服务退出后,没有退出客户端的问题 2023-02-21 10:02:53 +08:00
thinkgem
d9f9b17ece 分页参数不正确的时候,优化返回错误的提示信息。 2023-02-15 22:34:58 +08:00
thinkgem
89f8d8aed8 preferred-networks 2023-02-14 15:56:44 +08:00
thinkgem
ee50473830 Java 反射采用 ASM 并增加缓存,高并发下大幅度性能提升 2023-02-13 13:49:15 +08:00
thinkgem
fda9e9b571 用户管理增加性别维护 2023-02-13 13:44:37 +08:00
thinkgem
99d2eb4349 Merge remote-tracking branch 'origin/v5.temp' into v5.temp 2023-02-11 18:15:50 +08:00
thinkgem
dd9a058d63 @FunctionalInterface 2023-02-11 18:15:37 +08:00
thinkgem
ebb6f0ff26 @FunctionalInterface 2023-02-08 12:52:55 +08:00
thinkgem
dd81693b36 添加缺少的字段 2023-02-06 21:32:27 +08:00
thinkgem
38ed0fac97 优化格式,秒后增加毫秒显示,补全显示天时分、时分秒毫秒 2023-02-06 17:04:53 +08:00
thinkgem
9485e59bc6 update DaoMapperTest.java 2023-02-02 23:38:21 +08:00
thinkgem
969b5945c7 next 2023-02-01 13:00:11 +08:00
thinkgem
691c566031 update 2023-01-31 15:23:47 +08:00
150 changed files with 3498 additions and 1123 deletions

View File

@@ -4,7 +4,7 @@
</p>
<h3 align="center" style="margin:30px 0 30px;font-weight:bold;font-size:30px;">快速开发平台 - Spring Boot</h3>
<p align="center">
<a href="https://jeesite.com/docs/upgrade/" target="__blank"><img alt="JeeSite-V5.2" src="https://img.shields.io/badge/JeeSite-V5.2-success.svg"></a>
<a href="https://jeesite.com/docs/upgrade/" target="__blank"><img alt="JeeSite-V5.3" src="https://img.shields.io/badge/JeeSite-V5.3-success.svg"></a>
<a href="https://spring.io/projects/spring-boot#learn" target="__blank"><img alt="SpringBoot-2.7" src="https://img.shields.io/badge/SpringBoot-2.7-blue.svg"></a>
<a href="https://gitee.com/thinkgem/jeesite4/stargazers" target="__blank"><img alt="star" src="https://gitee.com/thinkgem/jeesite4/badge/star.svg?theme=dark"></a>
<a href="https://gitee.com/thinkgem/jeesite4/members" target="__blank"><img alt="fork" src="https://gitee.com/thinkgem/jeesite4/badge/fork.svg?theme=dark"></a>
@@ -23,6 +23,9 @@
![JeeSite微信公众号](https://images.gitee.com/uploads/images/2020/0727/091951_a3ab258c_6732.jpeg "JeeSite微信公众号")
* 源码仓库地址:<https://gitee.com/thinkgem/jeesite4>
* 分离版前端源码仓库:<https://gitee.com/thinkgem/jeesite-vue>
## 平台介绍
JeeSite 快速开发平台,不仅仅是一个后台开发框架,它是一个企业级快速开发解决方案,后端基于经典组合 Spring Boot、Shiro、MyBatis前端采用 Beetl、Bootstrap、AdminLTE 经典开发模式,或者分离版 Vue3、Vite、Ant Design Vue、TypeScript、Vben Admin 最先进技术栈。提供在线代码生成功能可自动创建业务模块工程和微服务模块工程自动生成前端代码和后端代码包括功能模块如组织机构、角色用户、菜单及按钮授权、数据权限、系统参数、内容管理、工作流等。采用松耦合设计微内核和插件架构模块增减便捷界面无刷新一键换肤众多账号安全设置密码策略文件在线预览消息推送多元化第三方登录在线定时任务配置支持集群支持SAAS支持多数据源支持读写分离、分库分表支持微服务应用。
@@ -43,6 +46,8 @@ JeeSite 是一个低代码开发平台,具有较高的封装度、扩展性,
大家都在用 Spring也在学习 Spring 的优点Spring 提供了较好的扩展性,可又有多少人去修改它的源代码呢,退一步说,大家去修改了 Spring 的源码反而会对未来升级造成很大困扰您说不是呢这样的例子很多所以不要纠结我们非常注重这一点JeeSite 也一样具备强大的扩展性。
为什么说 JeeSite 比较易于学习JeeSite 很好的把握了设计的 “度”,避免过度设计的情况。过度设计是在产品设计过程中忽略了产品和用户的实际需求,反而带来了不必要的复杂性,而忽略了系统的学习、开发和维护成本。
* 至今 JeeSite 平台架构已经非常稳定。
* JeeSite 精益求精,用心打磨每一个细节。
* JeeSite 是一个专业的平台,是一个让你使用放心的平台。
@@ -51,7 +56,7 @@ JeeSite 是一个低代码开发平台,具有较高的封装度、扩展性,
## 技术选型
* 主框架Spring Boot 2.7、Spring Framework 5.3、Apache Shiro 1.10、J2Cache
* 主框架Spring Boot 2.7、Spring Framework 5.3、Apache Shiro 1.11、J2Cache
* 持久层Apache MyBatis 3.5、Hibernate Validator 6.2、Alibaba Druid 1.2
* 视图层Spring MVC 5.3、Beetl 3.10替换JSP、Bootstrap 3.3、AdminLTE 2.4
* 前端组件jQuery 3.5、jqGrid 4.7、layer 3.5、zTree 3.5、jQuery Validation
@@ -72,11 +77,12 @@ JeeSite 是一个低代码开发平台,具有较高的封装度、扩展性,
## 生态系统
* 分布式微服务系统Spring Cloud<https://gitee.com/thinkgem/jeesite4-cloud>
* 分布式微服务Spring Cloud<https://gitee.com/thinkgem/jeesite4-cloud>
* Flowable业务流程引擎BPM<http://jeesite.com/docs/bpm/>
* JFlow工作流引擎<https://gitee.com/thinkgem/jeesite4-jflow> <http://ccflow.org>
* Flowable业务流程模块BPM<http://jeesite.com/docs/bpm/>
* 内容管理模块CMS<https://gitee.com/thinkgem/jeesite4-cms>
* 内容管理模块CMS<https://gitee.com/thinkgem/jeesite4/tree/v5.3/modules/cms>
* 手机端移动端:<https://gitee.com/thinkgem/jeesite4-uniapp>
* PC客户端程序<https://gitee.com/thinkgem/jeesite-client>
* Vue3分离版本<https://gitee.com/thinkgem/jeesite-vue>
## 快速体验
@@ -88,7 +94,7 @@ JeeSite 是一个低代码开发平台,具有较高的封装度、扩展性,
### 本地运行
1. 环境准备:`JDK 1.8 or 11、17``Maven 3.6+`、使用 `MySQL 5.7 or 8.0` 数据库、[其它数据库](https://jeesite.com/docs/technology/#_8、已支持数据库)
2. 下载源码:<https://gitee.com/thinkgem/jeesite4/repository/archive/v5.2.zip> 并解压
2. 下载源码:<https://gitee.com/thinkgem/jeesite4/repository/archive/v5.3.zip> 并解压
3. 打开文件:`/web/src/main/resources/config/application.yml` 配置JDBC连接
4. 执行脚本:`/web/bin/init-data.bat` 初始化数据库
5. 执行脚本:`/web/bin/run-tomcat.bat` 启动服务即可
@@ -99,7 +105,7 @@ JeeSite 是一个低代码开发平台,具有较高的封装度、扩展性,
### 快速运行
1. 环境准备:`JDK 1.8 or 11、17``Maven 3.6+`、无需准备数据库(使用内嵌 H2 DB
2. 下载源码:<https://gitee.com/thinkgem/jeesite4/repository/archive/v5.0_dev.zip> 并解压
2. 下载源码:<https://gitee.com/thinkgem/jeesite4/repository/archive/v5.3.zip> 并解压
3. 执行脚本:`/web-fast/bin/run-tomcat.bat` 启动服务即可(自动初始化库)
4. 浏览器访问:<http://127.0.0.1:8980/js/> 账号 system 密码 admin
5. 部署常见问题:<https://jeesite.com/docs/faq/>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>5.2.1-SNAPSHOT</version>
<version>5.3.1-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>

View File

@@ -8,6 +8,7 @@ package com.jeesite.common.callback;
* 方法回调接口
* @author ThinkGem
*/
@FunctionalInterface
public interface MethodCallback {
Object execute(Object... params);

View File

@@ -5,15 +5,10 @@
*/
package com.jeesite.common.codec;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.lang.ExceptionUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.web.http.ServletUtils;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
@@ -21,9 +16,13 @@ import org.apache.commons.text.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.lang.ExceptionUtils;
import com.jeesite.common.lang.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 封装各种格式的编码解码工具类.
@@ -238,7 +237,8 @@ public class EncodeUtils {
&& !StringUtils.contains(value, "id=\"FormHtml\"") // JFlow
&& !(StringUtils.startsWith(value, "{") && StringUtils.endsWith(value, "}")) // JSON Object
&& !(StringUtils.startsWith(value, "[") && StringUtils.endsWith(value, "]")) // JSON Array
&& !(request != null && StringUtils.contains(request.getRequestURI(), "/ureport/")) // UReport
&& !(StringUtils.containsAny((request != null ? request : ServletUtils.getRequest())
.getRequestURI(), "/ureport/", "/visual/")) // UReport、Visual
){
StringBuilder sb = new StringBuilder();
for (int i = 0; i < value.length(); i++) {

View File

@@ -65,17 +65,26 @@ public class ListUtils extends org.apache.commons.collections.ListUtils {
@SafeVarargs
public static <E> ArrayList<E> newArrayList(E... elements) {
if (elements == null) {
return newArrayList();
}
ArrayList<E> list = new ArrayList<E>(elements.length);
Collections.addAll(list, elements);
return list;
}
public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
if (elements == null) {
return newArrayList();
}
return (elements instanceof Collection) ? new ArrayList<E>(cast(elements))
: newArrayList(elements.iterator());
}
public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) {
if (elements == null) {
return newArrayList();
}
ArrayList<E> list = newArrayList();
addAll(list, elements);
return list;
@@ -86,6 +95,9 @@ public class ListUtils extends org.apache.commons.collections.ListUtils {
}
public static <E> LinkedList<E> newLinkedList(Iterable<? extends E> elements) {
if (elements == null) {
return newLinkedList();
}
LinkedList<E> list = newLinkedList();
addAll(list, elements);
return list;
@@ -96,6 +108,9 @@ public class ListUtils extends org.apache.commons.collections.ListUtils {
}
public static <E> CopyOnWriteArrayList<E> newCopyOnWriteArrayList(Iterable<? extends E> elements) {
if (elements == null) {
return new CopyOnWriteArrayList<E>();
}
Collection<? extends E> elementsCollection = (elements instanceof Collection)
? cast(elements) : newArrayList(elements);
return new CopyOnWriteArrayList<E>(elementsCollection);
@@ -106,6 +121,9 @@ public class ListUtils extends org.apache.commons.collections.ListUtils {
}
private static <T> boolean addAll(Collection<T> addTo, Iterator<? extends T> iterator) {
if (addTo == null || iterator == null) {
return false;
}
boolean wasModified = false;
while (iterator.hasNext()) {
wasModified |= addTo.add(iterator.next());
@@ -114,6 +132,9 @@ public class ListUtils extends org.apache.commons.collections.ListUtils {
}
public static <T> boolean addAll(Collection<T> addTo, Iterable<? extends T> elementsToAdd) {
if (addTo == null || elementsToAdd == null) {
return false;
}
if (elementsToAdd instanceof Collection) {
Collection<? extends T> c = cast(elementsToAdd);
return addTo.addAll(c);
@@ -409,22 +430,19 @@ public class ListUtils extends org.apache.commons.collections.ListUtils {
final String[] ss = orderBy.trim().split(" ");
if (ss != null){
final String t = ss.length==2 ? ss[1] : "asc";
Collections.sort(list, new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
String s1 = StringUtils.EMPTY, s2 = StringUtils.EMPTY;
if (o1 instanceof Map){
s1 = ObjectUtils.toString(((Map)o1).get(ss[0]));
s2 = ObjectUtils.toString(((Map)o2).get(ss[0]));
}else{
s1 = ObjectUtils.toString(ReflectUtils.invokeGetter(o1, ss[0]));
s2 = ObjectUtils.toString(ReflectUtils.invokeGetter(o2, ss[0]));
}
if ("asc".equalsIgnoreCase(t)){
return s1.compareTo(s2);
}else{
return s2.compareTo(s1);
}
Collections.sort(list, (o1, o2) -> {
String s1, s2;
if (o1 instanceof Map){
s1 = ObjectUtils.toString(((Map)o1).get(ss[0]));
s2 = ObjectUtils.toString(((Map)o2).get(ss[0]));
}else{
s1 = ObjectUtils.toString(ReflectUtils.invokeGetter(o1, ss[0]));
s2 = ObjectUtils.toString(ReflectUtils.invokeGetter(o2, ss[0]));
}
if ("asc".equalsIgnoreCase(t)){
return s1.compareTo(s2);
}else{
return s2.compareTo(s1);
}
});
}

View File

@@ -4,25 +4,14 @@
*/
package com.jeesite.common.collect;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.jeesite.common.lang.StringUtils;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import com.jeesite.common.lang.StringUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Map工具类实现 Map <-> Bean 互相转换
@@ -85,8 +74,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 Exception,
InvocationTargetException, NoSuchMethodException, InstantiationException {
public static <T, V> List<T> toObjectList(Class<T> clazz, List<HashMap<String, V>> list) throws Exception {
List<T> retList = new ArrayList<T>();
if (list != null && !list.isEmpty()) {
for (HashMap<String, V> m : list) {
@@ -101,8 +89,7 @@ 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 Exception,
InvocationTargetException {
public static <T, V> T toObject(Class<T> clazz, Map<String, V> map) throws Exception {
T object = clazz.getDeclaredConstructor().newInstance();
return toObject(object, map);
}
@@ -113,15 +100,13 @@ 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 Exception,
InvocationTargetException {
public static <T, V> T toObject(Class<T> clazz, Map<String, V> map, boolean toCamelCase) throws Exception {
T object = clazz.getDeclaredConstructor().newInstance();
return toObject(object, map, toCamelCase);
}
/**
* 将Map转换为Object
* @param clazz 目标对象的类
* @param map 待转换Map
*/
public static <T, V> T toObject(T object, Map<String, V> map) throws InstantiationException, IllegalAccessException, InvocationTargetException {
@@ -203,9 +188,7 @@ public class MapUtils extends org.apache.commons.collections.MapUtils {
/**
* 转换成Map并提供字段命名驼峰转平行
* @param clazz 目标对象所在类
* @param object 目标对象
* @param map 待转换Map
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException

View File

@@ -4,36 +4,26 @@
*/
package com.jeesite.common.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import javax.activation.MimetypesFileTypeMap;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.lang.StringUtils;
import net.sf.jmimemagic.Magic;
import net.sf.jmimemagic.MagicMatch;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.lang.StringUtils;
import net.sf.jmimemagic.Magic;
import net.sf.jmimemagic.MagicMatch;
import javax.activation.MimetypesFileTypeMap;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
/**
* 文件操作工具类
@@ -41,6 +31,7 @@ import net.sf.jmimemagic.MagicMatch;
* @author ThinkGem
* @version 2015-3-16
*/
@SuppressWarnings("deprecation")
public class FileUtils extends org.apache.commons.io.FileUtils {
private static Logger logger = LoggerFactory.getLogger(FileUtils.class);

View File

@@ -14,19 +14,11 @@ import java.util.Date;
public class TimeUtils {
public static final String[] CN = new String[] {"毫秒", "", "", "", ""};
public static final String[] EN = new String[] {" millisecond ", " second", " minute", " hour", " day"};
public static final String[] EN = new String[] {" millisecond ", " second ", " minute ", " hour ", " day "};
public static final String[] AGO_CN = new String[] {"刚刚", "秒前", "分钟前", "小时前", "天前"};
public static final String[] AGO_EN = new String[] {"just now", " seconds ago", " minutes ago", " hours ago", " days ago"};
/**
* 将毫秒数转换为xx天xx时xx分xx秒v5.1 替换为 formatTime
*/
@Deprecated
public static String formatDateAgo(long millisecond) {
return formatTime(millisecond, CN);
}
/**
* 将毫秒数转换为xx天xx时xx分xx秒
*/
@@ -52,21 +44,33 @@ public class TimeUtils {
sb.append(ms).append(lang[0]);
} else {
if (day > 0) {
ms -= day * dd;
sb.append(day).append(lang[4]);
}
if (hour > 0) {
if (day > 0 || hour > 0) {
ms -= hour * hh;
sb.append(hour).append(lang[3]);
}
if (minute > 0) {
if (day > 0 || hour > 0 || minute > 0) {
ms -= minute * mi;
sb.append(minute).append(lang[2]);
}
if (second > 0) {
sb.append(second).append(lang[1]);
if (hour > 0 || minute > 0 || second > 0) {
ms -= second * ss;
sb.append(second).append(".").append(ms).append(lang[1]);
}
}
return sb.toString();
}
// /**
// * 将毫秒数转换为xx天xx时xx分xx秒v5.1 替换为 formatTime
// */
// @Deprecated
// public static String formatDateAgo(long millisecond) {
// return formatTime(millisecond, CN);
// }
/**
* 将过去的时间转为为刚刚xx秒xx分钟xx小时前、xx天前大于3天的显示日期
*/

View File

@@ -33,18 +33,18 @@ public class EmailUtils {
return send(fromAddress, fromPassword, fromHostName, smtpPort, sslOnConnect, sslSmtpPort, toAddress, subject, content);
}
/**
* 发送邮件
* @param toAddress 接收地址
* @param subject 标题
* @param content 内容
* @return
*/
@Deprecated
public static boolean send(String fromAddress, String fromPassword, String fromHostName,
String sslOnConnect, String sslSmtpPort, String toAddress, String subject, String content) {
return send(fromAddress, fromPassword, fromHostName, 25, sslOnConnect, sslSmtpPort, toAddress, subject, content);
}
// /**
// * 发送邮件
// * @param toAddress 接收地址
// * @param subject 标题
// * @param content 内容
// * @return
// */
// @Deprecated
// public static boolean send(String fromAddress, String fromPassword, String fromHostName,
// String sslOnConnect, String sslSmtpPort, String toAddress, String subject, String content) {
// return send(fromAddress, fromPassword, fromHostName, 25, sslOnConnect, sslSmtpPort, toAddress, subject, content);
// }
/**
* 发送邮件

View File

@@ -1,49 +1,39 @@
/**
* Copyright (c) 2005-2012 springside.org.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Copyright (c) 2013-Now http://jeesite.com、springside.org.cn All rights reserved.
* No deletion without permission, or be held responsible to law.
*/
package com.jeesite.common.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.Map;
import com.jeesite.common.collect.MapUtils;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.reflect.asm.MethodAccess;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.poi.ss.usermodel.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.lang.ObjectUtils;
import java.lang.reflect.*;
import java.util.Date;
import java.util.Map;
/**
* 反射工具类.
* 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
* @author calvin、ThinkGem
* @version 2015-11-12
* @version 2023-2-6
*/
@SuppressWarnings("rawtypes")
public class ReflectUtils {
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
private static final String CGLIB_CLASS_SEPARATOR = "$$";
private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
private static Class baseEntityClass = null;
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
private static final String CGLIB_CLASS_SEPARATOR = "$$";
private static Map<String, Map<String, Method>> methodClassCache = MapUtils.newHashMap();
/**
* 调用Getter方法
* 调用Getter方法v5.3.0+ 变更为ASM方式不支持私有方法调用高性能
* 支持多级,如:对象名.对象名.方法,
* 支持静态类及方法调用,
* 支持Map
@@ -56,20 +46,21 @@ public class ReflectUtils {
object = ((Map)obj).get(name);
}else{
String methodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = invokeMethod(object, methodName, new Class[] {}, new Object[] {});
// object = invokeMethodByName(object, methodName, new Object[] {});
object = invokeMethodByAsm(object, methodName);
}
}
return (E)object;
}
/**
* 调用Setter方法仅匹配方法名
* 调用Setter方法仅匹配方法名v5.3.0+ 变更为ASM方式不支持私有方法调用高性能
* 支持多级,如:对象名.对象名.方法,
* 支持静态类及方法调用,
* 支持Map
*/
@SuppressWarnings("unchecked")
public static <E> void invokeSetter(Object obj, String propertyName, E value) {
public static <E> void invokeSetter(Object obj, String propertyName, Object... args) {
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i=0; i<names.length; i++){
@@ -77,35 +68,37 @@ public class ReflectUtils {
if (obj instanceof Map){
object = ((Map)obj).get(names[i]);
}else{
String methodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
Object childObj = invokeMethod(object, methodName, new Class[] {}, new Object[] {});
String methodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
//Object childObj = invokeMethod(object, methodName, new Class[] {}, new Object[] {});
Object childObj = invokeMethodByAsm(object, methodName);
// 如果 get 获取对象为空,并且返回值类型继承自 BaseEntity则 new 对象,并通过 set 赋予它
if (childObj == null && object != null){
Method method = getAccessibleMethod(object, methodName, new Class[] {});
if (method != null) {
Class<?> returnType = method.getReturnType();
try {
if (baseEntityClass == null) {
baseEntityClass = Class.forName("com.jeesite.common.entity.BaseEntity");
}
if (baseEntityClass.isAssignableFrom(returnType)) {
childObj = returnType.getDeclaredConstructor().newInstance();
methodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, methodName, new Object[] { childObj });
}
} catch (Exception e) {
e.printStackTrace();
}
try {
//Method method = getAccessibleMethodByName(object, methodName, 0);
//if (method == null) { return; }
//Class<?> returnType = method.getReturnType();
System.out.println(object.getClass());
MethodAccess ma = MethodAccess.get(object.getClass());
Class<?> returnType = ma.getReturnTypes()[ma.getIndex(methodName)];
childObj = returnType.getDeclaredConstructor().newInstance();
methodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
//invokeMethodByName(object, methodName, new Object[] { childObj });
ma.invoke(object, methodName, childObj);
} catch (Exception e) {
// 如果找不到类或方法,则不报错,直接返回。
logger.debug(object.getClass().getName(), e);
return;
}
}
object = childObj;
}
}else{
if (obj instanceof Map){
((Map)obj).put(names[i], value);
((Map)obj).put(names[i], args != null && args.length == 1 ? args[0] : args);
}else{
String methodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, methodName, new Object[] { value });
//invokeMethodByName(object, methodName, new Object[] { value });
invokeMethodByAsm(object, methodName, args);
}
}
}
@@ -179,17 +172,16 @@ public class ReflectUtils {
}
/**
* 直接调用对象方法无视private/protected修饰符
* 根据方法名和值,直接调用对象方法无视private/protected修饰符
* 用于一次性调用的情况否则应使用getAccessibleMethodByName()函数获得Method后反复调用
* 只匹配函数名,如果有多个同名函数调用第一个,
* 支持静态类及方法调用
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object... args) {
Method method = getAccessibleMethodByName(obj, methodName, args.length);
if (method == null) {
// 如果为空不报错,直接返回空。
// throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
// 如果为空不报错,直接返回空。 throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
if (obj != null) {
logger.debug("在 [" + (obj.getClass() == Class.class ? obj : obj.getClass()) + "] 中,没有找到 [" + methodName + "] 方法 ");
}
@@ -198,31 +190,7 @@ public class ReflectUtils {
try {
// 类型转换(将参数数据类型转换为目标方法参数类型)
Class<?>[] cs = method.getParameterTypes();
for (int i=0; i<cs.length; i++){
if (args[i] != null && !args[i].getClass().equals(cs[i])){
if (cs[i] == String.class){
args[i] = ObjectUtils.toString(args[i]);
if(StringUtils.endsWith((String)args[i], ".0")){
args[i] = StringUtils.substringBefore((String)args[i], ".0");
}
}else if (cs[i] == Integer.class){
args[i] = ObjectUtils.toInteger(args[i]);
}else if (cs[i] == Long.class){
args[i] = ObjectUtils.toLong(args[i]);
}else if (cs[i] == Double.class){
args[i] = ObjectUtils.toDouble(args[i]);
}else if (cs[i] == Float.class){
args[i] = ObjectUtils.toFloat(args[i]);
}else if (cs[i] == Date.class){
if (args[i] instanceof String){
args[i] = DateUtils.parseDate(args[i]);
}else{
// POI Excel 日期格式转换
args[i] = DateUtil.getJavaDate((Double)args[i]);
}
}
}
}
methodParameterTypesConverter(cs, args);
return (E)method.invoke(obj.getClass() == Class.class ? null : obj, args);
} catch (Exception e) {
String msg = "method: "+method+", obj: "+obj+", args: "+args+"";
@@ -230,18 +198,79 @@ public class ReflectUtils {
}
}
/**
* 根据方法名和值直接调用对象方法v5.3.0+ ASM方式不支持私有方法调用高性能
* 支持静态类及方法调用
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethodByAsm(final Object obj, final String methodName, final Object... args) {
Object object = obj;
if (object == null){
return null;
}
Class<?> clazz = object.getClass();
if (clazz == Class.class){
clazz = (Class) object;
object = null;
}
try {
MethodAccess ma = MethodAccess.get(clazz);
int idx = ma.getIndex(methodName);
Class<?>[] cs = ma.getParameterTypes()[idx];
methodParameterTypesConverter(cs, args);
return (E)ma.invoke(object, idx, args);
} catch (IllegalArgumentException e) {
// 如果找不到类或方法,则不报错,直接返回。
logger.debug(clazz.getName(), e);
return null;
}
}
/**
* 方法的参数类型转换
*/
private static void methodParameterTypesConverter(Class<?>[] cs, Object[] args) {
for (int i = 0; i< cs.length; i++){
if (args[i] != null && !args[i].getClass().equals(cs[i])){
if (cs[i] == String.class){
args[i] = ObjectUtils.toString(args[i]);
if(StringUtils.endsWith((String) args[i], ".0")){
args[i] = StringUtils.substringBefore((String) args[i], ".0");
}
}else if (cs[i] == Integer.class){
args[i] = ObjectUtils.toInteger(args[i]);
}else if (cs[i] == Long.class){
args[i] = ObjectUtils.toLong(args[i]);
}else if (cs[i] == Double.class){
args[i] = ObjectUtils.toDouble(args[i]);
}else if ( cs[i] == Float.class){
args[i] = ObjectUtils.toFloat(args[i]);
}else if (cs[i] == Date.class){
if (args[i] instanceof String){
args[i] = DateUtils.parseDate(args[i]);
}else if (args[i] instanceof Double){
// POI Excel 日期格式转换
args[i] = DateUtil.getJavaDate((Double) args[i]);
}
}else{
System.out.println(cs[i] + " " + args[i]);
}
}
}
}
/**
* 循环向上转型获取对象的DeclaredField并强制设置为可访问
* 如向上转型到Object仍无法找到返回null
*/
public static Field getAccessibleField(final Object obj, final String fieldName) {
// 为空不报错。直接返回 null
// Validate.notNull(obj, "object can't be null");
// 为空不报错。直接返回 null // Validate.notNull(obj, "object can't be null");
if (obj == null){
return null;
}
Validate.notBlank(fieldName, "fieldName can't be blank");
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {
Class<?> clazz = obj.getClass();
for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Field field = superClass.getDeclaredField(fieldName);
makeAccessible(field);
@@ -262,8 +291,7 @@ public class ReflectUtils {
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes) {
// 为空不报错。直接返回 null
// Validate.notNull(obj, "object can't be null");
// 为空不报错。直接返回 null // Validate.notNull(obj, "object can't be null");
if (obj == null){
return null;
}
@@ -272,9 +300,9 @@ public class ReflectUtils {
clazz = (Class) obj;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = clazz; searchType != Object.class; searchType = searchType.getSuperclass()) {
for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
Method method = superClass.getDeclaredMethod(methodName, parameterTypes);
makeAccessible(method);
return method;
} catch (NoSuchMethodException e) {
@@ -285,15 +313,27 @@ public class ReflectUtils {
return null;
}
/**
* 缓存方法类,因 for methods 比较耗时,提高性能
*/
private static Map<String, Method> getMethodClassCache(String className) {
Map<String, Method> classCache = methodClassCache.get(className);
if (classCache == null) {
classCache = MapUtils.newHashMap();
methodClassCache.put(className, classCache);
}
return classCache;
}
/**
* 循环向上转型获取对象的DeclaredMethod并强制设置为可访问
* 如向上转型到Object仍无法找到返回null
* 只匹配函数名。
* 用于方法需要被多次调用的情况先使用本函数先取得Method然后调用Method.invoke(Object obj, Object... args)
* 增加缓存提升性能
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) {
// 为空不报错。直接返回 null
// Validate.notNull(obj, "object can't be null");
// 为空不报错。直接返回 null // Validate.notNull(obj, "object can't be null");
if (obj == null){
return null;
}
@@ -302,11 +342,18 @@ public class ReflectUtils {
clazz = (Class) obj;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = clazz; searchType != Object.class; searchType = searchType.getSuperclass()) {
Method[] methods = searchType.getDeclaredMethods();
Map<String, Method> methodCache = getMethodClassCache(clazz.getName());
String cacheKey = methodName + "#" + argsNum;
Method cacheMethod = methodCache.get(cacheKey);
if (cacheMethod != null) {
return cacheMethod;
}
for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
Method[] methods = superClass.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) {
makeAccessible(method);
methodCache.put(cacheKey, method);
return method;
}
}
@@ -405,4 +452,5 @@ public class ReflectUtils {
}
return new RuntimeException(msg, e);
}
}

View File

@@ -0,0 +1,182 @@
/**
* Copyright (c) 2008, Nathan Sweet
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package com.jeesite.common.reflect.asm;
import sun.misc.Unsafe;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.ProtectionDomain;
import java.util.HashSet;
import java.util.WeakHashMap;
@SuppressWarnings({"restriction", "rawtypes", "unchecked"})
class AccessClassLoader extends ClassLoader {
// Weak-references to class loaders, to avoid perm gen memory leaks, for example in app servers/web containters if the
// reflectasm library (including this class) is loaded outside the deployed applications (WAR/EAR) using ReflectASM/Kryo (exts,
// user classpath, etc).
// The key is the parent class loader and the value is the AccessClassLoader, both are weak-referenced in the hash table.
static private final WeakHashMap<ClassLoader, WeakReference<AccessClassLoader>> accessClassLoaders = new WeakHashMap();
// Fast-path for classes loaded in the same ClassLoader as this class.
static private final ClassLoader selfContextParentClassLoader = getParentClassLoader(AccessClassLoader.class);
static private volatile AccessClassLoader selfContextAccessClassLoader = new AccessClassLoader(selfContextParentClassLoader);
static private volatile Method defineClassMethod;
private final HashSet<String> localClassNames = new HashSet();
static {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe u = (Unsafe) theUnsafe.get(null);
Class cls = Class.forName("jdk.internal.module.IllegalAccessLogger");
Field logger = cls.getDeclaredField("logger");
u.putObjectVolatile(cls, u.staticFieldOffset(logger), null);
} catch (Exception e) {
// ignore
}
}
private AccessClassLoader (ClassLoader parent) {
super(parent);
}
/** Returns null if the access class has not yet been defined. */
Class loadAccessClass (String name) {
// No need to check the parent class loader if the access class hasn't been defined yet.
if (localClassNames.contains(name)) {
try {
return loadClass(name, false);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(ex); // Should not happen, since we know the class has been defined.
}
}
return null;
}
Class defineAccessClass (String name, byte[] bytes) throws ClassFormatError {
localClassNames.add(name);
return defineClass(name, bytes);
}
protected Class<?> loadClass (String name, boolean resolve) throws ClassNotFoundException {
// These classes come from the classloader that loaded AccessClassLoader.
if (name.equals(FieldAccess.class.getName())) return FieldAccess.class;
if (name.equals(MethodAccess.class.getName())) return MethodAccess.class;
// if (name.equals(ConstructorAccess.class.getName())) return ConstructorAccess.class;
// if (name.equals(PublicConstructorAccess.class.getName())) return PublicConstructorAccess.class;
// All other classes come from the classloader that loaded the type we are accessing.
return super.loadClass(name, resolve);
}
Class<?> defineClass (String name, byte[] bytes) throws ClassFormatError {
try {
// Attempt to load the access class in the same loader, which makes protected and default access members accessible.
return (Class<?>)getDefineClassMethod().invoke(getParent(),
new Object[] {name, bytes, Integer.valueOf(0), Integer.valueOf(bytes.length), getClass().getProtectionDomain()});
} catch (Exception ignored) {
// continue with the definition in the current loader (won't have access to protected and package-protected members)
}
return defineClass(name, bytes, 0, bytes.length, getClass().getProtectionDomain());
}
// As per JLS, section 5.3,
// "The runtime package of a class or interface is determined by the package name and defining class loader of the class or
// interface."
static boolean areInSameRuntimeClassLoader (Class type1, Class type2) {
if (type1.getPackage() != type2.getPackage()) {
return false;
}
ClassLoader loader1 = type1.getClassLoader();
ClassLoader loader2 = type2.getClassLoader();
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
if (loader1 == null) {
return (loader2 == null || loader2 == systemClassLoader);
}
if (loader2 == null) return loader1 == systemClassLoader;
return loader1 == loader2;
}
static private ClassLoader getParentClassLoader (Class type) {
ClassLoader parent = type.getClassLoader();
if (parent == null) parent = ClassLoader.getSystemClassLoader();
return parent;
}
static private Method getDefineClassMethod () throws Exception {
if (defineClassMethod == null) {
synchronized (accessClassLoaders) {
if (defineClassMethod == null) {
defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass",
new Class[] {String.class, byte[].class, int.class, int.class, ProtectionDomain.class});
try {
defineClassMethod.setAccessible(true);
} catch (Exception ignored) {
}
}
}
}
return defineClassMethod;
}
static AccessClassLoader get (Class type) {
ClassLoader parent = getParentClassLoader(type);
// 1. fast-path:
if (selfContextParentClassLoader.equals(parent)) {
if (selfContextAccessClassLoader == null) {
synchronized (accessClassLoaders) { // DCL with volatile semantics
if (selfContextAccessClassLoader == null)
selfContextAccessClassLoader = new AccessClassLoader(selfContextParentClassLoader);
}
}
return selfContextAccessClassLoader;
}
// 2. normal search:
synchronized (accessClassLoaders) {
WeakReference<AccessClassLoader> ref = accessClassLoaders.get(parent);
if (ref != null) {
AccessClassLoader accessClassLoader = ref.get();
if (accessClassLoader != null)
return accessClassLoader;
else
accessClassLoaders.remove(parent); // the value has been GC-reclaimed, but still not the key (defensive sanity)
}
AccessClassLoader accessClassLoader = new AccessClassLoader(parent);
accessClassLoaders.put(parent, new WeakReference<AccessClassLoader>(accessClassLoader));
return accessClassLoader;
}
}
static public void remove (ClassLoader parent) {
// 1. fast-path:
if (selfContextParentClassLoader.equals(parent)) {
selfContextAccessClassLoader = null;
} else {
// 2. normal search:
synchronized (accessClassLoaders) {
accessClassLoaders.remove(parent);
}
}
}
static public int activeAccessClassLoaders () {
int sz = accessClassLoaders.size();
if (selfContextAccessClassLoader != null) sz++;
return sz;
}
}

View File

@@ -0,0 +1,615 @@
/**
* Copyright (c) 2008, Nathan Sweet
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package com.jeesite.common.reflect.asm;
import com.jeesite.common.collect.MapUtils;
import org.springframework.asm.ClassWriter;
import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Type;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Map;
import static org.springframework.asm.Opcodes.*;
@SuppressWarnings("rawtypes")
public abstract class FieldAccess {
private String[] fieldNames;
private Class[] fieldTypes;
private Field[] fields;
private static Map<Class, FieldAccess> cache = MapUtils.newHashMap();
public int getIndex (String fieldName) {
for (int i = 0, n = fieldNames.length; i < n; i++)
if (fieldNames[i].equals(fieldName)) return i;
throw new IllegalArgumentException("Unable to find non-private field: " + fieldName);
}
public int getIndex (Field field) {
for (int i = 0, n = fields.length; i < n; i++)
if (fields[i].equals(field)) return i;
throw new IllegalArgumentException("Unable to find non-private field: " + field);
}
public void set (Object instance, String fieldName, Object value) {
set(instance, getIndex(fieldName), value);
}
public Object get (Object instance, String fieldName) {
return get(instance, getIndex(fieldName));
}
public String[] getFieldNames () {
return fieldNames;
}
public Class[] getFieldTypes () {
return fieldTypes;
}
public int getFieldCount () {
return fieldTypes.length;
}
public Field[] getFields () {
return fields;
}
public void setFields (Field[] fields) {
this.fields = fields;
}
abstract public void set (Object instance, int fieldIndex, Object value);
abstract public void setBoolean (Object instance, int fieldIndex, boolean value);
abstract public void setByte (Object instance, int fieldIndex, byte value);
abstract public void setShort (Object instance, int fieldIndex, short value);
abstract public void setInt (Object instance, int fieldIndex, int value);
abstract public void setLong (Object instance, int fieldIndex, long value);
abstract public void setDouble (Object instance, int fieldIndex, double value);
abstract public void setFloat (Object instance, int fieldIndex, float value);
abstract public void setChar (Object instance, int fieldIndex, char value);
abstract public Object get (Object instance, int fieldIndex);
abstract public String getString (Object instance, int fieldIndex);
abstract public char getChar (Object instance, int fieldIndex);
abstract public boolean getBoolean (Object instance, int fieldIndex);
abstract public byte getByte (Object instance, int fieldIndex);
abstract public short getShort (Object instance, int fieldIndex);
abstract public int getInt (Object instance, int fieldIndex);
abstract public long getLong (Object instance, int fieldIndex);
abstract public double getDouble (Object instance, int fieldIndex);
abstract public float getFloat (Object instance, int fieldIndex);
/** @param type Must not be the Object class, an interface, a primitive type, or void. */
static public FieldAccess get (Class type) {
FieldAccess fa = cache.get(type);
if (fa != null) {
return fa;
}
if (type.getSuperclass() == null)
throw new IllegalArgumentException("The type must not be the Object class, an interface, a primitive type, or void.");
ArrayList<Field> fields = new ArrayList<Field>();
Class nextClass = type;
while (nextClass != Object.class) {
Field[] declaredFields = nextClass.getDeclaredFields();
for (int i = 0, n = declaredFields.length; i < n; i++) {
Field field = declaredFields[i];
int modifiers = field.getModifiers();
if (Modifier.isStatic(modifiers)) continue;
if (Modifier.isPrivate(modifiers)) continue;
fields.add(field);
}
nextClass = nextClass.getSuperclass();
}
String[] fieldNames = new String[fields.size()];
Class[] fieldTypes = new Class[fields.size()];
for (int i = 0, n = fieldNames.length; i < n; i++) {
fieldNames[i] = fields.get(i).getName();
fieldTypes[i] = fields.get(i).getType();
}
String className = type.getName();
String accessClassName = className + "FieldAccess";
if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
Class accessClass;
AccessClassLoader loader = AccessClassLoader.get(type);
synchronized (loader) {
accessClass = loader.loadAccessClass(accessClassName);
if (accessClass == null) {
String accessClassNameInternal = accessClassName.replace('.', '/');
String classNameInternal = className.replace('.', '/');
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER + ACC_SYNTHETIC, accessClassNameInternal, null, "com/jeesite/common/reflect/asm/FieldAccess",
null);
insertConstructor(cw);
insertGetObject(cw, classNameInternal, fields);
insertSetObject(cw, classNameInternal, fields);
insertGetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
insertSetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
insertGetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
insertSetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
insertGetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
insertSetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
insertGetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
insertSetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
insertGetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
insertSetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
insertGetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
insertSetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
insertGetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
insertSetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
insertGetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
insertSetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
insertGetString(cw, classNameInternal, fields);
cw.visitEnd();
accessClass = loader.defineAccessClass(accessClassName, cw.toByteArray());
}
}
try {
FieldAccess access = (FieldAccess)accessClass.newInstance();
access.fieldNames = fieldNames;
access.fieldTypes = fieldTypes;
access.fields = fields.toArray(new Field[fields.size()]);
cache.put(type, access);
return access;
} catch (Throwable t) {
throw new RuntimeException("Error constructing field access class: " + accessClassName, t);
}
}
static private void insertConstructor (ClassWriter cw) {
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "com/jeesite/common/reflect/asm/FieldAccess", "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
static private void insertSetObject (ClassWriter cw, String classNameInternal, ArrayList<Field> fields) {
int maxStack = 6;
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "set", "(Ljava/lang/Object;ILjava/lang/Object;)V", null, null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 2);
if (!fields.isEmpty()) {
maxStack--;
Label[] labels = new Label[fields.size()];
for (int i = 0, n = labels.length; i < n; i++)
labels[i] = new Label();
Label defaultLabel = new Label();
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
for (int i = 0, n = labels.length; i < n; i++) {
Field field = fields.get(i);
Type fieldType = Type.getType(field.getType());
mv.visitLabel(labels[i]);
mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, classNameInternal);
mv.visitVarInsn(ALOAD, 3);
switch (fieldType.getSort()) {
case Type.BOOLEAN:
mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
break;
case Type.BYTE:
mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
break;
case Type.CHAR:
mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
break;
case Type.SHORT:
mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
break;
case Type.INT:
mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
break;
case Type.FLOAT:
mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
break;
case Type.LONG:
mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
break;
case Type.DOUBLE:
mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
break;
case Type.ARRAY:
mv.visitTypeInsn(CHECKCAST, fieldType.getDescriptor());
break;
case Type.OBJECT:
mv.visitTypeInsn(CHECKCAST, fieldType.getInternalName());
break;
}
mv.visitFieldInsn(PUTFIELD, field.getDeclaringClass().getName().replace('.', '/'), field.getName(),
fieldType.getDescriptor());
mv.visitInsn(RETURN);
}
mv.visitLabel(defaultLabel);
mv.visitFrame(F_SAME, 0, null, 0, null);
}
mv = insertThrowExceptionForFieldNotFound(mv);
mv.visitMaxs(maxStack, 4);
mv.visitEnd();
}
static private void insertGetObject (ClassWriter cw, String classNameInternal, ArrayList<Field> fields) {
int maxStack = 6;
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "get", "(Ljava/lang/Object;I)Ljava/lang/Object;", null, null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 2);
if (!fields.isEmpty()) {
maxStack--;
Label[] labels = new Label[fields.size()];
for (int i = 0, n = labels.length; i < n; i++)
labels[i] = new Label();
Label defaultLabel = new Label();
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
for (int i = 0, n = labels.length; i < n; i++) {
Field field = fields.get(i);
mv.visitLabel(labels[i]);
mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, classNameInternal);
mv.visitFieldInsn(GETFIELD, field.getDeclaringClass().getName().replace('.', '/'), field.getName(),
Type.getDescriptor(field.getType()));
Type fieldType = Type.getType(field.getType());
switch (fieldType.getSort()) {
case Type.BOOLEAN:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
break;
case Type.BYTE:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
break;
case Type.CHAR:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
break;
case Type.SHORT:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
break;
case Type.INT:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
break;
case Type.FLOAT:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
break;
case Type.LONG:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
break;
case Type.DOUBLE:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
break;
}
mv.visitInsn(ARETURN);
}
mv.visitLabel(defaultLabel);
mv.visitFrame(F_SAME, 0, null, 0, null);
}
insertThrowExceptionForFieldNotFound(mv);
mv.visitMaxs(maxStack, 3);
mv.visitEnd();
}
static private void insertGetString (ClassWriter cw, String classNameInternal, ArrayList<Field> fields) {
int maxStack = 6;
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "getString", "(Ljava/lang/Object;I)Ljava/lang/String;", null, null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 2);
if (!fields.isEmpty()) {
maxStack--;
Label[] labels = new Label[fields.size()];
Label labelForInvalidTypes = new Label();
boolean hasAnyBadTypeLabel = false;
for (int i = 0, n = labels.length; i < n; i++) {
if (fields.get(i).getType().equals(String.class))
labels[i] = new Label();
else {
labels[i] = labelForInvalidTypes;
hasAnyBadTypeLabel = true;
}
}
Label defaultLabel = new Label();
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
for (int i = 0, n = labels.length; i < n; i++) {
if (!labels[i].equals(labelForInvalidTypes)) {
Field field = fields.get(i);
mv.visitLabel(labels[i]);
mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, classNameInternal);
mv.visitFieldInsn(GETFIELD, field.getDeclaringClass().getName().replace('.', '/'), field.getName(),
"Ljava/lang/String;");
mv.visitInsn(ARETURN);
}
}
// Rest of fields: different type
if (hasAnyBadTypeLabel) {
mv.visitLabel(labelForInvalidTypes);
mv.visitFrame(F_SAME, 0, null, 0, null);
insertThrowExceptionForFieldType(mv, "String");
}
// Default: field not found
mv.visitLabel(defaultLabel);
mv.visitFrame(F_SAME, 0, null, 0, null);
}
insertThrowExceptionForFieldNotFound(mv);
mv.visitMaxs(maxStack, 3);
mv.visitEnd();
}
static private void insertSetPrimitive (ClassWriter cw, String classNameInternal, ArrayList<Field> fields,
Type primitiveType) {
int maxStack = 6;
int maxLocals = 4; // See correction below for LLOAD and DLOAD
final String setterMethodName;
final String typeNameInternal = primitiveType.getDescriptor();
final int loadValueInstruction;
switch (primitiveType.getSort()) {
case Type.BOOLEAN:
setterMethodName = "setBoolean";
loadValueInstruction = ILOAD;
break;
case Type.BYTE:
setterMethodName = "setByte";
loadValueInstruction = ILOAD;
break;
case Type.CHAR:
setterMethodName = "setChar";
loadValueInstruction = ILOAD;
break;
case Type.SHORT:
setterMethodName = "setShort";
loadValueInstruction = ILOAD;
break;
case Type.INT:
setterMethodName = "setInt";
loadValueInstruction = ILOAD;
break;
case Type.FLOAT:
setterMethodName = "setFloat";
loadValueInstruction = FLOAD;
break;
case Type.LONG:
setterMethodName = "setLong";
loadValueInstruction = LLOAD;
maxLocals++; // (LLOAD and DLOAD actually load two slots)
break;
case Type.DOUBLE:
setterMethodName = "setDouble";
loadValueInstruction = DLOAD;
maxLocals++; // (LLOAD and DLOAD actually load two slots)
break;
default:
setterMethodName = "set";
loadValueInstruction = ALOAD;
break;
}
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, setterMethodName, "(Ljava/lang/Object;I" + typeNameInternal + ")V", null,
null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 2);
if (!fields.isEmpty()) {
maxStack--;
Label[] labels = new Label[fields.size()];
Label labelForInvalidTypes = new Label();
boolean hasAnyBadTypeLabel = false;
for (int i = 0, n = labels.length; i < n; i++) {
if (Type.getType(fields.get(i).getType()).equals(primitiveType))
labels[i] = new Label();
else {
labels[i] = labelForInvalidTypes;
hasAnyBadTypeLabel = true;
}
}
Label defaultLabel = new Label();
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
for (int i = 0, n = labels.length; i < n; i++) {
if (!labels[i].equals(labelForInvalidTypes)) {
Field field = fields.get(i);
mv.visitLabel(labels[i]);
mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, classNameInternal);
mv.visitVarInsn(loadValueInstruction, 3);
mv.visitFieldInsn(PUTFIELD, field.getDeclaringClass().getName().replace('.', '/'), field.getName(),
typeNameInternal);
mv.visitInsn(RETURN);
}
}
// Rest of fields: different type
if (hasAnyBadTypeLabel) {
mv.visitLabel(labelForInvalidTypes);
mv.visitFrame(F_SAME, 0, null, 0, null);
insertThrowExceptionForFieldType(mv, primitiveType.getClassName());
}
// Default: field not found
mv.visitLabel(defaultLabel);
mv.visitFrame(F_SAME, 0, null, 0, null);
}
mv = insertThrowExceptionForFieldNotFound(mv);
mv.visitMaxs(maxStack, maxLocals);
mv.visitEnd();
}
static private void insertGetPrimitive (ClassWriter cw, String classNameInternal, ArrayList<Field> fields,
Type primitiveType) {
int maxStack = 6;
final String getterMethodName;
final String typeNameInternal = primitiveType.getDescriptor();
final int returnValueInstruction;
switch (primitiveType.getSort()) {
case Type.BOOLEAN:
getterMethodName = "getBoolean";
returnValueInstruction = IRETURN;
break;
case Type.BYTE:
getterMethodName = "getByte";
returnValueInstruction = IRETURN;
break;
case Type.CHAR:
getterMethodName = "getChar";
returnValueInstruction = IRETURN;
break;
case Type.SHORT:
getterMethodName = "getShort";
returnValueInstruction = IRETURN;
break;
case Type.INT:
getterMethodName = "getInt";
returnValueInstruction = IRETURN;
break;
case Type.FLOAT:
getterMethodName = "getFloat";
returnValueInstruction = FRETURN;
break;
case Type.LONG:
getterMethodName = "getLong";
returnValueInstruction = LRETURN;
break;
case Type.DOUBLE:
getterMethodName = "getDouble";
returnValueInstruction = DRETURN;
break;
default:
getterMethodName = "get";
returnValueInstruction = ARETURN;
break;
}
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, getterMethodName, "(Ljava/lang/Object;I)" + typeNameInternal, null, null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 2);
if (!fields.isEmpty()) {
maxStack--;
Label[] labels = new Label[fields.size()];
Label labelForInvalidTypes = new Label();
boolean hasAnyBadTypeLabel = false;
for (int i = 0, n = labels.length; i < n; i++) {
if (Type.getType(fields.get(i).getType()).equals(primitiveType))
labels[i] = new Label();
else {
labels[i] = labelForInvalidTypes;
hasAnyBadTypeLabel = true;
}
}
Label defaultLabel = new Label();
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
for (int i = 0, n = labels.length; i < n; i++) {
Field field = fields.get(i);
if (!labels[i].equals(labelForInvalidTypes)) {
mv.visitLabel(labels[i]);
mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, classNameInternal);
mv.visitFieldInsn(GETFIELD, field.getDeclaringClass().getName().replace('.', '/'), field.getName(),
typeNameInternal);
mv.visitInsn(returnValueInstruction);
}
}
// Rest of fields: different type
if (hasAnyBadTypeLabel) {
mv.visitLabel(labelForInvalidTypes);
mv.visitFrame(F_SAME, 0, null, 0, null);
insertThrowExceptionForFieldType(mv, primitiveType.getClassName());
}
// Default: field not found
mv.visitLabel(defaultLabel);
mv.visitFrame(F_SAME, 0, null, 0, null);
}
mv = insertThrowExceptionForFieldNotFound(mv);
mv.visitMaxs(maxStack, 3);
mv.visitEnd();
}
static private MethodVisitor insertThrowExceptionForFieldNotFound (MethodVisitor mv) {
mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
mv.visitInsn(DUP);
mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
mv.visitInsn(DUP);
mv.visitLdcInsn("Field not found: ");
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V", false);
mv.visitVarInsn(ILOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V", false);
mv.visitInsn(ATHROW);
return mv;
}
static private MethodVisitor insertThrowExceptionForFieldType (MethodVisitor mv, String fieldType) {
mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
mv.visitInsn(DUP);
mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
mv.visitInsn(DUP);
mv.visitLdcInsn("Field not declared as " + fieldType + ": ");
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V", false);
mv.visitVarInsn(ILOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V", false);
mv.visitInsn(ATHROW);
return mv;
}
}

View File

@@ -0,0 +1,313 @@
/**
* Copyright (c) 2008, Nathan Sweet
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package com.jeesite.common.reflect.asm;
import com.jeesite.common.collect.MapUtils;
import org.springframework.asm.*;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import static org.springframework.asm.Opcodes.*;
@SuppressWarnings("rawtypes")
public abstract class MethodAccess {
private String[] methodNames;
private Class[][] parameterTypes;
private Class[] returnTypes;
private static Map<Class, MethodAccess> cache = MapUtils.newHashMap();
abstract public Object invoke (Object object, int methodIndex, Object... args);
/** Invokes the method with the specified name and the specified param types. */
public Object invoke (Object object, String methodName, Class[] paramTypes, Object... args) {
return invoke(object, getIndex(methodName, paramTypes), args);
}
/** Invokes the first method with the specified name and the specified number of arguments. */
public Object invoke (Object object, String methodName, Object... args) {
return invoke(object, getIndex(methodName, args == null ? 0 : args.length), args);
}
/** Returns the index of the first method with the specified name. */
public int getIndex (String methodName) {
for (int i = 0, n = methodNames.length; i < n; i++)
if (methodNames[i].equals(methodName)) return i;
throw new IllegalArgumentException("Unable to find non-private method: " + methodName);
}
/** Returns the index of the first method with the specified name and param types. */
public int getIndex (String methodName, Class... paramTypes) {
for (int i = 0, n = methodNames.length; i < n; i++)
if (methodNames[i].equals(methodName) && Arrays.equals(paramTypes, parameterTypes[i])) return i;
throw new IllegalArgumentException("Unable to find non-private method: " + methodName + " " + Arrays.toString(paramTypes));
}
/** Returns the index of the first method with the specified name and the specified number of arguments. */
public int getIndex (String methodName, int paramsCount) {
for (int i = 0, n = methodNames.length; i < n; i++)
if (methodNames[i].equals(methodName) && parameterTypes[i].length == paramsCount) return i;
throw new IllegalArgumentException(
"Unable to find non-private method: " + methodName + " with " + paramsCount + " params.");
}
public String[] getMethodNames () {
return methodNames;
}
public Class[][] getParameterTypes () {
return parameterTypes;
}
public Class[] getReturnTypes () {
return returnTypes;
}
/** Creates a new MethodAccess for the specified type.
* @param type Must not be a primitive type, or void. */
static public MethodAccess get (Class type) {
MethodAccess ma = cache.get(type);
if (ma != null) {
return ma;
}
boolean isInterface = type.isInterface();
if (!isInterface && type.getSuperclass() == null && type != Object.class)
throw new IllegalArgumentException("The type must not be an interface, a primitive type, or void.");
ArrayList<Method> methods = new ArrayList<Method>();
if (!isInterface) {
Class nextClass = type;
while (nextClass != Object.class) {
addDeclaredMethodsToList(nextClass, methods);
nextClass = nextClass.getSuperclass();
}
} else
recursiveAddInterfaceMethodsToList(type, methods);
int n = methods.size();
String[] methodNames = new String[n];
Class[][] parameterTypes = new Class[n][];
Class[] returnTypes = new Class[n];
for (int i = 0; i < n; i++) {
Method method = methods.get(i);
methodNames[i] = method.getName();
parameterTypes[i] = method.getParameterTypes();
returnTypes[i] = method.getReturnType();
}
String className = type.getName();
String accessClassName = className + "MethodAccess";
if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
Class accessClass;
AccessClassLoader loader = AccessClassLoader.get(type);
synchronized (loader) {
accessClass = loader.loadAccessClass(accessClassName);
if (accessClass == null) {
String accessClassNameInternal = accessClassName.replace('.', '/');
String classNameInternal = className.replace('.', '/');
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
MethodVisitor mv;
cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/jeesite/common/reflect/asm/MethodAccess",
null);
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "com/jeesite/common/reflect/asm/MethodAccess", "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "invoke",
"(Ljava/lang/Object;I[Ljava/lang/Object;)Ljava/lang/Object;", null, null);
mv.visitCode();
if (!methods.isEmpty()) {
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, classNameInternal);
mv.visitVarInsn(ASTORE, 4);
mv.visitVarInsn(ILOAD, 2);
Label[] labels = new Label[n];
for (int i = 0; i < n; i++)
labels[i] = new Label();
Label defaultLabel = new Label();
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
StringBuilder buffer = new StringBuilder(128);
for (int i = 0; i < n; i++) {
mv.visitLabel(labels[i]);
if (i == 0)
mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {classNameInternal}, 0, null);
else
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 4);
buffer.setLength(0);
buffer.append('(');
Class[] paramTypes = parameterTypes[i];
Class returnType = returnTypes[i];
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
mv.visitVarInsn(ALOAD, 3);
mv.visitIntInsn(BIPUSH, paramIndex);
mv.visitInsn(AALOAD);
Type paramType = Type.getType(paramTypes[paramIndex]);
switch (paramType.getSort()) {
case Type.BOOLEAN:
mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
break;
case Type.BYTE:
mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
break;
case Type.CHAR:
mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
break;
case Type.SHORT:
mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
break;
case Type.INT:
mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
break;
case Type.FLOAT:
mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
break;
case Type.LONG:
mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
break;
case Type.DOUBLE:
mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
break;
case Type.ARRAY:
mv.visitTypeInsn(CHECKCAST, paramType.getDescriptor());
break;
case Type.OBJECT:
mv.visitTypeInsn(CHECKCAST, paramType.getInternalName());
break;
}
buffer.append(paramType.getDescriptor());
}
buffer.append(')');
buffer.append(Type.getDescriptor(returnType));
int invoke;
if (isInterface)
invoke = INVOKEINTERFACE;
else if (Modifier.isStatic(methods.get(i).getModifiers()))
invoke = INVOKESTATIC;
else
invoke = INVOKEVIRTUAL;
mv.visitMethodInsn(invoke, classNameInternal, methodNames[i], buffer.toString(), false);
switch (Type.getType(returnType).getSort()) {
case Type.VOID:
mv.visitInsn(ACONST_NULL);
break;
case Type.BOOLEAN:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
break;
case Type.BYTE:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
break;
case Type.CHAR:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
break;
case Type.SHORT:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
break;
case Type.INT:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
break;
case Type.FLOAT:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
break;
case Type.LONG:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
break;
case Type.DOUBLE:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
break;
}
mv.visitInsn(ARETURN);
}
mv.visitLabel(defaultLabel);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
}
mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
mv.visitInsn(DUP);
mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
mv.visitInsn(DUP);
mv.visitLdcInsn("Method not found: ");
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V", false);
mv.visitVarInsn(ILOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V", false);
mv.visitInsn(ATHROW);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
cw.visitEnd();
byte[] data = cw.toByteArray();
accessClass = loader.defineAccessClass(accessClassName, data);
}
}
try {
MethodAccess access = (MethodAccess)accessClass.newInstance();
access.methodNames = methodNames;
access.parameterTypes = parameterTypes;
access.returnTypes = returnTypes;
cache.put(type, access);
return access;
} catch (Throwable t) {
throw new RuntimeException("Error constructing method access class: " + accessClassName, t);
}
}
static private void addDeclaredMethodsToList (Class type, ArrayList<Method> methods) {
Method[] declaredMethods = type.getDeclaredMethods();
for (int i = 0, n = declaredMethods.length; i < n; i++) {
Method method = declaredMethods[i];
int modifiers = method.getModifiers();
// if (Modifier.isStatic(modifiers)) continue;
if (Modifier.isPrivate(modifiers)) continue;
methods.add(method);
}
}
static private void recursiveAddInterfaceMethodsToList (Class interfaceType, ArrayList<Method> methods) {
addDeclaredMethodsToList(interfaceType, methods);
for (Class nextInterface : interfaceType.getInterfaces())
recursiveAddInterfaceMethodsToList(nextInterface, methods);
}
}

View File

@@ -0,0 +1,10 @@
Copyright (c) 2008, Nathan Sweet
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -4,44 +4,6 @@
*/
package com.jeesite.common.utils.excel;
import java.io.Closeable;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
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.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.collect.MapUtils;
@@ -53,6 +15,22 @@ 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;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
/**
* 导出Excel文件导出“XLSX”格式支持大数据量导出 @see org.apache.poi.ss.SpreadsheetVersion
@@ -92,7 +70,10 @@ public class ExcelExport implements Closeable{
* 存储字段类型临时数据
*/
private Map<Class<? extends FieldType>, FieldType> fieldTypes = MapUtils.newHashMap();
@SuppressWarnings("rawtypes")
private static Class dictUtilsClass = null;
/**
* 构造函数
* @param title 表格标题,传“空值”,表示无标题
@@ -224,6 +205,7 @@ public class ExcelExport implements Closeable{
}
ExcelField ef = f.getAnnotation(ExcelField.class);
addAnnotation(annotationList, ef, f, type, groups);
ReflectUtils.makeAccessible(f);
}
// Get annotation method
Method[] ms = cls.getDeclaredMethods();
@@ -236,6 +218,7 @@ public class ExcelExport implements Closeable{
}
ExcelField ef = m.getAnnotation(ExcelField.class);
addAnnotation(annotationList, ef, m, type, groups);
ReflectUtils.makeAccessible(m);
}
// Field sorting
Collections.sort(annotationList, new Comparator<Object[]>() {
@@ -542,16 +525,22 @@ public class ExcelExport implements Closeable{
val = ReflectUtils.invokeGetter(e, ef.attrName());
}else{
if (os[1] instanceof Field){
val = ReflectUtils.invokeGetter(e, ((Field)os[1]).getName());
//val = ReflectUtils.invokeGetter(e, ((Field)os[1]).getName());
val = ((Field)os[1]).get(e);
}else if (os[1] instanceof Method){
val = ReflectUtils.invokeMethod(e, ((Method)os[1]).getName(), new Class[] {}, new Object[] {});
//val = ReflectUtils.invokeMethod(e, ((Method)os[1]).getName(), new Class[] {}, new Object[] {});
val = ((Method)os[1]).invoke(e);
}
}
// If is dict, get dict label
if (StringUtils.isNotBlank(ef.dictType())){
Class<?> dictUtils = Class.forName("com.jeesite.modules.sys.utils.DictUtils");
val = dictUtils.getMethod("getDictLabels", String.class, String.class,
String.class).invoke(null, ef.dictType(), val==null?"":val.toString(), "");
if (dictUtilsClass == null) {
dictUtilsClass = Class.forName("com.jeesite.modules.sys.utils.DictUtils");
}
val = ReflectUtils.invokeMethodByAsm(dictUtilsClass, "getDictLabels",
ef.dictType(), val == null ? "" : val.toString(), "");
//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(), "");
}
}catch(Exception ex) {
@@ -611,7 +600,7 @@ public class ExcelExport implements Closeable{
/**
* 输出到文件
* @param fileName 输出文件名
* @param name 输出文件名
*/
public ExcelExport writeFile(String name) throws FileNotFoundException, IOException{
FileOutputStream os = new FileOutputStream(name);

View File

@@ -4,40 +4,6 @@
*/
package com.jeesite.common.utils.excel;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
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.Map;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import com.jeesite.common.callback.MethodCallback;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.collect.ListUtils;
@@ -50,6 +16,23 @@ 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;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.lang.reflect.Constructor;
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.*;
/**
* 导入Excel文件支持“XLS”和“XLSX”格式
@@ -79,7 +62,10 @@ public class ExcelImport implements Closeable {
* 存储字段类型临时数据
*/
private Map<Class<? extends FieldType>, FieldType> fieldTypes = MapUtils.newHashMap();
@SuppressWarnings("rawtypes")
private static Class dictUtilsClass = null;
/**
* 构造函数
* @param path 导入文件对象,读取第一个工作表
@@ -92,7 +78,7 @@ public class ExcelImport implements Closeable {
/**
* 构造函数
* @param path 导入文件对象,读取第一个工作表
* @param file 导入文件对象,读取第一个工作表
* @param headerNum 标题行数,数据行号=标题行数+1
* @throws InvalidFormatException
* @throws IOException
@@ -104,7 +90,7 @@ public class ExcelImport implements Closeable {
/**
* 构造函数
* @param path 导入文件对象
* @param file 导入文件对象
* @param headerNum 标题行数,数据行号=标题行数+1
* @param sheetIndexOrName 工作表编号或名称从0开始
* @throws InvalidFormatException
@@ -117,7 +103,7 @@ public class ExcelImport implements Closeable {
/**
* 构造函数
* @param file 导入文件对象
* @param multipartFile 导入文件对象
* @param headerNum 标题行数,数据行号=标题行数+1
* @param sheetIndexOrName 工作表编号或名称从0开始
* @throws InvalidFormatException
@@ -130,7 +116,7 @@ public class ExcelImport implements Closeable {
/**
* 构造函数
* @param path 导入文件对象
* @param fileName 导入文件对象
* @param headerNum 标题行数,数据行号=标题行数+1
* @param sheetIndexOrName 工作表编号或名称
* @throws InvalidFormatException
@@ -334,23 +320,20 @@ public class ExcelImport implements Closeable {
* @param groups 导入分组
*/
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) {
if (isThrowException){
Exception ex = (Exception)params[0];
int rowNum = (int)params[1];
int columnNum = (int)params[2];
throw new ExcelException("Get cell value ["+rowNum+","+columnNum+"]", ex);
}
return null;
return getDataList(cls, params -> {
if (isThrowException){
Exception ex = (Exception)params[0];
int rowNum = (int)params[1];
int columnNum = (int)params[2];
throw new ExcelException("Get cell value ["+rowNum+","+columnNum+"]", ex);
}
return null;
}, groups);
}
/**
* 获取导入数据列表
* @param cls 导入对象类型
* @param isThrowException 遇见错误是否抛出异常
* @param exceptionCallback 遇见异常时回调方法
* @param groups 导入分组
*/
@SuppressWarnings("unchecked")
@@ -377,6 +360,7 @@ public class ExcelImport implements Closeable {
}
ExcelField ef = f.getAnnotation(ExcelField.class);
addAnnotation(annotationList, ef, f, Type.IMPORT, groups);
ReflectUtils.makeAccessible(f);
}
// Get annotation method
Method[] ms = cls.getDeclaredMethods();
@@ -389,6 +373,7 @@ public class ExcelImport implements Closeable {
}
ExcelField ef = m.getAnnotation(ExcelField.class);
addAnnotation(annotationList, ef, m, Type.IMPORT, groups);
ReflectUtils.makeAccessible(m);
}
// Field sorting
Collections.sort(annotationList, new Comparator<Object[]>() {
@@ -417,15 +402,19 @@ public class ExcelImport implements Closeable {
// If is dict type, get dict value
if (StringUtils.isNotBlank(ef.dictType())){
try{
Class<?> dictUtils = Class.forName("com.jeesite.modules.sys.utils.DictUtils");
val = dictUtils.getMethod("getDictValues", String.class, String.class,
String.class).invoke(null, ef.dictType(), val.toString(), "");
if (dictUtilsClass == null) {
dictUtilsClass = Class.forName("com.jeesite.modules.sys.utils.DictUtils");
}
val = ReflectUtils.invokeMethodByAsm(dictUtilsClass, "getDictValues",
ef.dictType(), val.toString(), "");
//val = dictUtilsClass.getMethod("getDictValues", String.class, String.class,
// String.class).invoke(null, ef.dictType(), val.toString(), "");
//val = DictUtils.getDictValue(val.toString(), ef.dictType(), "");
//log.debug("Dictionary type value: ["+i+","+colunm+"] " + val);
} catch (Exception ex) {
log.info("Get cell value ["+i+","+column+"] error: " + ex.toString());
val = null;
}
//val = DictUtils.getDictValue(val.toString(), ef.dictType(), "");
//log.debug("Dictionary type value: ["+i+","+colunm+"] " + val);
}
// Get param type and type cast
Class<?> valType = Class.class;
@@ -500,13 +489,15 @@ public class ExcelImport implements Closeable {
ReflectUtils.invokeSetter(e, ef.attrName(), val);
}else{
if (os[1] instanceof Field){
ReflectUtils.invokeSetter(e, ((Field)os[1]).getName(), val);
//ReflectUtils.invokeSetter(e, ((Field)os[1]).getName(), val);
((Field)os[1]).set(e, val);
}else if (os[1] instanceof Method){
String mthodName = ((Method)os[1]).getName();
if ("get".equals(mthodName.substring(0, 3))){
mthodName = "set"+StringUtils.substringAfter(mthodName, "get");
}
ReflectUtils.invokeMethod(e, mthodName, new Class[] {valType}, new Object[] {val});
//String mthodName = ((Method)os[1]).getName();
//if ("get".equals(mthodName.substring(0, 3))){
// mthodName = "set"+StringUtils.substringAfter(mthodName, "get");
//}
//ReflectUtils.invokeMethod(e, mthodName, new Class[] {valType}, new Object[] {val});
((Method)os[1]).invoke(e, val);
}
}
}

View File

@@ -4,13 +4,14 @@
*/
package com.jeesite.common.web;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.io.PropertiesUtils;
import com.jeesite.common.lang.StringUtils;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.lang.StringUtils;
/**
* Cookie工具类
* @author ThinkGem
@@ -31,8 +32,7 @@ public class CookieUtils {
* 设置 Cookie
* @param name 名称
* @param value 值
* @param maxAge 生存时间(单位秒)
* @param uri 路径
* @param path 路径
*/
public static void setCookie(HttpServletResponse response, String name, String value, String path) {
setCookie(response, name, value, path, 60*60*24*30);
@@ -43,7 +43,6 @@ public class CookieUtils {
* @param name 名称
* @param value 值
* @param maxAge 生存时间(单位秒)
* @param uri 路径
*/
public static void setCookie(HttpServletResponse response, String name, String value, int maxAge) {
setCookie(response, name, value, "/", maxAge);
@@ -53,17 +52,19 @@ public class CookieUtils {
* 设置 Cookie
* @param name 名称
* @param value 值
* @param path 路径
* @param maxAge 生存时间(单位秒)
* @param uri 路径
*/
public static void setCookie(HttpServletResponse response, String name, String value, String path, int maxAge) {
if (StringUtils.isNotBlank(name)){
name = EncodeUtils.encodeUrl(name);
value = EncodeUtils.encodeUrl(value);
Cookie cookie = new Cookie(name, null);
Cookie cookie = new Cookie(name, value);
cookie.setPath(path);
cookie.setMaxAge(maxAge);
cookie.setValue(value);
PropertiesUtils props = PropertiesUtils.getInstance();
cookie.setSecure(props.getPropertyToBoolean("session.sessionIdCookieSecure", "false"));
cookie.setHttpOnly(props.getPropertyToBoolean("session.sessionIdCookieHttpOnly", "true"));
response.addCookie(cookie);
}
}

View File

@@ -100,7 +100,11 @@ public class ServletUtils {
if (ServletUtils.isAjaxRequest(request)){
request.getRequestDispatcher(url).forward(request, response); // AJAX不支持Redirect改用Forward
}else{
response.sendRedirect(request.getContextPath() + url);
if (StringUtils.contains(url, "://")){
response.sendRedirect(url);
}else{
response.sendRedirect(request.getContextPath() + url);
}
}
} catch (Exception e) {
e.printStackTrace();
@@ -179,7 +183,6 @@ public class ServletUtils {
* 返回结果JSON字符串支持JsonP请求参数加__callback=回调函数名)
* @param result Global.TRUE or Globle.False
* @param message 执行消息
* @param data 消息数据
* @return JSON字符串{result:'true',message:''}
*/
public static String renderResult(String result, String message) {
@@ -300,7 +303,6 @@ public class ServletUtils {
/**
* 将对象转换为JSON、XML、JSONP字符串渲染到客户端JsonP请求参数加__callback=回调函数名)
* @param request 请求对象用来得到输出格式的指令JSON、XML、JSONP
* @param response 渲染对象
* @param object 待转换JSON并渲染的对象
* @return null
@@ -311,7 +313,6 @@ public class ServletUtils {
/**
* 将对象转换为JSON、XML、JSONP字符串渲染到客户端JsonP请求参数加__callback=回调函数名)
* @param request 请求对象用来得到输出格式的指令JSON、XML、JSONP
* @param response 渲染对象
* @param object 待转换JSON并渲染的对象
* @param jsonView 根据 JsonView 过滤

View File

@@ -868,7 +868,7 @@ layer.iframeAuto = function(index, diffVal, $this){
var layero = $('#'+ doms[0] + index);
var titHeight = layero.find(doms[1]).outerHeight() || 0;
var btnHeight = layero.find('.'+doms[6]).outerHeight() || 0;
// var heg = layer.getChildFrame('html', index).outerHeight();
//var heg = layer.getChildFrame('html', index).outerHeight();
var heg = iframeWin.document.body.scrollHeight;
var layerHeight = heg + titHeight + btnHeight;
var layerTop = ($(window).height() - layerHeight) / 2;
@@ -876,7 +876,7 @@ layer.iframeAuto = function(index, diffVal, $this){
var $iframe = layero.find('iframe');
if (Math.abs($iframe.height() - heg) < (diffVal || 9000)){
layero.animate({height: layerHeight, top: layerTop}, 20);
$iframe.animate({height: heg}, 20);
$iframe.animate({height: heg + 1}, 20);
}
}
}

View File

@@ -0,0 +1,577 @@
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
*/
package com.jeesite.test;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.lang.TimeUtils;
import com.jeesite.common.reflect.ReflectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.poi.ss.usermodel.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
/**
* 反射工具类 性能测试
* @author ThinkGem
* @version 2023-2-6
*/
@SuppressWarnings("rawtypes")
public class ReflectUtilsTest {
public static void main(String[] args) {
int num = 100000;
for (int i = 0; i < 5; i++) {
getMethodTest(num, Type.FIELD);
getMethodTest(num, Type.ASM);
getMethodTest(num, Type.CACHE);
getMethodTest(num, Type.NOT_CACHE);
setMethodTest(num, Type.FIELD);
setMethodTest(num, Type.ASM);
setMethodTest(num, Type.CACHE);
setMethodTest(num, Type.NOT_CACHE);
}
ReflectUtils.invokeGetter(Test.class, "staticMethodTest");
ReflectUtils.invokeSetter(Test.class, "staticMethodTest", "123");
}
public static void getMethodTest(int num, Type type) {
long start = System.currentTimeMillis();
for (int i = 0; i < num; i++) {
Test test = new Test("1", "2", "3", 4, 5, 6, new Date());
for (int j = 1; j <= 7; j++) {
String name = (j >= 1 && j <= 3 ? "str" : j >=4 && j<= 6 ? "int" : "date") + j;
Object v = null;
switch (type) {
case ASM:
v = ReflectUtils.invokeGetter(test, name);
break;
case CACHE:
v = ReflectUtils2.invokeGetterCache(test, name);
break;
case NOT_CACHE:
v = ReflectUtils2.invokeGetter(test, name);
break;
case FIELD:
v = ReflectUtils.getFieldValue(test, name);
break;
}
if (v == null) {
throw new RuntimeException("error.");
}else if (j == 1 && !v.equals(test.getStr1())) {
throw new RuntimeException("error.");
} else if (j == 4 && !v.equals(test.getInt4())) {
throw new RuntimeException("error.");
} else if (j == 7 && !v.equals(test.getDate7())) {
throw new RuntimeException("error.");
}
}
}
long total = System.currentTimeMillis() - start;
System.out.println("Get " + type.getVal() + ": " + TimeUtils.formatTime(total));
}
public static void setMethodTest(int num, Type type) {
long start = System.currentTimeMillis();
for (int i = 0; i < num; i++) {
Test test = new Test();
for (int j = 1; j <= 7; j++) {
String name = (j >= 1 && j <= 3 ? "str" : j >=4 && j<= 6 ? "int" : "date") + j;
Object v = (j >= 1 && j <= 3 ? ("str" + j) : j >=4 && j<= 6 ? (123 + j) : new Date());
switch (type) {
case ASM:
// MethodAccess ma = MethodAccess.get(test.getClass());
// ma.invoke(test, SETTER_PREFIX+StringUtils.capitalize(name), v);
ReflectUtils.invokeSetter(test, name, v);
break;
case CACHE:
ReflectUtils2.invokeSetterCache(test, name, v);
break;
case NOT_CACHE:
ReflectUtils2.invokeSetter(test, name, v);
break;
case FIELD:
ReflectUtils.setFieldValue(test, name, v);
break;
}
if (j == 1 && !v.equals(test.getStr1())) {
throw new RuntimeException("error.");
} else if (j == 4 && !v.equals(test.getInt4())) {
throw new RuntimeException("error.");
} else if (j == 7 && !v.equals(test.getDate7())) {
throw new RuntimeException("error.");
}
}
}
long total = System.currentTimeMillis() - start;
System.out.println("Set " + type.getVal() + ": " + TimeUtils.formatTime(total));
}
enum Type {
FIELD("field"),
ASM("method asm"),
CACHE("method use cache"),
NOT_CACHE("method not use cache");
private String val;
Type(String val) {
this.val = val;
}
public String getVal() {
return val;
}
}
public static class Test {
private String str1;
private String str2;
private String str3;
private Integer int4;
private Integer int5;
private Integer int6;
private Date date7;
public Test() {
}
public Test(String str1, String str2, String str3, Integer int4, Integer int5, Integer int6, Date date7) {
this.str1 = str1;
this.str2 = str2;
this.str3 = str3;
this.int4 = int4;
this.int5 = int5;
this.int6 = int6;
this.date7 = date7;
}
public String getStr1() {
return str1;
}
public void setStr1(String str1) {
this.str1 = str1;
}
public String getStr2() {
return str2;
}
public void setStr2(String str2) {
this.str2 = str2;
}
public String getStr3() {
return str3;
}
public void setStr3(String str3) {
this.str3 = str3;
}
public Integer getInt4() {
return int4;
}
public void setInt4(Integer int4) {
this.int4 = int4;
}
public Integer getInt5() {
return int5;
}
public void setInt5(Integer int5) {
this.int5 = int5;
}
public Integer getInt6() {
return int6;
}
public void setInt6(Integer int6) {
this.int6 = int6;
}
public Date getDate7() {
return date7;
}
public void setDate7(Date date7) {
this.date7 = date7;
}
public static void getStaticMethodTest() {
System.out.println("This is a static get method");
}
public static void setStaticMethodTest(String val) {
System.out.println("This is a static set method, set val: " + val);
}
}
}
/**
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
* @author calvin、ThinkGem
* @version 2015-11-12
*/
class ReflectUtils2 {
private static Logger logger = LoggerFactory.getLogger(ReflectUtils2.class);
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get";
private static Class baseEntityClass = null;
/**
* 调用Getter方法
* 支持多级,如:对象名.对象名.方法,
* 支持静态类及方法调用,
* 支持Map
*/
@SuppressWarnings("unchecked")
public static <E> E invokeGetter(Object obj, String propertyName) {
Object object = obj;
for (String name : StringUtils.split(propertyName, ".")){
if (obj instanceof Map){
object = ((Map)obj).get(name);
}else{
String methodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = invokeMethod(object, methodName, new Class[] {}, new Object[] {});
}
}
return (E)object;
}
/**
* 调用Getter方法
* 支持多级,如:对象名.对象名.方法,
* 支持静态类及方法调用,
* 支持Map
*/
@SuppressWarnings("unchecked")
public static <E> E invokeGetterCache(Object obj, String propertyName) {
Object object = obj;
for (String name : StringUtils.split(propertyName, ".")){
if (obj instanceof Map){
object = ((Map)obj).get(name);
}else{
String methodName = GETTER_PREFIX + StringUtils.capitalize(name);
object = ReflectUtils.invokeMethodByName(object, methodName);
}
}
return (E)object;
}
/**
* 调用Setter方法仅匹配方法名
* 支持多级,如:对象名.对象名.方法,
* 支持静态类及方法调用,
* 支持Map
*/
@SuppressWarnings("unchecked")
public static <E> void invokeSetter(Object obj, String propertyName, E value) {
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i=0; i<names.length; i++){
if(i<names.length-1){
if (obj instanceof Map){
object = ((Map)obj).get(names[i]);
}else{
String methodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
Object childObj = ReflectUtils.invokeMethodByName(object, methodName);
// 如果 get 获取对象为空,并且返回值类型继承自 BaseEntity则 new 对象,并通过 set 赋予它
if (childObj == null && object != null){
Method method = getAccessibleMethod(object, methodName, new Class[] {});
if (method != null) {
Class<?> returnType = method.getReturnType();
try {
if (baseEntityClass == null) {
baseEntityClass = Class.forName("com.jeesite.common.entity.BaseEntity");
}
if (baseEntityClass.isAssignableFrom(returnType)) {
childObj = returnType.getDeclaredConstructor().newInstance();
methodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, methodName, new Object[] { childObj });
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
object = childObj;
}
}else{
if (obj instanceof Map){
((Map)obj).put(names[i], value);
}else{
String methodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, methodName, new Object[] { value });
}
}
}
}
/**
* 调用Setter方法仅匹配方法名
* 支持多级,如:对象名.对象名.方法,
* 支持静态类及方法调用,
* 支持Map
*/
@SuppressWarnings("unchecked")
public static <E> void invokeSetterCache(Object obj, String propertyName, E value) {
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i=0; i<names.length; i++){
if(i<names.length-1){
if (obj instanceof Map){
object = ((Map)obj).get(names[i]);
}else{
String methodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
Object childObj = ReflectUtils.invokeMethodByName(object, methodName);
// 如果 get 获取对象为空,并且返回值类型继承自 BaseEntity则 new 对象,并通过 set 赋予它
if (childObj == null && object != null){
Method method = getAccessibleMethod(object, methodName, new Class[] {});
if (method != null) {
Class<?> returnType = method.getReturnType();
try {
if (baseEntityClass == null) {
baseEntityClass = Class.forName("com.jeesite.common.entity.BaseEntity");
}
if (baseEntityClass.isAssignableFrom(returnType)) {
childObj = returnType.getDeclaredConstructor().newInstance();
methodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
ReflectUtils.invokeMethodByName(object, methodName, childObj);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
object = childObj;
}
}else{
if (obj instanceof Map){
((Map)obj).put(names[i], value);
}else{
String methodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
ReflectUtils.invokeMethodByName(object, methodName, value);
}
}
}
}
/**
* 直接读取对象属性值无视private/protected修饰符不经过getter函数
*/
@SuppressWarnings("unchecked")
public static <E> E getFieldValue(final Object obj, final String fieldName) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
//throw new IllegalArgumentException("在 [" + 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());
}
return result;
}
/**
* 直接设置对象属性值无视private/protected修饰符不经过setter函数
*/
public static <E> void setFieldValue(final Object obj, final String fieldName, final E value) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
//throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return;
}
try {
field.set(obj, value);
} catch (IllegalAccessException e) {
logger.error("不可能抛出的异常: {}", e.getMessage());
}
}
/**
* 直接调用对象方法无视private/protected修饰符
* 用于一次性调用的情况否则应使用getAccessibleMethod()函数获得Method后反复调用
* 同时匹配方法名+参数类型,
* 支持静态类及方法调用
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
final Object[] args) {
if (obj == null || methodName == null){
return null;
}
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
//throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
if (obj != null) {
logger.debug("在 [" + (obj.getClass() == Class.class ? obj : obj.getClass()) + "] 中,没有找到 [" + methodName + "] 方法 ");
}
return null;
}
try {
return (E)method.invoke(obj.getClass() == Class.class ? null : obj, args);
} catch (Exception e) {
String msg = "method: "+method+", obj: "+obj+", args: "+args+"";
throw ReflectUtils.convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* 直接调用对象方法无视private/protected修饰符
* 用于一次性调用的情况否则应使用getAccessibleMethodByName()函数获得Method后反复调用
* 只匹配函数名,如果有多个同名函数调用第一个,
* 支持静态类及方法调用
*/
@SuppressWarnings("unchecked")
public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args) {
Method method = getAccessibleMethodByName(obj, methodName, args.length);
if (method == null) {
// 如果为空不报错,直接返回空。
// throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
if (obj != null) {
logger.debug("在 [" + (obj.getClass() == Class.class ? obj : obj.getClass()) + "] 中,没有找到 [" + methodName + "] 方法 ");
}
return null;
}
try {
// 类型转换(将参数数据类型转换为目标方法参数类型)
Class<?>[] cs = method.getParameterTypes();
for (int i=0; i<cs.length; i++){
if (args[i] != null && !args[i].getClass().equals(cs[i])){
if (cs[i] == String.class){
args[i] = ObjectUtils.toString(args[i]);
if(StringUtils.endsWith((String)args[i], ".0")){
args[i] = StringUtils.substringBefore((String)args[i], ".0");
}
}else if (cs[i] == Integer.class){
args[i] = ObjectUtils.toInteger(args[i]);
}else if (cs[i] == Long.class){
args[i] = ObjectUtils.toLong(args[i]);
}else if (cs[i] == Double.class){
args[i] = ObjectUtils.toDouble(args[i]);
}else if (cs[i] == Float.class){
args[i] = ObjectUtils.toFloat(args[i]);
}else if (cs[i] == Date.class){
if (args[i] instanceof String){
args[i] = DateUtils.parseDate(args[i]);
}else{
// POI Excel 日期格式转换
args[i] = DateUtil.getJavaDate((Double)args[i]);
}
}
}
}
return (E)method.invoke(obj.getClass() == Class.class ? null : obj, args);
} catch (Exception e) {
String msg = "method: "+method+", obj: "+obj+", args: "+args+"";
throw ReflectUtils.convertReflectionExceptionToUnchecked(msg, e);
}
}
/**
* 循环向上转型获取对象的DeclaredField并强制设置为可访问
* 如向上转型到Object仍无法找到返回null
*/
public static Field getAccessibleField(final Object obj, final String fieldName) {
// 为空不报错。直接返回 null // Validate.notNull(obj, "object can't be null");
if (obj == null){
return null;
}
Validate.notBlank(fieldName, "fieldName can't be blank");
Class<?> clazz = obj.getClass();
for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Field field = superClass.getDeclaredField(fieldName);
ReflectUtils.makeAccessible(field);
return field;
} catch (NoSuchFieldException e) {//NOSONAR
// Field不在当前类定义,继续向上转型
continue;// new add
}
}
return null;
}
/**
* 循环向上转型获取对象的DeclaredMethod,并强制设置为可访问,
* 如向上转型到Object仍无法找到返回null
* 匹配函数名+参数类型。
* 用于方法需要被多次调用的情况先使用本函数先取得Method然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes) {
// 为空不报错。直接返回 null // Validate.notNull(obj, "object can't be null");
if (obj == null){
return null;
}
Class<?> clazz = obj.getClass();
if (clazz == Class.class){
clazz = (Class) obj;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
try {
Method method = superClass.getDeclaredMethod(methodName, parameterTypes);
ReflectUtils.makeAccessible(method);
return method;
} catch (NoSuchMethodException e) {
// Method不在当前类定义,继续向上转型
continue;// new add
}
}
return null;
}
/**
* 循环向上转型获取对象的DeclaredMethod并强制设置为可访问
* 如向上转型到Object仍无法找到返回null
* 只匹配函数名。
* 用于方法需要被多次调用的情况先使用本函数先取得Method然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) {
// 为空不报错。直接返回 null // Validate.notNull(obj, "object can't be null");
if (obj == null){
return null;
}
Class<?> clazz = obj.getClass();
if (clazz == Class.class){
clazz = (Class) obj;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
Method[] methods = superClass.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) {
ReflectUtils.makeAccessible(method);
return method;
}
}
}
return null;
}
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>5.2.1-SNAPSHOT</version>
<version>5.3.1-SNAPSHOT</version>
<relativePath>../../parent/pom.xml</relativePath>
</parent>

View File

@@ -4,11 +4,6 @@
*/
package com.jeesite.modules.cms.db;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import com.jeesite.common.callback.MethodCallback;
import com.jeesite.common.config.Global;
import com.jeesite.common.tests.BaseInitDataTests;
import com.jeesite.modules.cms.dao.ArticleDao;
@@ -20,6 +15,9 @@ import com.jeesite.modules.cms.entity.Site;
import com.jeesite.modules.cms.service.CategoryService;
import com.jeesite.modules.cms.service.SiteService;
import com.jeesite.modules.gen.utils.GenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
/**
* 初始化CMS表及数据
@@ -51,72 +49,60 @@ public class InitCmsData extends BaseInitDataTests {
@Autowired
private SiteService siteService;
public void initSite() throws Exception{
initExcelData(Site.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
Site entity = (Site)params[1];
entity.setIsNewRecord(true);
siteService.save(entity);
return null;
}
initExcelData(Site.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
Site entity = (Site)params[1];
entity.setIsNewRecord(true);
siteService.save(entity);
return null;
}
return null;
});
}
@Autowired
private CategoryService categoryService;
public void initCategory() throws Exception{
initExcelData(Category.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
Category entity = (Category)params[1];
entity.setIsNewRecord(true);
categoryService.save(entity);
return null;
}
initExcelData(Category.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
Category entity = (Category)params[1];
entity.setIsNewRecord(true);
categoryService.save(entity);
return null;
}
return null;
});
}
@Autowired
private ArticleDao articleDao;
public void initArticle() throws Exception{
initExcelData(Article.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
Article entity = (Article)params[1];
entity.setIsNewRecord(true);
articleDao.insert(entity);
return null;
}
initExcelData(Article.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
Article entity = (Article)params[1];
entity.setIsNewRecord(true);
articleDao.insert(entity);
return null;
}
return null;
});
}
@Autowired
private ArticleDataDao articleDataDao;
public void initArticleData() throws Exception{
initExcelData(ArticleData.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
ArticleData entity = (ArticleData)params[1];
entity.setIsNewRecord(true);
articleDataDao.insert(entity);
return null;
}
initExcelData(ArticleData.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
ArticleData entity = (ArticleData)params[1];
entity.setIsNewRecord(true);
articleDataDao.insert(entity);
return null;
}
return null;
});
}

View File

@@ -4,13 +4,6 @@
*/
package com.jeesite.modules.cms.entity;
import java.util.Date;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.jeesite.common.entity.BaseEntity;
import com.jeesite.common.entity.DataEntity;
@@ -20,6 +13,11 @@ import com.jeesite.common.mybatis.annotation.Table;
import com.jeesite.common.mybatis.mapper.query.QueryType;
import com.jeesite.modules.cms.utils.CmsUtils;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Date;
/**
* 文章表Entity
* @author 长春叭哥、ThinkGem
@@ -45,7 +43,12 @@ import com.jeesite.modules.cms.utils.CmsUtils;
@Column(name = "word_count", attrName = "wordCount", label = "字数", comment = "字数不包含html"),
@Column(name = "custom_content_view", attrName = "customContentView", label = "自定义内容视图"),
@Column(name = "view_config", attrName = "viewConfig", label = "视图配置"),
@Column(includeEntity = DataEntity.class),
@Column(name="status", attrName="status", label="状态", isUpdate=false),
@Column(name="create_by", attrName="createBy", label="创建者", isUpdate=true),
@Column(name="create_date", attrName="createDate", label="创建时间", isUpdate=false, isQuery=false),
@Column(name="update_by", attrName="updateBy", label="更新者", isUpdate=true),
@Column(name="update_date", attrName="updateDate", label="更新时间", isUpdate=true, isQuery=false),
@Column(name="remarks", attrName="remarks", label="备注信息", queryType=QueryType.LIKE),
@Column(includeEntity = BaseEntity.class),
}, joinTable = {
@JoinTable(entity = Category.class, alias = "c",
@@ -83,12 +86,13 @@ public class Article extends DataEntity<Article> {
private Integer wordCount; // 字数不包含html
private String customContentView; // 自定义内容视图
private String viewConfig; // 视图配置
private ArticleData articleData; //文章副表
private Boolean isQueryArticleData; // 是否查询文章内容
private Date beginDate; // 开始时间
private Date endDate; // 结束时间
private Boolean isQueryArticleData; // 是否查询文章内容
public Article() {
super();
//this.weight = 0;
@@ -223,8 +227,6 @@ public class Article extends DataEntity<Article> {
this.hits = hits;
}
public Integer getHitsPlus() {
return hitsPlus;
}
@@ -275,6 +277,18 @@ public class Article extends DataEntity<Article> {
this.articleData = articleData;
}
/**
* 是否查询文章内容
* @return
*/
public Boolean getIsQueryArticleData() {
return isQueryArticleData;
}
public void setIsQueryArticleData(Boolean isQueryArticleData) {
this.isQueryArticleData = isQueryArticleData;
}
public Date getBeginDate() {
return beginDate;
}
@@ -291,20 +305,6 @@ public class Article extends DataEntity<Article> {
this.endDate = endDate;
}
/**
* 是否查询文章内容
* @return
*/
public Boolean getIsQueryArticleData() {
return isQueryArticleData;
}
public void setIsQueryArticleData(Boolean isQueryArticleData) {
this.isQueryArticleData = isQueryArticleData;
}
public String getUrl() {
return CmsUtils.getUrlDynamic(this);
}

View File

@@ -4,20 +4,20 @@
*/
package com.jeesite.modules.cms.entity;
import java.util.List;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import com.jeesite.common.config.Global;
import com.jeesite.common.entity.DataEntity;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.mybatis.annotation.Column;
import com.jeesite.common.mybatis.annotation.Table;
import com.jeesite.common.mybatis.mapper.query.QueryType;
import com.jeesite.modules.cms.utils.CmsUtils;
import com.jeesite.modules.sys.utils.CorpUtils;
import com.jeesite.modules.sys.utils.UserUtils;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.List;
/**
* 站点表Entity
* @author 长春叭哥、ThinkGem
@@ -209,15 +209,16 @@ public class Site extends DataEntity<Site> {
this.categoryList = categoryList;
}
/**
* 判断是否为当前站点
*/
public Boolean getIsCurrentSite(){
return getCurrentSiteCode().equals(siteCode);
}
public String getUrl() {
return CmsUtils.getUrlDynamic(this);
}
/**
* 判断是否为默认(主站)站点

View File

@@ -79,7 +79,7 @@ public class ArticleService extends CrudService<ArticleDao, Article> {
/**
* 查询分页数据
* @param article 查询条件
* @param article.page 分页对象
* @param article page 分页对象
* @return
*/
@Override

View File

@@ -4,18 +4,17 @@
*/
package com.jeesite.modules.cms.service;
import java.util.List;
import org.apache.commons.text.StringEscapeUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.service.TreeService;
import com.jeesite.modules.cms.dao.CategoryDao;
import com.jeesite.modules.cms.entity.Category;
import com.jeesite.modules.cms.utils.CmsUtils;
import com.jeesite.modules.file.utils.FileUploadUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* 栏目表Service
@@ -75,7 +74,7 @@ public class CategoryService extends TreeService<CategoryDao, Category> {
@Override
protected void updateChildNode(Category childEntity, Category parentEntity) {
childEntity.setSite(parentEntity.getSite());
childEntity.getSqlMap().updateTreeDataExtSql("site_code = #{site.siteCode}");
childEntity.sqlMap().updateTreeDataExtSql("site_code = #{site.siteCode}");
super.updateChildNode(childEntity, parentEntity);
}

View File

@@ -4,14 +4,6 @@
*/
package com.jeesite.modules.cms.utils;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import org.springframework.ui.Model;
import com.jeesite.common.cache.CacheUtils;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.config.Global;
@@ -26,6 +18,12 @@ import com.jeesite.modules.cms.entity.Site;
import com.jeesite.modules.cms.service.ArticleService;
import com.jeesite.modules.cms.service.CategoryService;
import com.jeesite.modules.cms.service.SiteService;
import org.springframework.ui.Model;
import javax.servlet.ServletContext;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* CmsUtils
@@ -45,7 +43,6 @@ public class CmsUtils {
/**
* 获得当前站点信息
* @param siteCode 站点编号
*/
public static Site getCurrentSite() {
return getSite(Site.getCurrentSiteCode());
@@ -191,7 +188,7 @@ public class CmsUtils {
* @param siteCode 站点编号
* @param categoryCode 分类编号
* @param number 获取数目
* @param param 预留参数,例: key1:'value1', key2:'value2' ...<br>
* @param params 预留参数,例: key1:'value1', key2:'value2' ...<br>
* posid : 推荐位1首页焦点图2栏目页文章推荐<br>
* image : 文章图片1有图片的文章<br>
* isQueryArticleData : 是否查询文章详情信息,查询会影响效率<br>
@@ -298,6 +295,26 @@ public class CmsUtils {
return str.toString();
}
/**
* 获得站点动态URL地址
* @param site
* @return url
*/
public static String getUrlDynamic(Site site) {
StringBuilder str = new StringBuilder();
str.append(Static.context.getContextPath()).append(Global.getFrontPath());
if (StringUtils.isNotBlank(site.getDomain())) {
if (site.getDomain().contains("://")) {
return site.getDomain();
} else {
str.append(site.getDomain());
return str.toString();
}
}
str.append("/index-").append(site.getSiteCode()).append(".html");
return str.toString();
}
/**
* 获得栏目动态URL地址
* @param category

View File

@@ -4,22 +4,6 @@
*/
package com.jeesite.modules.cms.web;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.jeesite.common.config.Global;
import com.jeesite.common.entity.Page;
import com.jeesite.common.lang.StringUtils;
@@ -33,6 +17,20 @@ import com.jeesite.modules.cms.service.CategoryService;
import com.jeesite.modules.cms.service.FileTempleteService;
import com.jeesite.modules.cms.utils.CmsUtils;
import com.jeesite.modules.sys.utils.UserUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* 文章表Controller
@@ -100,12 +98,12 @@ public class ArticleController extends BaseController {
if (!(isAll != null && isAll)) {
articleService.addDataScopeFilter(article);
}
if (!article.getCurrentUser().isAdmin()) {
if (!article.currentUser().isAdmin()) {
// 如果没有审核权限,或者 草稿状态的文章 则只查看自己创建的文章。
if (!UserUtils.getSubject().isPermitted("cms:article:audit")) {
article.setCreateBy(article.getCurrentUser().getUserCode());
article.setCreateBy(article.currentUser().getUserCode());
} else if (Article.STATUS_DRAFT.equals(article.getStatus())) {
article.setCreateBy(article.getCurrentUser().getUserCode());
article.setCreateBy(article.currentUser().getUserCode());
}
}
Page<Article> page = articleService.findPage(article);

View File

@@ -4,20 +4,6 @@
*/
package com.jeesite.modules.cms.web;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.collect.MapUtils;
import com.jeesite.common.config.Global;
@@ -33,6 +19,20 @@ import com.jeesite.modules.cms.utils.CmsUtils;
import com.jeesite.modules.sys.entity.Office;
import com.jeesite.modules.sys.utils.DictUtils;
import com.jeesite.modules.sys.utils.UserUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* 栏目表Controller
@@ -252,7 +252,7 @@ public class CategoryController extends BaseController {
* @param isShowCode 是否显示编码true or 1显示在左侧2显示在右侧false or null不显示
* @return
*/
@RequiresPermissions("cms:category:view")
@RequiresPermissions(value = {"cms:category:view", "cms:article:view"}, logical = Logical.OR)
@RequestMapping(value = "treeData")
@ResponseBody
public List<Map<String, Object>> treeData(String siteCode, String module, String excludeCode, Boolean isAll, String isShowCode) {

View File

@@ -13,4 +13,6 @@
5.0.2
5.1.0
5.2.0
5.2.1
5.2.1
5.3.0
5.3.1

View File

@@ -2,15 +2,23 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jeesite.modules.cms.dao.ArticleDao">
<!-- 查询数据
<select id="findList" resultType="CmsArticle">
<!-- 查询数据 -->
<select id="findList" resultType="Article">
SELECT ${sqlMap.column.toSql()}
<if test="isQueryArticleData">,
ad.content AS "articleData.content",
ad.relation AS "articleData.relation",
ad.is_can_comment AS "articleData.isCanComment"
</if>
FROM ${sqlMap.table.toSql()}
<if test="isQueryArticleData">
JOIN ${_prefix}cms_article_data ad ON ad.id = a.id
</if>
<where>
${sqlMap.where.toSql()}
</where>
ORDER BY ${sqlMap.order.toSql()}
</select> -->
</select>
<update id="updateExpiredWeight">
update ${_prefix}cms_article SET weight = 0

View File

@@ -1,4 +1,4 @@
body{padding-top:50px;font-size:14px;}
body{padding-top:50px;font-size:15px;background:#f7f8f9;}
body>.navbar{-webkit-transition:background-color .3s ease-in;transition:background-color .3s ease-in}
@media (min-width:768px){
body>.navbar-transparent{background-color:transparent}
@@ -51,20 +51,34 @@ footer p{clear:left;margin-bottom:0}
#banner{margin-bottom:2em;text-align:center}
}
.jumbotron {background:#f1f1f1;margin:48px auto;}
.panel-title small .more {padding-top:4px;}
.breadcrumb {border-radius:8px;background:transparent;padding:0;margin:2px 15px 21px 15px;}
.jumbotron {background:#fff;margin:48px auto;border:1px solid #ededed;box-shadow:0 1px 4px 0 rgb(0 0 0 / 5%);border-radius:8px!important;}
.jumbotron h1, .jumbotron .h1 {font-size:43px;margin: 0 0 30px;}
.jumbotron .btn-sm {font-size:17px;}
.panel {border-radius:8px}
.panel-heading {border-radius:8px 8px 0 0}
.panel-footer {border-radius:0 0 8px 8px}
.panel-title {font-size:18px;}
.panel-title small .more {padding-top:4px;font-size:14px}
.nav-search {margin-top:9px;}
.nav-search .form-control {height:30px;padding:5px;}
.nav-search .btn {height:31px;padding:5px 10px;}
.main {background:#fff;box-shadow:0 1px 4px 0 rgb(0 0 0 / 8%);border-radius:0 0 8px 8px;padding:20px 10px;margin:0 -1px}
.main-list {border-radius:8px;}
.main-right::before {content:'';border-left:1px solid #e6e6e6;position:absolute;height:100%;left:-20px;}
.article-list {padding:5px;margin:0;}
.article-list li {list-style:none;padding:8px 0;}
.article-title {color:#555555;font-size:20px;text-align:center;border-bottom:1px solid #ddd;padding:15px 20px 20px 20px;margin-bottom:30px;}
.article-info {border-top:1px solid #ddd;padding:10px;margin:25px 0 0;}
.article-desc {padding:8px 10px 8px;margin:10px 20px 20px 35px;font-size:13px;}
.article-content {padding-top:10px;}
.article-view {border-radius:8px;padding:30px 50px;}
.article-title {color:#333;font-size:30px;text-align:center;border-bottom:1px solid #ddd;padding:15px 20px 20px 20px;margin-bottom:30px;}
.article-info {border-top:1px solid #ddd;padding:10px;margin:30px 0 0;}
.article-desc {padding:8px 10px 8px;margin:10px 20px 20px 35px;font-size:14px;}
.article-content {padding-top:20px;}
.pagination {margin:8px 0;display:block;/* text-align:center; */font-size:13px;} /* .pagination .controls a{border:0;} */
.pagination>li>a, .pagination>li>span {min-width:37px;text-align:center;padding:6px;border:1px solid #ddd;background:transparent;/* border-radius:3px; */}

View File

@@ -143,7 +143,7 @@
</div>
</div>
</div>
<div class="col-xs-6">
<!--<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4">${text('推荐位')}</label>
<div class="col-sm-8">
@@ -162,14 +162,14 @@
<#form:select path="state" dictType="sys_status" blankOption="true" class="form-control" />
</div>
</div>
</div>
</div>-->
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-sm-4" title="${text('可修改发布时间,不填则使用当前时间')}">
${text('发布时间')} <i class="fa icon-question"></i></label>
<div class="col-sm-8">
<#form:input path="createDate" readonly="true" maxlength="20" class="form-control Wdate"
dataFormat="datetime" onclick="WdatePicker({dateFmt:'yyyy-MM-dd HH:mm',isShowClear:false});"/>
<#form:input path="createDate" readonly="true" maxlength="20" class="form-control laydate"
dataFormat="datetime" data-type="datetime" data-format="yyyy-MM-dd HH:mm"/>
</div>
</div>
</div>
@@ -208,7 +208,7 @@
</div>
</div>
</div>
<#form:extend collapsed="true" />
<#form:extend collapsed="true" pathPrefix="articleData"/>
<div class="box-footer">
<div class="row">
<div class="col-sm-offset-2 col-sm-10">

View File

@@ -42,7 +42,7 @@
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
</div>
</#form:form>
<table id="dataGrid"></table>

View File

@@ -58,7 +58,7 @@
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
</div>
</#form:form>
<table id="dataGrid"></table>

View File

@@ -1,18 +1,18 @@
<% layout('/layouts/default.html', {title: '文章评论表管理', libs: ['dataGrid']}){ %>
<div class="main-content">
<div class="box box-main">
<div class="box-header">
<div class="box-title">
<i class="fa fa-list-alt"></i> ${text('文章评论表管理')}
</div>
<div class="box-tools pull-right">
<a href="#" class="btn btn-default" id="btnSearch" title="${text('查询')}"><i class="fa fa-filter"></i> ${text('查询')}</a>
<% if(hasPermi('cms:comment:edit')){ %>
<a href="${ctx}/cms/comment/form" class="btn btn-default btnTool" title="${text('新增文章评论表')}"><i class="fa fa-plus"></i> ${text('新增')}</a>
<% } %>
</div>
</div>
<div class="box-body">
<% layout('/layouts/default.html', {title: '文章评论表管理', libs: ['dataGrid']}){ %>
<div class="main-content">
<div class="box box-main">
<div class="box-header">
<div class="box-title">
<i class="fa fa-list-alt"></i> ${text('文章评论表管理')}
</div>
<div class="box-tools pull-right">
<a href="#" class="btn btn-default" id="btnSearch" title="${text('查询')}"><i class="fa fa-filter"></i> ${text('查询')}</a>
<% if(hasPermi('cms:comment:edit')){ %>
<a href="${ctx}/cms/comment/form" class="btn btn-default btnTool" title="${text('新增文章评论表')}"><i class="fa fa-plus"></i> ${text('新增')}</a>
<% } %>
</div>
</div>
<div class="box-body">
<#form:form id="searchForm" model="${comment}" action="${ctx}/cms/comment/listData" method="post" class="form-inline hide"
data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
<div class="form-group">
@@ -95,56 +95,56 @@
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
</div>
</#form:form>
<table id="dataGrid"></table>
<div id="dataGridPage"></div>
</div>
</div>
</div>
<% } %>
<script>
// 初始化DataGrid对象
$('#dataGrid').dataGrid({
searchForm: $("#searchForm"),
columnModel: [
{header:'${text('栏目编码')}', name:'categoryCode', index:'a.category_code', width:150, align:"left", frozen:true, formatter: function(val, obj, row, act){
return '<a href="${ctx}/cms/comment/form?id='+row.id+'" class="btnList" data-title="${text('编辑文章评论表')}">'+(val||row.id)+'</a>';
}},
{header:'${text('内容编号')}', name:'articleId', index:'a.article_id', width:150, align:"left"},
{header:'${text('父级评论')}', name:'parentId', index:'a.parent_id', width:150, align:"left"},
{header:'${text('内容标题')}', name:'articleTitle', index:'a.article_title', width:150, align:"left"},
{header:'${text('评论内容')}', name:'content', index:'a.content', width:150, align:"left"},
{header:'${text('评论姓名')}', name:'name', index:'a.name', width:150, align:"left"},
{header:'${text('评论IP')}', name:'ip', index:'a.ip', width:150, align:"left"},
{header:'${text('创建时间')}', name:'createDate', index:'a.create_date', width:150, align:"center"},
{header:'${text('审核人')}', name:'auditUserCode', index:'a.audit_user_code', width:150, align:"left"},
{header:'${text('审核时间')}', name:'auditDate', index:'a.audit_date', width:150, align:"center"},
{header:'${text('审核意见')}', name:'auditComment', index:'a.audit_comment', width:150, align:"left"},
{header:'${text('支持数')}', name:'hitsPlus', index:'a.hits_plus', width:150, align:"center"},
{header:'${text('反对数')}', name:'hitsMinus', index:'a.hits_minus', width:150, align:"center"},
{header:'${text('状态')}', name:'status', index:'a.status', width:150, align:"center", formatter: function(val, obj, row, act){
return js.getDictLabel(${@DictUtils.getDictListJson('sys_search_status')}, val, '${text('未知')}', true);
}},
{header:'${text('操作')}', name:'actions', width:120, formatter: function(val, obj, row, act){
var actions = [];
<% if(hasPermi('cms:comment:edit')){ %>
actions.push('<a href="${ctx}/cms/comment/form?id='+row.id+'" class="btnList" title="${text('编辑文章评论表')}"><i class="fa fa-pencil"></i></a>&nbsp;');
if (row.status == Global.STATUS_NORMAL){
actions.push('<a href="${ctx}/cms/comment/disable?id='+row.id+'" class="btnList" title="${text('停用文章评论表')}" data-confirm="${text('确认要停用该文章评论表吗')}"><i class="glyphicon glyphicon-ban-circle"></i></a>&nbsp;');
}
if (row.status == Global.STATUS_DISABLE){
actions.push('<a href="${ctx}/cms/comment/enable?id='+row.id+'" class="btnList" title="${text('启用文章评论表')}" data-confirm="${text('确认要启用该文章评论表吗')}"><i class="glyphicon glyphicon-ok-circle"></i></a>&nbsp;');
}
actions.push('<a href="${ctx}/cms/comment/delete?id='+row.id+'" class="btnList" title="${text('删除文章评论表')}" data-confirm="${text('确认要删除该文章评论表吗')}"><i class="fa fa-trash-o"></i></a>&nbsp;');
<% } %>
return actions.join('');
}}
],
// 加载成功后执行事件
ajaxSuccess: function(data){
}
});
<table id="dataGrid"></table>
<div id="dataGridPage"></div>
</div>
</div>
</div>
<% } %>
<script>
// 初始化DataGrid对象
$('#dataGrid').dataGrid({
searchForm: $("#searchForm"),
columnModel: [
{header:'${text('栏目编码')}', name:'categoryCode', index:'a.category_code', width:150, align:"left", frozen:true, formatter: function(val, obj, row, act){
return '<a href="${ctx}/cms/comment/form?id='+row.id+'" class="btnList" data-title="${text('编辑文章评论表')}">'+(val||row.id)+'</a>';
}},
{header:'${text('内容编号')}', name:'articleId', index:'a.article_id', width:150, align:"left"},
{header:'${text('父级评论')}', name:'parentId', index:'a.parent_id', width:150, align:"left"},
{header:'${text('内容标题')}', name:'articleTitle', index:'a.article_title', width:150, align:"left"},
{header:'${text('评论内容')}', name:'content', index:'a.content', width:150, align:"left"},
{header:'${text('评论姓名')}', name:'name', index:'a.name', width:150, align:"left"},
{header:'${text('评论IP')}', name:'ip', index:'a.ip', width:150, align:"left"},
{header:'${text('创建时间')}', name:'createDate', index:'a.create_date', width:150, align:"center"},
{header:'${text('审核人')}', name:'auditUserCode', index:'a.audit_user_code', width:150, align:"left"},
{header:'${text('审核时间')}', name:'auditDate', index:'a.audit_date', width:150, align:"center"},
{header:'${text('审核意见')}', name:'auditComment', index:'a.audit_comment', width:150, align:"left"},
{header:'${text('支持数')}', name:'hitsPlus', index:'a.hits_plus', width:150, align:"center"},
{header:'${text('反对数')}', name:'hitsMinus', index:'a.hits_minus', width:150, align:"center"},
{header:'${text('状态')}', name:'status', index:'a.status', width:150, align:"center", formatter: function(val, obj, row, act){
return js.getDictLabel(${@DictUtils.getDictListJson('sys_search_status')}, val, '${text('未知')}', true);
}},
{header:'${text('操作')}', name:'actions', width:120, formatter: function(val, obj, row, act){
var actions = [];
//<% if(hasPermi('cms:comment:edit')){ %>
actions.push('<a href="${ctx}/cms/comment/form?id='+row.id+'" class="btnList" title="${text('编辑文章评论表')}"><i class="fa fa-pencil"></i></a>&nbsp;');
if (row.status == Global.STATUS_NORMAL){
actions.push('<a href="${ctx}/cms/comment/disable?id='+row.id+'" class="btnList" title="${text('停用文章评论表')}" data-confirm="${text('确认要停用该文章评论表吗')}"><i class="glyphicon glyphicon-ban-circle"></i></a>&nbsp;');
}
if (row.status == Global.STATUS_DISABLE){
actions.push('<a href="${ctx}/cms/comment/enable?id='+row.id+'" class="btnList" title="${text('启用文章评论表')}" data-confirm="${text('确认要启用该文章评论表吗')}"><i class="glyphicon glyphicon-ok-circle"></i></a>&nbsp;');
}
actions.push('<a href="${ctx}/cms/comment/delete?id='+row.id+'" class="btnList" title="${text('删除文章评论表')}" data-confirm="${text('确认要删除该文章评论表吗')}"><i class="fa fa-trash-o"></i></a>&nbsp;');
//<% } %>
return actions.join('');
}}
],
// 加载成功后执行事件
ajaxSuccess: function(data){
}
});
</script>

View File

@@ -47,7 +47,7 @@
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
</div>
</#form:form>
<table id="dataGrid"></table>

View File

@@ -41,7 +41,7 @@
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
</div>
</#form:form>
<table id="dataGrid"></table>

View File

@@ -54,7 +54,7 @@
<div class="form-group">
<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
<button type="reset" class="btn btn-default btn-sm isQuick">${text('重置')}</button>
</div>
</#form:form>
<table id="dataGrid"></table>

View File

@@ -1,15 +1,15 @@
<div class="row"><br/>
<ul class="breadcrumb">
<li><span style="color:#999;">当前位置:</span><a href="${ctx}/index-${site.siteCode}">首页</a></li>
<li><span style="color:#999;">当前位置:</span><a href="${site.url}">首页</a></li>
<%
var pcs = @StringUtils.split(category.parentCodes, ',');
var tns = @StringUtils.split(category.treeNames, '/');
for(var i = 0; i < pcs.~size - 1; i++){
%>
<li><a href="${ctx}/list-${pcs[i+1]}">${tns[i]}</a></li>
<li><a href="${ctx}/list-${pcs[i+1]}.html">${tns[i]}</a></li>
<%
}
%>
<li><a href="${ctx}/list-${category.categoryCode}">${category.categoryName}</a></li>
<li><a href="${category.url}">${category.categoryName}</a></li>
</ul>
</div>

View File

@@ -4,7 +4,7 @@
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a href="${ctx}/index-${site.siteCode}" class="navbar-brand">${site.title}</a>
<a href="${site.url}" class="navbar-brand">${site.title}</a>
<button class="navbar-toggle" type="button" data-toggle="collapse" data-target="#navbar-main">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
@@ -16,16 +16,15 @@
<#html:foreach items="${categoryList(site.siteCode, '0', 4, '')}" var="c">
<#html:if test="${c.inMenu == @Global.YES}">
<li class="${c.categoryCode == category.categoryCode! ? 'active' : ''}"><a
href="${ctx}/list-${c.categoryCode}">${c.categoryName}</a></li>
href="${c.url}">${c.categoryName}</a></li>
</#html:if>
</#html:foreach>
<li><a href="http://jeesite.com" target="_blank">官方网站</a></li>
<li><a href="http://s.jeesite.com" target="_blank">技术服务</a></li>
<li id="siteSwitch" class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#" title="站点">子站切换 <span class="caret"></span></a>
<ul class="dropdown-menu">
<#html:foreach items="${siteList()}" var="site,status">
<li><a href="#" onclick="location='${ctx}/index-${site.id}'">${site.title}</a></li>
<li><a href="#" onclick="location='${site.url}'">${site.title}</a></li>
</#html:foreach>
</ul>
</li>
@@ -36,7 +35,7 @@
</ul>
</li> -->
</ul>
<ul class="nav navbar-nav navbar-right">
<ul class="nav navbar-nav navbar-right hidden-xs hidden-sm">
<form class="navbar-form navbar-left nav-search" action="${ctx}/search">
<div class="form-group">
<input type="text" name="q" class="form-control" placeholder="全站搜索...">

View File

@@ -15,7 +15,7 @@
<div class="bs-component">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><small><a href="${ctx}/list-${category.categoryCode}" class="pull-right more">更多&gt;&gt;</a></small>${category.categoryName}</h3>
<h3 class="panel-title"><small><a href="${category.url}" class="pull-right more">更多&gt;&gt;</a></small>${category.categoryName}</h3>
</div>
<div class="panel-body">
<ul class="article-list">

View File

@@ -1,7 +1,7 @@
<% layout('layouts/default.html', {title: '列表页面', libs: []}){ %>
<% include('include/banner.html'){} %>
<div class="row">
<div class="col-xs-2">
<div class="row main main-list">
<div class="col-sm-2 col-xs-12 main-left">
<h4>栏目列表</h4>
<ul class="article-list">
<#html:foreach items="${qmark(categoryList! != null, categoryList!, categoryList(site.siteCode, category.parentCode, 50, ''))}" var="category,status">
@@ -9,7 +9,7 @@
</#html:foreach>
</ul>
</div>
<div class="col-xs-10">
<div class="col-sm-10 col-xs-12 main-right">
<h4>${category.categoryName}</h4>
<#html:if test="${page! != null && category.moduleType == 'article'}">
<ul class="article-list">
@@ -21,7 +21,7 @@
<div class="pagination">${@page.toHtml()}</div>
<script type="text/javascript">
function page(n,s){
location="${ctx}/list-${category.categoryCode}?pageNo="+n+"&pageSize="+s;
location="${category.url}?pageNo="+n+"&pageSize="+s;
}
</script>
</#html:if>

View File

@@ -1,7 +1,7 @@
<% layout('layouts/default.html', {title: '列表页面', libs: []}){ %>
<% include('include/banner.html'){} %>
<div class="row">
<div class="col-xs-2">
<div class="row main main-list">
<div class="col-sm-2 col-xs-12 main-left">
<h4>栏目列表</h4>
<ul class="article-list">
<#html:foreach items="${qmark(categoryList! != null, categoryList!, categoryList(site.siteCode, category.parentCode, 50, ''))}" var="category,status">
@@ -9,7 +9,7 @@
</#html:foreach>
</ul>
</div>
<div class="col-xs-10">
<div class="col-sm-10 col-xs-12 main-right">
<h4>${category.categoryName}</h4>
<div class="row"><br/>
<#html:foreach items="${qmark(categoryList! != null, categoryList!, [])}" var="category,status">
@@ -18,7 +18,7 @@
<div class="bs-component">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><small><a href="${ctx}/list-${category.categoryCode}" class="pull-right more">更多&gt;&gt;</a></small>${category.categoryName}</h3>
<h3 class="panel-title"><small><a href="${category.url}" class="pull-right more">更多&gt;&gt;</a></small>${category.categoryName}</h3>
</div>
<div class="panel-body">
<ul class="article-list">

View File

@@ -1,6 +1,6 @@
<% layout('layouts/default.html', {title: '站点地图', libs: []}){ %>
<style type="text/css">
h2 {padding-left:10px;}
h2 {padding-left:10px;text-align:center;}
h3.title {padding:5px 5px;margin:15px 8px 10px;}
dl.map{border:1px solid #ddd;border-top:0;margin:10px 8px 8px;}
dl.map dt{border-top:1px solid #ddd;padding:10px 15px;} dl.map dd{margin:20px 30px 30px;}
@@ -8,7 +8,7 @@
dl.map span:hover{border:1px solid #bbb;background:#f1f1f1;}
dl.map span a:hover{text-decoration:none;color:#333;}
</style>
<div class="row">
<div class="row main">
<h2>站点地图</h2>
<#html:foreach items="${siteList()}" var="site">
<h3 class="title breadcrumb">${site.siteName}</h3>

View File

@@ -37,7 +37,7 @@ $(function(){
laydate.render({elem:'#ed', type:'date', format:'yyyy-MM-dd'});
});
</script>
<div class="row">
<div class="row main">
<form id="searchForm" method="get" class="search">
<input type="hidden" id="pageNo" name="pageNo" value="${page.pageNo!}"/>
<input type="hidden" id="t" name="t" value="${isNotBlank(t)?t:'article'}"/>

View File

@@ -1,6 +1,6 @@
<% layout('layouts/default.html', {title:'文章查看',libs: []}){ %>
<% include('include/banner.html'){} %>
<div class="row article-view">
<div class="row main article-view">
<h3 class="article-title">${article.title}</h3>
<blockquote class="article-desc">摘要:${article.description}</blockquote>
<div class="article-content uparse">${article.articleData.content}</div>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>5.2.1-SNAPSHOT</version>
<version>5.3.1-SNAPSHOT</version>
<relativePath>../../parent/pom.xml</relativePath>
</parent>
@@ -40,11 +40,13 @@
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>19.3.0.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>orai18n</artifactId>
<version>19.3.0.0</version>
<scope>runtime</scope>
</dependency> -->
<!-- SqlServer 2008 -->
@@ -86,13 +88,6 @@
<version>${project.parent.version}</version>
</dependency>
<!-- Core Extend
<dependency>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-module-core-extend</artifactId>
<version>${project.parent.version}</version>
</dependency> -->
</dependencies>
<developers>

View File

@@ -4,19 +4,20 @@
*/
package com.jeesite.common.shiro.filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jeesite.common.lang.ExceptionUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.shiro.realm.BaseAuthorizingRealm;
import com.jeesite.common.web.http.ServletUtils;
import com.jeesite.modules.sys.utils.UserUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;
import com.jeesite.common.lang.ExceptionUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.shiro.realm.BaseAuthorizingRealm;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* CAS过滤器
@@ -25,13 +26,17 @@ import com.jeesite.common.shiro.realm.BaseAuthorizingRealm;
*/
@SuppressWarnings("deprecation")
public class CasFilter extends org.apache.shiro.cas.CasFilter {
private BaseAuthorizingRealm authorizingRealm;
/**
* 登录成功调用事件
*/
@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
return FormFilter.onLoginSuccess((HttpServletRequest)request, (HttpServletResponse)response);
authorizingRealm.onLoginSuccess(UserUtils.getLoginInfo(), (HttpServletRequest)request);
ServletUtils.redirectUrl((HttpServletRequest)request, (HttpServletResponse)response, getSuccessUrl());
return false;
}
/**
@@ -41,12 +46,7 @@ public class CasFilter extends org.apache.shiro.cas.CasFilter {
protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException ae, ServletRequest request, ServletResponse response) {
Subject subject = getSubject(request, response);
if (subject.isAuthenticated() || subject.isRemembered()) {
try {
// AJAX不支持Redirect改用Forward
request.getRequestDispatcher(getSuccessUrl()).forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
ServletUtils.redirectUrl((HttpServletRequest)request, (HttpServletResponse)response, getSuccessUrl());
return false;
} else {
try {
@@ -66,7 +66,7 @@ public class CasFilter extends org.apache.shiro.cas.CasFilter {
}
public void setAuthorizingRealm(BaseAuthorizingRealm authorizingRealm) {
this.authorizingRealm = authorizingRealm;
}
}

View File

@@ -4,29 +4,6 @@
*/
package com.jeesite.common.shiro.filter;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.servlet.Cookie.SameSiteOptions;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jeesite.common.codec.DesUtils;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.collect.MapUtils;
@@ -43,6 +20,27 @@ import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.utils.LogUtils;
import com.jeesite.modules.sys.utils.UserUtils;
import com.jeesite.modules.sys.utils.ValidCodeUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.Cookie.SameSiteOptions;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
/**
* 表单验证(包含验证码)过滤类
@@ -59,7 +57,7 @@ public class FormFilter extends org.apache.shiro.web.filter.authc.FormAuthentica
private static final Logger logger = LoggerFactory.getLogger(FormFilter.class);
private static FormFilter instance;
private BaseAuthorizingRealm authorizingRealm;
private Cookie rememberUserCodeCookie; // 记住用户名Cookie
@@ -73,7 +71,8 @@ public class FormFilter extends org.apache.shiro.web.filter.authc.FormAuthentica
rememberUserCodeCookie.setPath(Global.getProperty("session.sessionIdCookiePath"));
rememberUserCodeCookie.setSecure(Global.getPropertyToBoolean("session.sessionIdCookieSecure", "false"));
rememberUserCodeCookie.setHttpOnly(Global.getPropertyToBoolean("session.sessionIdCookieHttpOnly", "true"));
rememberUserCodeCookie.setSameSite(SameSiteOptions.valueOf(Global.getProperty("session.sessionIdCookieSameSite", "LAX")));
String sameSite = Global.getProperty("session.sessionIdCookieSameSite", "Lax"); // Null、None、Lax、Strict
rememberUserCodeCookie.setSameSite(!"Null".equalsIgnoreCase(sameSite) ? SameSiteOptions.valueOf(StringUtils.upperCase(sameSite)) : null);
rememberUserCodeCookie.setMaxAge(Cookie.ONE_YEAR);
instance = this;
}
@@ -295,15 +294,16 @@ public class FormFilter extends org.apache.shiro.web.filter.authc.FormAuthentica
* 登录成功调用事件
*/
@Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest servletRequest, ServletResponse response) throws Exception {
HttpServletRequest request = (HttpServletRequest)servletRequest;
// 登录成功后初始化授权信息并处理登录后的操作
authorizingRealm.onLoginSuccess(UserUtils.getLoginInfo(), (HttpServletRequest)request);
// AJAX不支持Redirect改用Forward
try {
request.getRequestDispatcher(getSuccessUrl()).forward(request, response);
} catch (Exception e) {
e.printStackTrace();
authorizingRealm.onLoginSuccess(UserUtils.getLoginInfo(), request);
// 跳转到登录成功页面
String successUrl = getSuccessUrl(); // shiro.successUrl in application.yml
if (StringUtils.contains((request).getRequestURI(), "/oauth2/callback/")) {
successUrl = Global.getConfig("oauth2.successUrl", successUrl);
}
ServletUtils.redirectUrl(request, (HttpServletResponse)response, successUrl);
return false;
}
@@ -330,14 +330,9 @@ public class FormFilter extends org.apache.shiro.web.filter.authc.FormAuthentica
}
request.setAttribute(EXCEPTION_ATTRIBUTE_NAME, e);
request.setAttribute(MESSAGE_PARAM, message);
// AJAX不支持Redirect改用Forward
try {
String loginFailureUrl = Global.getProperty("adminPath")+"/loginFailure";
request.getRequestDispatcher(loginFailureUrl).forward(request, response);
} catch (Exception ex) {
ex.printStackTrace();
}
// 跳转到登录失败页面
String loginFailureUrl = Global.getProperty("adminPath") + "/loginFailure";
ServletUtils.redirectUrl((HttpServletRequest)request, (HttpServletResponse)response, loginFailureUrl);
return false;
}

View File

@@ -29,7 +29,7 @@ public class InnerFilter extends AccessControlFilter {
"shiro.innerFilterAllowRemoteAddrs", "127.0.0.1"), ",");
}
if (prefixes != null && request instanceof HttpServletRequest){
String ip = ((HttpServletRequest)request).getRemoteAddr();
String ip = request.getRemoteAddr();
for (String prefix : prefixes){
result = StringUtils.startsWithIgnoreCase(ip, StringUtils.trim(prefix));
if (result){

View File

@@ -4,12 +4,6 @@
*/
package com.jeesite.common.shiro.realm;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.codec.Sha1Utils;
import com.jeesite.common.shiro.authc.FormToken;
@@ -19,6 +13,11 @@ import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.service.UserService;
import com.jeesite.modules.sys.utils.LogUtils;
import com.jeesite.modules.sys.utils.UserUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import javax.servlet.http.HttpServletRequest;
/**
* 系统认证授权实现类
@@ -51,12 +50,13 @@ public class AuthorizingRealm extends BaseAuthorizingRealm {
/**
* 用于用户根据登录信息获取用户信息<br>
* 1、默认根据登录账号登录信息UserUtils.getByLoginCode(token.getUsername(), token.getParam("corpCode"));<br>
* 2、如果增加其它登录,请重写此方法,如根据手机号或邮箱登录返回用户信息。
* 1、默认根据登录账号登录信息UserUtils.getByLoginCode(formToken.getUsername(), formToken.getParam("corpCode"));<br>
* 2、中断操作,可抛出异常提示用户 throw new AuthenticationException("msg:登录失败");<br>
* 3、如果增加其它登录方式请重写此方法如根据手机号或邮箱登录返回用户信息。
*/
@Override
protected User getUserInfo(FormToken token) {
return super.getUserInfo(token);
protected User getUserInfo(FormToken formToken) {
return super.getUserInfo(formToken);
}
/**

View File

@@ -4,22 +4,6 @@
*/
package com.jeesite.common.shiro.realm;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ValidationException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.cas.CasToken;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.collect.MapUtils;
import com.jeesite.common.lang.ObjectUtils;
@@ -35,6 +19,20 @@ import com.jeesite.modules.sys.service.EmpUserService;
import com.jeesite.modules.sys.service.UserService;
import com.jeesite.modules.sys.utils.LogUtils;
import com.jeesite.modules.sys.utils.UserUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.cas.CasToken;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ValidationException;
import java.util.Map;
/**
* 系统认证授权实现类
@@ -181,20 +179,11 @@ public class CasAuthorizingRealm extends BaseAuthorizingRealm {
@Override
public void onLoginSuccess(LoginInfo loginInfo, HttpServletRequest request) {
super.onLoginSuccess(loginInfo, request);
// 单点登录登出句柄登录时注入session在这之前必须获取下授权信息
String ticket = loginInfo.getParam("ticket");
casOutHandler.recordSession(request, ticket);
//System.out.print("__sid: "+request.getSession().getId());
//System.out.println(" == "+UserUtils.getSession().getId());
// 更新登录IP、时间、会话ID等
User user = UserUtils.get(loginInfo.getId());
getUserService().updateUserLoginInfo(user);
// 记录用户登录日志
LogUtils.saveLog(user, ServletUtils.getRequest(), "系统登录", Log.TYPE_LOGIN_LOGOUT);
}
@Override

View File

@@ -1,48 +0,0 @@
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
*/
package com.jeesite.modules.config.web;
/**
* 页面缓存,如果需要,则加入如下依赖并取消下面注释
1、pom.xml:
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-web</artifactId>
<version>2.0.4</version>
</dependency>
2、application.yml:
# 页面缓存配置
ehcache:
pageCaching:
enabled: false
urlPatterns: "*.html"
* @author ThinkGem
* @version 2017年11月30日
*/
//@Configuration
public class PageCacheConfig {
// /**
// * PageCache Filter, cache .html suffix.
// */
// @Bean
// @Order(2000)
// @ConditionalOnProperty(name = "ehcache.pageCaching.enabled", havingValue = "true")
// @ConditionalOnMissingBean(name="pageCachingFilter")
// public FilterRegistrationBean<PageCachingFilter> pageCachingFilter(EhCacheManagerFactoryBean ehCacheManager) {
// FilterRegistrationBean<PageCachingFilter> bean = new FilterRegistrationBean<>();
// SimplePageCachingFilter pageCachingFilter = new SimplePageCachingFilter();
// pageCachingFilter.setCacheManager(ehCacheManager.getObject());
// bean.setFilter(pageCachingFilter);
// bean.addInitParameter("cacheName", "pageCachingFilter");
// bean.addUrlPatterns(StringUtils.split(Global.getProperty(
// "ehcache.pageCaching.urlPatterns"), ","));
// return bean;
// }
}

View File

@@ -83,7 +83,7 @@ public class MsgInnerService extends CrudService<MsgInnerDao, MsgInner> {
@Transactional
public void save(MsgInner msgInner) {
if (msgInner.getIsNewRecord()){
User user = msgInner.getCurrentUser();
User user = msgInner.currentUser();
msgInner.setSendUserCode(user.getUserCode());
msgInner.setSendUserName(user.getUserName());
// 没有设置状态,则默认新增后是草稿状态
@@ -206,7 +206,7 @@ public class MsgInnerService extends CrudService<MsgInnerDao, MsgInner> {
public void readMsgInnerRecord(MsgInner msgInner){
MsgInnerRecord msgInnerRecord = new MsgInnerRecord();
msgInnerRecord.setMsgInnerId(msgInner.getId());
msgInnerRecord.setReceiveUserCode(msgInner.getCurrentUser().getUserCode());
msgInnerRecord.setReceiveUserCode(msgInner.currentUser().getUserCode());
msgInnerRecord.setReadStatus(MsgInnerRecord.READ_STATUS_READ);
msgInnerRecord.setReadDate(new Date());
msgInnerRecordDao.updateReadStatus(msgInnerRecord);

View File

@@ -67,7 +67,7 @@ public class MsgInnerController extends BaseController {
public Page<MsgInner> listData(MsgInner msgInner, HttpServletRequest request, HttpServletResponse response) {
msgInner.setPage(new Page<>(request, response));
msgInner.setRecord(new MsgInnerRecord());
msgInner.getRecord().setReceiveUserCode(msgInner.getCurrentUser().getUserCode());
msgInner.getRecord().setReceiveUserCode(msgInner.currentUser().getUserCode());
Page<MsgInner> page = msgInnerService.findPage(msgInner);
return page;
}

View File

@@ -4,12 +4,6 @@
*/
package com.jeesite.modules.sys.db;
import org.quartz.CronTrigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import com.jeesite.common.callback.MethodCallback;
import com.jeesite.common.config.Global;
import com.jeesite.common.idgen.IdGen;
import com.jeesite.common.tests.BaseInitDataTests;
@@ -19,30 +13,12 @@ import com.jeesite.modules.job.entity.JobEntity;
import com.jeesite.modules.msg.task.impl.MsgLocalMergePushTask;
import com.jeesite.modules.msg.task.impl.MsgLocalPushTask;
import com.jeesite.modules.sys.dao.RoleMenuDao;
import com.jeesite.modules.sys.entity.Area;
import com.jeesite.modules.sys.entity.Company;
import com.jeesite.modules.sys.entity.Config;
import com.jeesite.modules.sys.entity.DictData;
import com.jeesite.modules.sys.entity.DictType;
import com.jeesite.modules.sys.entity.EmpUser;
import com.jeesite.modules.sys.entity.Menu;
import com.jeesite.modules.sys.entity.Module;
import com.jeesite.modules.sys.entity.Office;
import com.jeesite.modules.sys.entity.Post;
import com.jeesite.modules.sys.entity.Role;
import com.jeesite.modules.sys.entity.RoleMenu;
import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.service.CompanyService;
import com.jeesite.modules.sys.service.ConfigService;
import com.jeesite.modules.sys.service.DictDataService;
import com.jeesite.modules.sys.service.DictTypeService;
import com.jeesite.modules.sys.service.EmpUserService;
import com.jeesite.modules.sys.service.MenuService;
import com.jeesite.modules.sys.service.ModuleService;
import com.jeesite.modules.sys.service.OfficeService;
import com.jeesite.modules.sys.service.PostService;
import com.jeesite.modules.sys.service.RoleService;
import com.jeesite.modules.sys.service.UserService;
import com.jeesite.modules.sys.entity.*;
import com.jeesite.modules.sys.service.*;
import org.quartz.CronTrigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
/**
* 初始化核心表数据
@@ -112,19 +88,16 @@ public class InitCoreData extends BaseInitDataTests {
*/
public void initConfig() throws Exception{
// clearTable(Config.class);
initExcelData(Config.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
Config entity = (Config)params[1];
entity.setId(IdGen.nextId());
entity.setIsNewRecord(true);
configService.save(entity);
return null;
}
initExcelData(Config.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
Config entity = (Config)params[1];
entity.setId(IdGen.nextId());
entity.setIsNewRecord(true);
configService.save(entity);
return null;
}
return null;
});
}
@@ -135,18 +108,15 @@ public class InitCoreData extends BaseInitDataTests {
*/
public void initModule() throws Exception{
// clearTable(Module.class);
initExcelData(Module.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
Module entity = (Module)params[1];
entity.setIsNewRecord(true);
moduleService.save(entity);
return null;
}
initExcelData(Module.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
Module entity = (Module)params[1];
entity.setIsNewRecord(true);
moduleService.save(entity);
return null;
}
return null;
});
}
@@ -159,34 +129,28 @@ public class InitCoreData extends BaseInitDataTests {
*/
public void initDict() throws Exception{
// clearTable(DictType.class);
initExcelData(DictType.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
DictType entity = (DictType)params[1];
entity.setId(IdGen.nextId());
entity.setIsNewRecord(true);
dictTypeService.save(entity);
return null;
}
initExcelData(DictType.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
DictType entity = (DictType)params[1];
entity.setId(IdGen.nextId());
entity.setIsNewRecord(true);
dictTypeService.save(entity);
return null;
}
return null;
});
// clearTable(DictData.class);
initExcelData(DictData.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
DictData entity = (DictData)params[1];
entity.setIsNewRecord(true);
dictDataService.save(entity);
return null;
}
initExcelData(DictData.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
DictData entity = (DictData)params[1];
entity.setIsNewRecord(true);
dictDataService.save(entity);
return null;
}
return null;
});
}
@@ -199,18 +163,15 @@ public class InitCoreData extends BaseInitDataTests {
// clearTable(Role.class);
// clearTable(RoleMenu.class);
// clearTable(RoleDataScope.class);
initExcelData(Role.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
Role entity = (Role)params[1];
entity.setIsNewRecord(true);
roleService.save(entity);
return null;
}
initExcelData(Role.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
Role entity = (Role)params[1];
entity.setIsNewRecord(true);
roleService.save(entity);
return null;
}
return null;
});
}
@@ -224,22 +185,19 @@ public class InitCoreData extends BaseInitDataTests {
public void initMenu() throws Exception{
// clearTable(Menu.class);
// clearTable(RoleMenu.class);
initExcelData(Menu.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
Menu entity = (Menu)params[1];
entity.setIsNewRecord(true);
menuService.save(entity);
RoleMenu rm = new RoleMenu();
rm.setMenuCode(entity.getMenuCode());
rm.setRoleCode(Role.CORP_ADMIN_ROLE_CODE);
roleMenuDao.insert(rm);
return null;
}
initExcelData(Menu.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
Menu entity = (Menu)params[1];
entity.setIsNewRecord(true);
menuService.save(entity);
RoleMenu rm = new RoleMenu();
rm.setMenuCode(entity.getMenuCode());
rm.setRoleCode(Role.CORP_ADMIN_ROLE_CODE);
roleMenuDao.insert(rm);
return null;
}
return null;
});
}
@@ -252,18 +210,15 @@ public class InitCoreData extends BaseInitDataTests {
// clearTable(User.class);
// clearTable(UserRole.class);
// clearTable(UserDataScope.class);
initExcelData(User.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
User entity = (User)params[1];
entity.setIsNewRecord(true);
userService.save(entity);
return null;
}
initExcelData(User.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
User entity = (User)params[1];
entity.setIsNewRecord(true);
userService.save(entity);
return null;
}
return null;
});
}
@@ -274,18 +229,15 @@ public class InitCoreData extends BaseInitDataTests {
*/
public void initOffice() throws Exception{
// clearTable(Office.class);
initExcelData(Office.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
Office entity = (Office)params[1];
entity.setIsNewRecord(true);
officeService.save(entity);
return null;
}
initExcelData(Office.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
Office entity = (Office)params[1];
entity.setIsNewRecord(true);
officeService.save(entity);
return null;
}
return null;
});
}
@@ -297,18 +249,15 @@ public class InitCoreData extends BaseInitDataTests {
public void initCompany() throws Exception{
// clearTable(Company.class);
// clearTable(CompanyOffice.class);
initExcelData(Company.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
Company entity = (Company)params[1];
entity.setIsNewRecord(true);
companyService.save(entity);
return null;
}
initExcelData(Company.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
Company entity = (Company)params[1];
entity.setIsNewRecord(true);
companyService.save(entity);
return null;
}
return null;
});
}
@@ -319,18 +268,15 @@ public class InitCoreData extends BaseInitDataTests {
*/
public void initPost() throws Exception{
// clearTable(Post.class);
initExcelData(Post.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("save".equals(action)){
Post entity = (Post)params[1];
entity.setIsNewRecord(true);
postService.save(entity);
return null;
}
initExcelData(Post.class, params -> {
String action = (String)params[0];
if("save".equals(action)){
Post entity = (Post)params[1];
entity.setIsNewRecord(true);
postService.save(entity);
return null;
}
return null;
});
}
@@ -342,36 +288,33 @@ public class InitCoreData extends BaseInitDataTests {
public void initEmpUser() throws Exception{
// clearTable(Employee.class);
// clearTable(EmployeePost.class);
initExcelData(EmpUser.class, new MethodCallback() {
@Override
public Object execute(Object... params) {
String action = (String)params[0];
if("check".equals(action)){
User user = new User();
user.setLoginCode("user1");
return userService.getByLoginCode(user) == null;
}else if("set".equals(action)){
EmpUser entity = (EmpUser)params[1];
String header = (String)params[2];
String val = (String)params[3];
if ("userRoleString".equals(header)){
entity.setUserRoleString(val);
return true;
}else if ("employee.employeePosts".equals(header)){
entity.getEmployee().setEmployeePosts(val);
return true;
}
}else if("save".equals(action)){
EmpUser entity = (EmpUser)params[1];
entity.setIsNewRecord(true);
empUserService.save(entity);
// 设置当前为管理员,否则无法保存用户角色关系
entity.setCurrentUser(new User(User.SUPER_ADMIN_CODE));
userService.saveAuth(entity);
return null;
initExcelData(EmpUser.class, params -> {
String action = (String)params[0];
if("check".equals(action)){
User user = new User();
user.setLoginCode("user1");
return userService.getByLoginCode(user) == null;
}else if("set".equals(action)){
EmpUser entity = (EmpUser)params[1];
String header = (String)params[2];
String val = (String)params[3];
if ("userRoleString".equals(header)){
entity.setUserRoleString(val);
return true;
}else if ("employee.employeePosts".equals(header)){
entity.getEmployee().setEmployeePosts(val);
return true;
}
}else if("save".equals(action)){
EmpUser entity = (EmpUser)params[1];
entity.setIsNewRecord(true);
empUserService.save(entity);
// 设置当前为管理员,否则无法保存用户角色关系
entity.currentUser(new User(User.SUPER_ADMIN_CODE));
userService.saveAuth(entity);
return null;
}
return null;
});
}

View File

@@ -4,8 +4,6 @@
*/
package com.jeesite.modules.sys.entity;
import javax.validation.Valid;
import com.jeesite.common.entity.BaseEntity;
import com.jeesite.common.entity.DataEntity;
import com.jeesite.common.entity.TreeEntity;
@@ -19,6 +17,9 @@ import com.jeesite.common.utils.excel.annotation.ExcelField.Align;
import com.jeesite.common.utils.excel.annotation.ExcelFields;
import com.jeesite.common.utils.excel.fieldtype.CompanyType;
import com.jeesite.common.utils.excel.fieldtype.OfficeType;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.Valid;
/**
* 员工用户管理Entity
@@ -123,7 +124,8 @@ public class EmpUser extends User {
public void setEmployee(Employee employee){
super.setRefObj(employee);
}
@ApiModelProperty("根据各种编码查询")
public String[] getCodes() {
return codes;
}

View File

@@ -4,12 +4,6 @@
*/
package com.jeesite.modules.sys.entity;
import java.util.List;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.entity.BaseEntity;
import com.jeesite.common.entity.DataEntity;
@@ -19,6 +13,11 @@ import com.jeesite.common.mybatis.annotation.JoinTable;
import com.jeesite.common.mybatis.annotation.JoinTable.Type;
import com.jeesite.common.mybatis.annotation.Table;
import com.jeesite.common.mybatis.mapper.query.QueryType;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.List;
/**
* 员工管理Entity
@@ -130,6 +129,7 @@ public class Employee extends DataEntity<Employee> {
this.company = company;
}
@ApiModelProperty("根据岗位编码查询")
public String getPostCode() {
return postCode;
}
@@ -146,6 +146,7 @@ public class Employee extends DataEntity<Employee> {
this.employeePostList = employeePostList;
}
@ApiModelProperty("员工岗位关系")
public String getEmployeePosts() {
List<String> list = ListUtils.extractToList(employeePostList, "postCode");
return StringUtils.join(list, ",");

View File

@@ -14,6 +14,7 @@ import com.jeesite.common.lang.TimeUtils;
import com.jeesite.common.mybatis.annotation.Column;
import com.jeesite.common.mybatis.annotation.Table;
import com.jeesite.common.mybatis.mapper.query.QueryType;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@@ -228,7 +229,8 @@ public class Log extends DataEntity<Log> {
public void setExecuteTime(Long executeTime) {
this.executeTime = executeTime;
}
@ApiModelProperty("格式化后的执行时间")
public String getExecuteTimeFormat(){
if (executeTime == null) {
executeTime = 0L;

View File

@@ -4,10 +4,6 @@
*/
package com.jeesite.modules.sys.entity;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.jeesite.common.entity.BaseEntity;
import com.jeesite.common.entity.DataEntity;
@@ -20,6 +16,11 @@ import com.jeesite.common.utils.excel.annotation.ExcelField;
import com.jeesite.common.utils.excel.annotation.ExcelField.Align;
import com.jeesite.common.utils.excel.annotation.ExcelFields;
import com.jeesite.modules.sys.utils.EmpUtils;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
/**
* 组织机构Entity
@@ -137,7 +138,8 @@ public class Office extends TreeEntity<Office> {
public void setOfficeType(String officeType) {
this.officeType = officeType;
}
@ApiModelProperty("包含某机构类型")
public String[] getOfficeType_in(){
return sqlMap.getWhere().getValue("office_type", QueryType.IN);
}
@@ -198,7 +200,8 @@ public class Office extends TreeEntity<Office> {
public void setExtend(Extend extend) {
this.extend = extend;
}
@ApiModelProperty("公司编码")
public String getCompanyCode() {
return companyCode;
}

View File

@@ -4,15 +4,16 @@
*/
package com.jeesite.modules.sys.entity;
import javax.validation.constraints.Size;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import com.jeesite.common.entity.BaseEntity;
import com.jeesite.common.entity.DataEntity;
import com.jeesite.common.mybatis.annotation.Column;
import com.jeesite.common.mybatis.annotation.Table;
import com.jeesite.common.mybatis.mapper.query.QueryType;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
@Table(name="${_prefix}sys_post", alias="a", label="岗位信息", columns={
@Column(includeEntity=BaseEntity.class),
@@ -70,13 +71,14 @@ public class Post extends DataEntity<Post> {
public void setPostName(String postName) {
this.postName = postName;
}
@ApiModelProperty("模糊查询岗位名称")
public String getPostName_like() {
return getSqlMap().getWhere().getValue("post_name", QueryType.LIKE);
return sqlMap().getWhere().getValue("post_name", QueryType.LIKE);
}
public void setPostName_like(String roleName) {
getSqlMap().getWhere().and("post_name", QueryType.LIKE, roleName);
sqlMap().getWhere().and("post_name", QueryType.LIKE, roleName);
}
@Size(min=0, max=100, message="岗位分类长度不能超过 100 个字符")
@@ -96,6 +98,7 @@ public class Post extends DataEntity<Post> {
this.postSort = postSort;
}
@ApiModelProperty("根据员工编码查询")
public String getEmpCode() {
return empCode;
}

View File

@@ -26,7 +26,7 @@ public interface EmpUserService extends CrudServiceApi<EmpUser> {
/**
* 添加数据权限过滤条件
* @param entity 控制对象
* @param empUser 控制对象
* @param ctrlPermi 控制权限类型拥有的数据权限DataScope.CTRL_PERMI_HAVE、可管理的数据权限DataScope.CTRL_PERMI_HAVE
*/
@Override

View File

@@ -46,7 +46,7 @@ public class CompanyServiceSupport extends TreeService<CompanyDao, Company>
*/
@Override
public void addDataScopeFilter(Company company, String ctrlPermi) {
company.getSqlMap().getDataScope().addFilter("dsf", "Company", "a.company_code",
company.sqlMap().getDataScope().addFilter("dsf", "Company", "a.company_code",
null, ctrlPermi, "office_user");
}

View File

@@ -72,10 +72,10 @@ public class EmpUserServiceSupport extends CrudService<EmpUserDao, EmpUser>
*/
@Override
public void addDataScopeFilter(EmpUser empUser, String ctrlPermi) {
empUser.getSqlMap().getDataScope().addFilter("dsfOffice",
empUser.sqlMap().getDataScope().addFilter("dsfOffice",
"Office", "e.office_code", "a.create_by", ctrlPermi, "office_user");
if (StringUtils.isNotBlank(EmpUtils.getCompany().getCompanyCode())){
empUser.getSqlMap().getDataScope().addFilter("dsfCompany",
empUser.sqlMap().getDataScope().addFilter("dsfCompany",
"Company", "e.company_code", "a.create_by", ctrlPermi, "office_user");
}
}

View File

@@ -34,8 +34,8 @@ public class LogServiceSupport extends CrudService<LogDao, Log>
// log.setCreateDate_lte(DateUtils.addDays(DateUtils.addMonths(log.getCreateDate_gte(), 1), -1));
// }
// 普通用户看自己的,管理员看全部的。
if (!log.getCurrentUser().isAdmin()){
log.setCreateBy(log.getCurrentUser().getUserCode());
if (!log.currentUser().isAdmin()){
log.setCreateBy(log.currentUser().getUserCode());
}
return super.findPage(log);
}

View File

@@ -48,7 +48,7 @@ public class OfficeServiceSupport extends TreeService<OfficeDao, Office>
*/
@Override
public void addDataScopeFilter(Office office, String ctrlPermi) {
office.getSqlMap().getDataScope().addFilter("dsf", "Office", "a.office_code",
office.sqlMap().getDataScope().addFilter("dsf", "Office", "a.office_code",
null, ctrlPermi , "office_user");
}

View File

@@ -103,7 +103,7 @@ public class LogUtils {
log.setCorpName(user.getCorpName());
}
log.setExecuteTime(executeTime);
log.setCurrentUser(user);
log.currentUser(user);
log.preInsert();
// 获取异常对象

View File

@@ -4,24 +4,6 @@
*/
package com.jeesite.modules.sys.web;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.collect.MapUtils;
import com.jeesite.common.config.Global;
@@ -34,6 +16,22 @@ import com.jeesite.modules.sys.entity.Company;
import com.jeesite.modules.sys.service.AreaService;
import com.jeesite.modules.sys.utils.AreaUtils;
import com.jeesite.modules.sys.utils.UserUtils;
import io.swagger.annotations.Api;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;
/**
* 区域Controller
@@ -108,7 +106,7 @@ public class AreaController extends BaseController {
|| StringUtils.isNotBlank(area.getAreaName())){
area.setParentCode(null);
}
area.setPage(new Page<>(request, response, !area.getIsRoot() ? Page.PAGE_SIZE_NOT_PAGING : null));
area.setPage(new Page<>(request, response, area.getIsRoot()));
Page<Area> page = areaService.findPage(area);
return page;
}

View File

@@ -78,7 +78,9 @@ public class LoginController extends BaseController{
// 获取登录数据
model.addAllAttributes(FormFilter.getLoginData(request, response));
model.addAttribute("useCorpModel", Global.isUseCorpModel()
&& Global.getConfigToBoolean("user.loginCodeCorpUnique", "false"));
// 如果是Ajax请求返回Json字符串。
if (ServletUtils.isAjaxRequest((HttpServletRequest)request)){
model.addAttribute("message", text("sys.login.notLongIn"));
@@ -194,6 +196,7 @@ public class LoginController extends BaseController{
model.addAttribute("useCorpModel", Global.isUseCorpModel());
model.addAttribute("currentCorpCode", CorpUtils.getCurrentCorpCode());
model.addAttribute("currentCorpName", CorpUtils.getCurrentCorpName());
model.addAttribute("msgEnabled", Global.getPropertyToBoolean("msg.enabled", "false"));
model.addAttribute("sysCode", session.getAttribute("sysCode"));
// 是否是登录操作

View File

@@ -184,7 +184,7 @@ public class OfficeController extends BaseController {
if (!(isAll != null && isAll) || Global.isStrictMode()){
officeService.addDataScopeFilter(office, ctrlPermi);
}
office.getSqlMap().getOrder().setOrderBy("a.tree_sorts");
office.sqlMap().getOrder().setOrderBy("a.tree_sorts");
List<Office> list = officeService.findList(office);
String fileName = "机构数据" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
try(ExcelExport ee = new ExcelExport("机构数据", Office.class)){

View File

@@ -65,8 +65,8 @@ public class CorpAdminController extends BaseController {
user.setCorpCode(null);
user.setCorpName(null);
model.addAttribute("user", user);
model.addAttribute("currentCorpCode", user.getCurrentUser().getCorpCode_());
model.addAttribute("currentCorpName", user.getCurrentUser().getCorpName_());
model.addAttribute("currentCorpCode", user.currentUser().getCorpCode_());
model.addAttribute("currentCorpName", user.currentUser().getCorpName_());
model.addAttribute("useCorpModel", Global.getConfigToBoolean("user.useCorpModel", "false"));
return "modules/sys/user/corpAdminList";
}
@@ -77,7 +77,7 @@ public class CorpAdminController extends BaseController {
public Page<User> listData(User user, HttpServletRequest request, HttpServletResponse response) {
user.setMgrType(User.MGR_TYPE_CORP_ADMIN); // 租户管理员
// 禁用自动添加租户代码条件,添加自定义租户查询条件
user.getSqlMap().getWhere().disableAutoAddCorpCodeWhere()
user.sqlMap().getWhere().disableAutoAddCorpCodeWhere()
.and("corp_code", QueryType.EQ, user.getCorpCode_())
.and("corp_name", QueryType.LIKE, user.getCorpName_());
user.setPage(new Page<>(request, response));
@@ -113,7 +113,7 @@ public class CorpAdminController extends BaseController {
@PostMapping(value = "save")
@ResponseBody
public String save(@Validated User user, String op, HttpServletRequest request) {
if (!user.getCurrentUser().isSuperAdmin()){
if (!user.currentUser().isSuperAdmin()){
return renderResult(Global.FALSE, text("越权操作,只有超级管理员才能修改此数据!"));
}
if (User.isSuperAdmin(user.getUserCode())) {
@@ -175,7 +175,7 @@ public class CorpAdminController extends BaseController {
if (User.isSuperAdmin(user.getUserCode())) {
return renderResult(Global.FALSE, text("非法操作,不能够操作此用户!"));
}
if (user.getCurrentUser().getUserCode().equals(user.getUserCode())) {
if (user.currentUser().getUserCode().equals(user.getUserCode())) {
return renderResult(Global.FALSE, text("停用用户失败,不允许停用当前用户"));
}
user.setStatus(User.STATUS_DISABLE);
@@ -228,7 +228,7 @@ public class CorpAdminController extends BaseController {
if (User.isSuperAdmin(user.getUserCode())) {
return renderResult(Global.FALSE, text("非法操作,不能够操作此用户!"));
}
if (user.getCurrentUser().getUserCode().equals(user.getUserCode())) {
if (user.currentUser().getUserCode().equals(user.getUserCode())) {
return renderResult(Global.FALSE, text("删除用户失败,不允许删除当前用户"));
}
if (User.USER_TYPE_NONE.equals(user.getUserType())){

View File

@@ -286,7 +286,7 @@ public class EmpUserController extends BaseController {
if (!EmpUser.USER_TYPE_EMPLOYEE.equals(empUser.getUserType())){
return renderResult(Global.FALSE, "非法操作,不能够操作此用户!");
}
if (empUser.getCurrentUser().getUserCode().equals(empUser.getUserCode())) {
if (empUser.currentUser().getUserCode().equals(empUser.getUserCode())) {
return renderResult(Global.FALSE, text("停用用户失败,不允许停用当前用户"));
}
empUser.setStatus(User.STATUS_DISABLE);
@@ -350,7 +350,7 @@ public class EmpUserController extends BaseController {
if (!EmpUser.USER_TYPE_EMPLOYEE.equals(empUser.getUserType())){
return renderResult(Global.FALSE, "非法操作,不能够操作此用户!");
}
if (empUser.getCurrentUser().getUserCode().equals(empUser.getUserCode())) {
if (empUser.currentUser().getUserCode().equals(empUser.getUserCode())) {
return renderResult(Global.FALSE, text("删除用户失败,不允许删除当前用户"));
}
empUserService.delete(empUser);

View File

@@ -7,7 +7,6 @@ package com.jeesite.modules.sys.web.user;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -56,7 +55,7 @@ public class UserController extends BaseController {
// if (User.USER_TYPE_NONE.equals(user.getUserType())){
// return new Page<User>(request, response);
// }
if (Global.isStrictMode() && !user.getCurrentUser().isAdmin()){
if (Global.isStrictMode() && !user.currentUser().isAdmin()){
return new Page<User>(request, response);
}
user.setPage(new Page<>(request, response));

View File

@@ -104,6 +104,7 @@ FN.hasRole = com.jeesite.common.beetl.ext.fn.HasRole
FN.cookie = com.jeesite.common.beetl.ext.fn.Cookie
FN.lang = com.jeesite.common.beetl.ext.fn.Lang
FN.text = com.jeesite.common.beetl.ext.fn.Text
FN.user = com.jeesite.common.beetl.ext.fn.User
##内置的功能包
FNP.strutil = org.beetl.ext.fn.StringUtil

View File

@@ -461,7 +461,7 @@ session:
# 会话超时时间单位毫秒10m=600000, 20m=1200000ms, 30m=1800000ms, 60m=3600000ms, 12h=43200000ms, 1day=86400000ms
# 注意如果超时超过30m你还需要同步修改当前配置文件的属性j2cache.caffeine.region.sessionCache 超时时间,大于这个值。
# 游客会话超时时间:只访问了系统,但未登录系统的用户为游客,游客默认超时时间为10分钟,如:未登录系统时的图片验证码有效时间。
# 游客会话超时时间:只访问了系统,但未登录系统的用户为游客,游客默认超时时间为3分钟,如:未登录系统时的图片验证码有效时间。
sessionTimeout: 180000
# 登录系统后的用户超时时间(不明确 param_deviceType 参数的,默认设备为 pc 登录)
@@ -533,11 +533,17 @@ j2cache:
# MyBatis 相关
mybatis:
# @MyBatisDao、Aliases 扫描基础包,如果多个,用“,”分隔
scanBasePackage: com.jeesite.modules
# @MyBatisDao 扫描基础包,如果多个,用“,”分隔
#scanBasePackage: com.jeesite.modules.**.dao
# TypeAliases 扫描基础包,如果多个,用“,”分隔 v5.3.1
#scanTypeAliasesBasePackage: com.jeesite.modules.**.entity
# TypeHandlers 扫描基础包,如果多个,用“,”分隔
scanTypeHandlersPackage: ~
# 自定义 Mapper 文件扫描路径,如果多个,用“,”分隔 v4.2.3
scanMapperLocations: classpath*:/mappings/**/*.xml
# 是否开启 JDBC 管理事务,默认 Spring 管理事务 v4.2.3
jdbcTransaction: false
@@ -590,6 +596,9 @@ web:
${adminPath}/index,
${adminPath}/login,
${adminPath}/desktop,
${adminPath}/authInfo,
${adminPath}/menuRoute,
${adminPath}/switchSkin/*,
${adminPath}/index/menuTree,
${adminPath}/sys/online/count,
${adminPath}/**/server/rtInfo,

View File

@@ -348,7 +348,14 @@ CREATE TABLE ${_prefix}sys_job
job_group varchar(64) NOT NULL,
description vargraphic(100) NOT NULL,
invoke_target vargraphic(1000) NOT NULL,
job_type vargraphic(10) DEFAULT 'cron' NOT NULL,
job_priority decimal(10),
start_time timestamp,
start_delay decimal(19),
repeat_interval decimal(19),
repeat_count decimal(10),
cron_expression varchar(255) NOT NULL,
rule_expression varchar(255),
misfire_instruction decimal(1) NOT NULL,
concurrent char(1) NOT NULL,
instance_name varchar(64) DEFAULT 'JeeSiteScheduler' NOT NULL,

View File

@@ -348,7 +348,14 @@ CREATE TABLE ${_prefix}sys_job
job_group varchar(64) NOT NULL,
description varchar(100) NOT NULL,
invoke_target varchar(1000) NOT NULL,
job_type varchar(10) DEFAULT 'cron' NOT NULL,
job_priority decimal(10),
start_time datetime,
start_delay decimal(19),
repeat_interval decimal(19),
repeat_count decimal(10),
cron_expression varchar(255) NOT NULL,
rule_expression varchar(255),
misfire_instruction decimal(1) NOT NULL,
concurrent char(1) NOT NULL,
instance_name varchar(64) DEFAULT 'JeeSiteScheduler' NOT NULL,

View File

@@ -348,7 +348,14 @@ CREATE TABLE [${_prefix}sys_job]
[job_group] varchar(64) NOT NULL,
[description] nvarchar(100) NOT NULL,
[invoke_target] nvarchar(1000) NOT NULL,
[job_type] nvarchar(10) DEFAULT 'cron' NOT NULL,
[job_priority] decimal(10),
[start_time] datetime,
[start_delay] decimal(19),
[repeat_interval] decimal(19),
[repeat_count] decimal(10),
[cron_expression] varchar(255) NOT NULL,
[rule_expression] varchar(255),
[misfire_instruction] decimal(1) NOT NULL,
[concurrent] char(1) NOT NULL,
[instance_name] varchar(64) DEFAULT 'JeeSiteScheduler' NOT NULL,

View File

@@ -349,7 +349,14 @@ CREATE TABLE ${_prefix}sys_job
job_group varchar(64) NOT NULL COMMENT '任务组名',
description varchar(100) NOT NULL COMMENT '任务描述',
invoke_target varchar(1000) NOT NULL COMMENT '调用目标字符串',
job_type varchar(10) DEFAULT 'cron' NOT NULL COMMENT '任务触发类型',
job_priority decimal(10) COMMENT '触发器优先级',
start_time datetime COMMENT '触发器启动时间',
start_delay decimal(19) COMMENT '触发器延迟启动时间',
repeat_interval decimal(19) COMMENT '循环间隔时间(毫秒)',
repeat_count decimal(10) COMMENT '循环次数( -1 无期限)',
cron_expression varchar(255) NOT NULL COMMENT 'Cron执行表达式',
rule_expression varchar(255) COMMENT '自定义规则表达式',
misfire_instruction decimal(1) NOT NULL COMMENT '计划执行错误策略',
concurrent char(1) NOT NULL COMMENT '是否并发执行',
instance_name varchar(64) DEFAULT 'JeeSiteScheduler' NOT NULL COMMENT '集群的实例名字',

View File

@@ -348,7 +348,14 @@ CREATE TABLE ${_prefix}sys_job
job_group varchar2(64) NOT NULL,
description nvarchar2(100) NOT NULL,
invoke_target nvarchar2(1000) NOT NULL,
job_type nvarchar2(10) DEFAULT 'cron' NOT NULL,
job_priority number(10),
start_time timestamp,
start_delay number(19),
repeat_interval number(19),
repeat_count number(10),
cron_expression varchar2(255) NOT NULL,
rule_expression varchar2(255),
misfire_instruction number(1) NOT NULL,
concurrent char(1) NOT NULL,
instance_name varchar2(64) DEFAULT 'JeeSiteScheduler' NOT NULL,
@@ -1233,7 +1240,14 @@ COMMENT ON COLUMN ${_prefix}sys_job.job_name IS '任务名称';
COMMENT ON COLUMN ${_prefix}sys_job.job_group IS '任务组名';
COMMENT ON COLUMN ${_prefix}sys_job.description IS '任务描述';
COMMENT ON COLUMN ${_prefix}sys_job.invoke_target IS '调用目标字符串';
COMMENT ON COLUMN ${_prefix}sys_job.job_type IS '任务触发类型';
COMMENT ON COLUMN ${_prefix}sys_job.job_priority IS '触发器优先级';
COMMENT ON COLUMN ${_prefix}sys_job.start_time IS '触发器启动时间';
COMMENT ON COLUMN ${_prefix}sys_job.start_delay IS '触发器延迟启动时间';
COMMENT ON COLUMN ${_prefix}sys_job.repeat_interval IS '循环间隔时间(毫秒)';
COMMENT ON COLUMN ${_prefix}sys_job.repeat_count IS '循环次数( -1 无期限)';
COMMENT ON COLUMN ${_prefix}sys_job.cron_expression IS 'Cron执行表达式';
COMMENT ON COLUMN ${_prefix}sys_job.rule_expression IS '自定义规则表达式';
COMMENT ON COLUMN ${_prefix}sys_job.misfire_instruction IS '计划执行错误策略';
COMMENT ON COLUMN ${_prefix}sys_job.concurrent IS '是否并发执行';
COMMENT ON COLUMN ${_prefix}sys_job.instance_name IS '集群的实例名字';

View File

@@ -348,7 +348,14 @@ CREATE TABLE ${_prefix}sys_job
job_group varchar(64) NOT NULL,
description varchar(100) NOT NULL,
invoke_target varchar(1000) NOT NULL,
job_type varchar(10) DEFAULT 'cron' NOT NULL,
job_priority decimal(10),
start_time timestamp,
start_delay decimal(19),
repeat_interval decimal(19),
repeat_count decimal(10),
cron_expression varchar(255) NOT NULL,
rule_expression varchar(255),
misfire_instruction decimal(1) NOT NULL,
concurrent char(1) NOT NULL,
instance_name varchar(64) DEFAULT 'JeeSiteScheduler' NOT NULL,
@@ -1233,7 +1240,14 @@ COMMENT ON COLUMN ${_prefix}sys_job.job_name IS '任务名称';
COMMENT ON COLUMN ${_prefix}sys_job.job_group IS '任务组名';
COMMENT ON COLUMN ${_prefix}sys_job.description IS '任务描述';
COMMENT ON COLUMN ${_prefix}sys_job.invoke_target IS '调用目标字符串';
COMMENT ON COLUMN ${_prefix}sys_job.job_type IS '任务触发类型';
COMMENT ON COLUMN ${_prefix}sys_job.job_priority IS '触发器优先级';
COMMENT ON COLUMN ${_prefix}sys_job.start_time IS '触发器启动时间';
COMMENT ON COLUMN ${_prefix}sys_job.start_delay IS '触发器延迟启动时间';
COMMENT ON COLUMN ${_prefix}sys_job.repeat_interval IS '循环间隔时间(毫秒)';
COMMENT ON COLUMN ${_prefix}sys_job.repeat_count IS '循环次数( -1 无期限)';
COMMENT ON COLUMN ${_prefix}sys_job.cron_expression IS 'Cron执行表达式';
COMMENT ON COLUMN ${_prefix}sys_job.rule_expression IS '自定义规则表达式';
COMMENT ON COLUMN ${_prefix}sys_job.misfire_instruction IS '计划执行错误策略';
COMMENT ON COLUMN ${_prefix}sys_job.concurrent IS '是否并发执行';
COMMENT ON COLUMN ${_prefix}sys_job.instance_name IS '集群的实例名字';

View File

@@ -1,7 +1,7 @@
# =========== 登录登出相关 ===========
sys.login.notLongIn=No login or login timeout.Please login again, thank you!
sys.login.notLongIn=Your login information has expired. Please log in again.
sys.login.success=Login successful!
sys.login.getInfo=Get info successful!
sys.login.failure=Account or password error, please try again.

View File

@@ -1,7 +1,7 @@
# =========== 登录登出相关 ===========
sys.login.notLongIn=ログインしていないか、またはログインがタイムアウトしました。もう一度ログインしてください
sys.login.notLongIn=ログイン情報が期限切れになっています。再度ログインしてください
sys.login.success=ログイン成功!
sys.login.getInfo=情報取得成功!
sys.login.failure=ログインID或いはパスワードに誤りがあります。もう一度にゅうしてください。

View File

@@ -1,7 +1,7 @@
# =========== 登录登出相关 ===========
sys.login.notLongIn=未登录或登录超时。请重新登录,谢谢!
sys.login.notLongIn=您的登录信息已过期,请重新登录
sys.login.success=登录成功!
sys.login.getInfo=获取信息成功!
sys.login.failure=账号或密码错误,请重试。

View File

@@ -258,6 +258,7 @@
办公电话=Phone
权重(排序)=Weight(Sort)
权重越大排名越靠前,请填写数字。=Weight big, ranking the front, fill Numbers.
性别=Gender
员工=Employee
员工工号=Work No

View File

@@ -195,6 +195,7 @@
办公电话=会社電話
权重(排序)=レベル(ソート)
权重越大排名越靠前,请填写数字。=重要度が大きいほど前に表示します。数字を入力してください.
性别=性别
员工=社員
员工工号=社員コード

View File

@@ -233,6 +233,7 @@
<template>module_cloud/web/src/main/webapp/WEB-INF/startup.bat.xml</template>
<template>module_cloud/web/src/main/webapp/WEB-INF/startup.sh.xml</template>
<template>module_cloud/web/pom.xml</template>
<template>module_cloud/pom.xml</template>
</category>
</moduleTplCategory>
</config>

View File

@@ -82,7 +82,7 @@ public class ${ClassName}Service extends ${table.isTreeEntity?'Tree':'Crud'}Serv
/**
* 查询分页数据
* @param ${className} 查询条件
* @param ${className}.page 分页对象
* @param ${className} page 分页对象
* @return
*/
@Override
@@ -104,7 +104,7 @@ public class ${ClassName}Service extends ${table.isTreeEntity?'Tree':'Crud'}Serv
/**
* 查询子表分页数据
* @param ${@StringUtils.uncap(child.className)}
* @param ${@StringUtils.uncap(child.className)}.page 分页对象
* @param ${@StringUtils.uncap(child.className)} page 分页对象
* @return
*/
public Page<${@StringUtils.cap(child.className)}> findSubPage(${@StringUtils.cap(child.className)} ${@StringUtils.uncap(child.className)}) {

View File

@@ -545,7 +545,7 @@ for (c in table.columnList){
});
}
if (!${@StringUtils.uncap(child.className)}ListValid) {
throw new Error('${@StringUtils.uncap(child.className)}List valid.');
throw { errorFields: [{ name: ['${@StringUtils.uncap(child.className)}List'] }] };
}
return ${@StringUtils.uncap(child.className)}List;
}

View File

@@ -88,7 +88,7 @@ public class ${ClassName}Service extends ${table.isTreeEntity?'Tree':'Crud'}Serv
/**
* 查询分页数据
* @param ${className} 查询条件
* @param ${className}.page 分页对象
* @param ${className} page 分页对象
* @return
*/
@Override
@@ -110,7 +110,7 @@ public class ${ClassName}Service extends ${table.isTreeEntity?'Tree':'Crud'}Serv
/**
* 查询子表分页数据
* @param ${@StringUtils.uncap(child.className)}
* @param ${@StringUtils.uncap(child.className)}.page 分页对象
* @param ${@StringUtils.uncap(child.className)} page 分页对象
* @return
*/
public Page<${@StringUtils.cap(child.className)}> findSubPage(${@StringUtils.cap(child.className)} ${@StringUtils.uncap(child.className)}) {

View File

@@ -68,7 +68,7 @@
<% } %>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-sm">\${text('查询')}</button>
<button type="reset" class="btn btn-default btn-sm">\${text('重置')}</button>
<button type="reset" class="btn btn-default btn-sm isQuick">\${text('重置')}</button>
</div>
</${'#'}form:form>
<% /* 查询表单 end // 此行是为了去除空行 */ %>

View File

@@ -89,11 +89,7 @@ $('#btnDraft').click(function(){
});
// 流程按钮操作事件
BpmButton = window.BpmButton || {};
BpmButton.init = function(task){
if (task && task.priority){
$('#bpm_priority').val(task.priority).trigger('change'); // 设置下一个任务的优先级
}
}
BpmButton.init = function(task){}
BpmButton.complete = function($this, task){
$('#status').val(Global.STATUS_AUDIT);
};

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2013-Now http://jeesite.com All rights reserved.
No deletion without permission, or be held responsible to law. -->
<template>
<name>pom</name>
<filePath>${baseDir}/${moduleCode}</filePath>
<fileName>pom.xml</fileName>
<charset></charset>
<content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-cloud-module-${moduleCode}</artifactId>
<version>${jeesiteVersion}-SNAPSHOT</version>
<packaging>pom</packaging>
<name>JeeSite Cloud Module ${moduleName}</name>
<url>http://jeesite.com</url>
<inceptionYear>2013-Now</inceptionYear>
<modules>
<module>${moduleCode}</module>
<module>${moduleCode}-client</module>
</modules>
<developers>
<developer>
<id>thinkgem</id>
<name>WangZhen</name>
<email>thinkgem at 163.com</email>
<roles><role>Project lead</role></roles>
<timezone>+8</timezone>
</developer>
</developers>
<organization>
<name>JeeSite</name>
<url>http://jeesite.com</url>
</organization>
</project>
]]>
</content>
</template>

View File

@@ -18,10 +18,10 @@
<relativePath>../../../parent/web/pom.xml</relativePath>
</parent>
<artifactId>jeesite-cloud-module-${moduleCode}</artifactId>
<artifactId>jeesite-cloud-module-${moduleCode}-web</artifactId>
<packaging>war</packaging>
<name>JeeSite Cloud Module ${moduleName}</name>
<name>JeeSite Cloud Module ${moduleName} Web</name>
<url>http://jeesite.com</url>
<inceptionYear>2013-Now</inceptionYear>

View File

@@ -31,7 +31,8 @@ eureka:
# 客户端设置
client:
# 注册中心地址(集群时指定另外一个注册中心地址)
serviceUrl.defaultZone: http://127.0.0.1:8970/eureka/
serviceUrl:
defaultZone: http://127.0.0.1:8970/eureka/
#======================================#
#========== Spring settings ===========#
@@ -74,6 +75,10 @@ spring:
- data-id: application.yml
group: jeesite-cloud-50
# 服务发现与注册优选IP前缀
#inetutils:
# preferred-networks: 192.168.56.
# 打印横幅
main:
bannerMode: "off"

View File

@@ -3,7 +3,7 @@
No deletion without permission, or be held responsible to law. -->
<template>
<name>run-web</name>
<filePath>${module.moduleCode}/${module.moduleCode}/src/main/webapp/WEB-INF</filePath>
<filePath>${baseDir}/${moduleCode}/${moduleCode}/src/main/webapp/WEB-INF</filePath>
<fileName>startup.bat</fileName>
<content><![CDATA[chcp 65001
@echo off

View File

@@ -3,7 +3,7 @@
No deletion without permission, or be held responsible to law. -->
<template>
<name>run-web</name>
<filePath>${module.moduleCode}/${module.moduleCode}/src/main/webapp/WEB-INF</filePath>
<filePath>${baseDir}/${moduleCode}/${moduleCode}/src/main/webapp/WEB-INF</filePath>
<fileName>startup.sh</fileName>
<content><![CDATA[#!/bin/sh
# /**

View File

@@ -61,7 +61,7 @@ public class ${ClassName}Service extends ${table.isTreeEntity?'Tree':'Query'}Ser
/**
* 查询分页数据
* @param ${className} 查询条件
* @param ${className}.page 分页对象
* @param ${className} page 分页对象
* @return
*/
@Override
@@ -83,7 +83,7 @@ public class ${ClassName}Service extends ${table.isTreeEntity?'Tree':'Query'}Ser
/**
* 查询子表分页数据
* @param ${@StringUtils.uncap(child.className)}
* @param ${@StringUtils.uncap(child.className)}.page 分页对象
* @param ${@StringUtils.uncap(child.className)} page 分页对象
* @return
*/
public Page<${@StringUtils.cap(child.className)}> findSubPage(${@StringUtils.cap(child.className)} ${@StringUtils.uncap(child.className)}) {

Some files were not shown because too many files have changed in this diff Show More