Compare commits

...

64 Commits

Author SHA1 Message Date
thinkgem
fe030b75c6 删除失信企业湖南乐活科技lehuo520.cn乐云短信代码 2018-09-15 20:49:55 +08:00
thinkgem
8563888fd5 v4.0.7 2018-09-15 17:46:18 +08:00
thinkgem
39a5f6164d 添加 ueditor后台源码,方便扩展上传文件存储。 2018-09-09 22:17:49 +08:00
33112
8b3a20b68b * 官方论坛:<http://jeesite.net> 2018-09-07 15:44:30 +08:00
33112
f6f824054a 取消测试声明 2018-09-07 11:56:12 +08:00
33112
9e163b1034 测试演示课程 2018-09-07 11:52:08 +08:00
thinkgem
1f92830aec update readme.md 2018-09-04 22:21:16 +08:00
ThinkGem
85c50bbd40 更新 README.md 2018-09-04 20:56:43 +08:00
thinkgem
6c7decc4a3 修正多个endBracket的情况下不输出问题,#IMJU8 2018-09-03 22:57:04 +08:00
thinkgem
bfabf1a85e 增加文件上传组件开关file.enabled;增加文件上传扩展服务类FileUploadServiceExtend接口,支持将文件保存到第三方文件服务器(如飞牛、OSS等) 2018-09-02 19:07:50 +08:00
thinkgem
5706c8bfc9 NumberUtils新增formatNumber方法 2018-08-29 23:34:28 +08:00
thinkgem
27434ee26e 分页器优化,Service基类新增重载findPage(T entity) 2018-08-28 23:08:58 +08:00
thinkgem
7bcf1095ff 消息推送单元测试完善;消息推送的PC消息按钮修正;模板消息优化修正; 2018-08-28 22:12:09 +08:00
thinkgem
01abf24665 job.scheduler.instanceName 2018-08-27 22:02:19 +08:00
thinkgem
8f4724fab2 i18n语言设置开关优化 2018-08-27 22:01:26 +08:00
thinkgem
b908885634 job数据源优化,druid升级到1.1.10版本 2018-08-26 23:10:55 +08:00
thinkgem
91d0e233f9 ListUtils.listOrderBy支持默认升序排序 2018-08-25 19:12:24 +08:00
thinkgem
cfdc99f190 客户端接口API信息输出优化 2018-08-25 19:11:42 +08:00
thinkgem
c553d966d6 新增调度日志开关,可关闭或只保存错误级别的日志,详见:jeesite.yml 2018-08-25 16:55:14 +08:00
thinkgem
0267908ece 增加Spring环境切换提示,不可设置为test,因为它是单元测试环境专属的名称。 2018-08-25 16:53:20 +08:00
thinkgem
7fdcecb912 支持@JsonView注解,自定义过滤Json视图输出字段。这在移动端API节省流量,隐私信息,或特殊场景下非常有用。 2018-08-23 22:11:55 +08:00
thinkgem
e1b6cdc831 修正PC消息提醒获取按钮报错问题。 2018-08-23 22:04:12 +08:00
thinkgem
596b1245d9 访问日志去掉日期范围查询条件 2018-08-21 21:33:00 +08:00
thinkgem
145e0b6b07 微不足道的修改 2018-08-21 21:32:06 +08:00
thinkgem
437220e34a update version. 2018-08-19 20:25:27 +08:00
thinkgem
28e1cd6f1d 记住我的账号,使用在线列表踢出用户无效问题修正。 2018-08-19 17:32:58 +08:00
thinkgem
09286c8287 新增记住我密钥自定义设置选项shiro.rememberMe.secretKey 2018-08-19 17:31:13 +08:00
thinkgem
b195480441 增加微服务优化选项,可关闭一些不需要的功能开关,包括如下:1、可关闭根据模块状态去更新相连的菜单状态(menu.updateStatusByModuleStatus=false);
2、可关闭国际化管理(lang.enabled=false);3、可关闭任务调度功能(job.enabled=false);4、可关闭核心模块的Web功能(web.core.enabled=false);减少加载启动时间,控制在10秒内;
2018-08-19 11:05:29 +08:00
ThinkGem
ec73aa0ab0 更新 jeesite.yml 2018-08-18 20:15:58 +08:00
thinkgem
55bc4dd3ad Md5Utils增加获取文件MD5值,支持获取文件指定前部分的MD5。 2018-08-17 23:11:17 +08:00
thinkgem
7a82d8a31c 添加mybatis.scanTypeHandlersPackage参数,TypeHandlers的扫描基础包。 2018-08-17 20:36:17 +08:00
thinkgem
3e6044d902 v4.0.6 2018-08-14 21:14:21 +08:00
thinkgem
15dcb1b27d update 2018-08-13 21:35:43 +08:00
thinkgem
849b3a7ec0 将web项目的config文件分散到jar包里,让web项目更简洁。 2018-08-12 19:55:32 +08:00
thinkgem
225a6a94ad 新增服务器监控功能,查看CPU,内存,JVM,磁盘信息等 2018-08-12 18:23:48 +08:00
thinkgem
8c52dd5db1 通用CrudDao基类新增物理删除方法,phyDelete、phyDeleteByEntity。 2018-08-11 23:09:17 +08:00
thinkgem
300bbd5f8f 优化XSS过滤方法,解决一些可能会发生的问题。 2018-08-11 12:59:03 +08:00
thinkgem
099ce0758b Excel导入导出的缓存清理优化,增加close方法,杜绝可能会造成内存泄露的问题。 2018-08-11 12:43:57 +08:00
thinkgem
f91bb55f38 支持指定获取客户端IP的Header名称,防止IP伪造。 2018-08-09 23:26:17 +08:00
thinkgem
0e67815b8d 修正用户列表选择的selectData变量可能造成XSS漏洞 2018-08-09 22:45:19 +08:00
thinkgem
19ba6daea7 修正登录页记住账号在DES加密的情况下,会有XSS漏洞。 2018-08-09 21:04:26 +08:00
thinkgem
45a09933b0 新增参数:是否在登录后生成新的Session(默认false)详见 jeesite.yml 2018-08-08 21:40:24 +08:00
thinkgem
fc88e47a4b update 2018-08-06 22:04:49 +08:00
thinkgem
dc088a4764 增加MyBatis的Map参数传递和返回实例,支持分页。 2018-08-05 22:12:30 +08:00
thinkgem
6895d57cfa update readme.md 2018-08-04 15:51:26 +08:00
thinkgem
1b09cf9969 优化StringUtils.camelCase驼峰命名法转换,不允许第二个字符是大写,因为这样会造成bean引用失败 2018-08-04 15:42:49 +08:00
thinkgem
086ca1d882 修正属性配置文件表达式为空时可能报错问题。 2018-08-02 21:17:31 +08:00
thinkgem
d336c0fcf7 update terms.md 2018-08-02 21:13:10 +08:00
thinkgem
9736100fdc 新增支持无页签模式和表单弹窗模式(专业版)。 2018-07-29 21:45:02 +08:00
thinkgem
38acf1ae16 Global增加getConfigToBoolean、getConfigToInteger、getPropertyToBoolean、getPropertyToInteger方法 2018-07-29 21:41:59 +08:00
thinkgem
7ffa86df6e 参数配置的参数值config_value允许空值 2018-07-29 21:34:17 +08:00
thinkgem
2a8a7edb83 优化用户树选择查询。 2018-07-28 00:10:28 +08:00
thinkgem
4cf49b7446 Revert "Revert "add update script""
This reverts commit 9db7917975.
2018-07-22 23:49:08 +08:00
thinkgem
9db7917975 Revert "add update script"
This reverts commit 095ecddc8d45c7e63c66cf086b8095ffc18cf50d.
2018-07-22 23:47:05 +08:00
thinkgem
5dfa01c421 优化shiro.successUrl登录成功后跳转页面参数,支持ajax登录后跳转,sso下登录跳转 2018-07-22 23:47:05 +08:00
thinkgem
4f8e2ccb4e 增加一些连接池常用参数,详见 jeesite-core.yml 2018-07-22 23:47:04 +08:00
thinkgem
b643b97603 新增缓存监控功能,查看缓存内存,清理缓存等 2018-07-22 23:47:03 +08:00
thinkgem
e651f23210 update pom version 2018-07-22 14:04:50 +08:00
thinkgem
8ecd600155 update terms.md 2018-07-22 14:04:37 +08:00
thinkgem
45fabc8ca0 降低ReflectUtils的错误级别,如果null不抛错,打印日志警告即可。 2018-07-22 12:16:31 +08:00
thinkgem
89fdfc2070 Merge branch 'master' of https://gitee.com/thinkgem/jeesite4
# Conflicts:
#	web/bin/init-data.bat
#	web/bin/init-data.sh
2018-07-16 23:29:08 +08:00
ThinkGem
a8cc129464 更新 terms.md 2018-07-03 10:12:37 +08:00
ThinkGem
a1577453c3 更新 init-data.sh 2018-06-28 18:19:57 +08:00
ThinkGem
2288884964 更新 init-data.bat 2018-06-28 18:19:18 +08:00
107 changed files with 2217 additions and 618 deletions

View File

@@ -21,7 +21,7 @@ JeeSite 自开源以来已被广大爱好者用到了企业、政府、医疗、
* 视图层Spring MVC 4.3、Beetl 2.7 替换JSP、Bootstrap 3.3、AdminLTE 2.4
* 前端组件jQuery 1.12、jqGrid 4.7、layer 3.0、zTree 3.5、jquery-validation
* 工具组件Apache Commons、Logback 1.1、Jackson 2.8、POI 3.14、Quartz 2.2
* 乐云短信网关SmsUtils.java <http://www.lehuo520.cn>
* JFlow工作流引擎<https://gitee.com/thinkgem/jeesite4-jflow> http://ccflow.org
* 技术选型详情:<http://jeesite4.mydoc.io/?t=273599>
## 内置功能菜单
@@ -38,6 +38,8 @@ JeeSite 自开源以来已被广大爱好者用到了企业、政府、医疗、
* 数据表格API (DataGrid.js)<http://jeesite4.mydoc.io/?t=301488>
* 修改 (默认) 视图,新增主题:<http://jeesite4.mydoc.io/?t=267355>
* 手机 API 接口调用、前后分离:<http://jeesite4.mydoc.io/?t=270527>
* 代码生成工具使用手册:<http://jeesite4.mydoc.io/?t=316743>
* 常见问题:<http://jeesite4.mydoc.io/?t=284210>
# 快速体验
@@ -90,12 +92,12 @@ JeeSite的小版本4.0.x升级是非常便捷的你只需要将 pom.xml
# 技术交流方式
* QQ 群号: `127515876(已满)` `209330483(已满)` `223507718(已满)` `709534275` `730390092`
* 入群须知目前为付费群刚入群会有5分钟禁言腾讯预设置的无法解除稍等片刻即可正常发言由于群容量有限为了维持运营千人QQ群的所需支付的QQ年费会员费用故开启付费入群模式申请者只需支付少量金额即可加入这样也可以保证只有真实交流需求的人进入避免闲杂做广告人员的乱入新手提问前请先阅读此[【文章](http://www.dianbo.org/9238/stone/tiwendezhihui.htm)
* Gitee<https://gitee.com/thinkgem/jeesite4>
* 问题反馈:<https://gitee.com/thinkgem/jeesite4/issues>  [【新手必读](http://www.dianbo.org/9238/stone/tiwendezhihui.htm)
* 码云Gitee<https://gitee.com/thinkgem/jeesite4>
* GitHub<https://github.com/thinkgem/jeesite4>
* 问题反馈<https://gitee.com/thinkgem/jeesite4/issues>
* 作者博客:<https://my.oschina.net/thinkgem/blog>
* 作者博客<https://my.oschina.net/thinkgem>
* 官方网站:<http://jeesite.com>
* 官方论坛:<http://jeesite.net>
* 微信公众号:
![https://static.oschina.net/uploads/space/2018/0302/145133_OGZf_941661.jpg](https://static.oschina.net/uploads/space/2018/0302/145133_OGZf_941661.jpg "JeeSite4微信公众号")

View File

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

View File

@@ -8,6 +8,8 @@ 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 org.apache.commons.codec.DecoderException;
@@ -17,6 +19,7 @@ import org.apache.commons.lang3.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;
@@ -167,7 +170,9 @@ public class EncodeUtils {
* URL 解码, Encode默认为UTF-8.
*/
public static String decodeUrl(String part, String encoding) {
if (part == null){
return null;
}
try {
return URLDecoder.decode(part, encoding);
} catch (UnsupportedEncodingException e) {
@@ -181,30 +186,29 @@ public class EncodeUtils {
public static String decodeUrl2(String part) {
return decodeUrl(decodeUrl(part));
}
// 预编译XSS过滤正则表达式
private static Pattern p1 = Pattern.compile("<\\s*(script|link|style|iframe)\\s([\\s\\S]+?)<\\/\\s*\\1\\s*>", Pattern.CASE_INSENSITIVE);
private static Pattern p2 = Pattern.compile("\\s*on[a-z]+\\s*=\\s*(\"[^\"]+\"|'[^']+'|[^\\s]+)\\s*(?=>)", Pattern.CASE_INSENSITIVE);
private static Pattern p3 = Pattern.compile("\\s*(href|src)\\s*=\\s*(\"\\s*(javascript|vbscript):[^\"]+\"|'\\s*(javascript|vbscript):[^']+'|(javascript|vbscript):[^\\s]+)\\s*(?=>)", Pattern.CASE_INSENSITIVE);
private static Pattern p4 = Pattern.compile("epression\\((.|\\n)*\\);?", Pattern.CASE_INSENSITIVE);
private static List<Pattern> xssPatterns = ListUtils.newArrayList(
Pattern.compile("(<\\s*(script|link|style|iframe)([\\s\\S]*?)(>|<\\/\\s*\\1\\s*>))|(</\\s*(script|link|style|iframe)\\s*>)", Pattern.CASE_INSENSITIVE),
Pattern.compile("\\s*(href|src)\\s*=\\s*(\"\\s*(javascript|vbscript):[^\"]+\"|'\\s*(javascript|vbscript):[^']+'|(javascript|vbscript):[^\\s]+)\\s*(?=>)", Pattern.CASE_INSENSITIVE),
Pattern.compile("\\s*on[a-z]+\\s*=\\s*(\"[^\"]+\"|'[^']+'|[^\\s]+)\\s*(?=>)", Pattern.CASE_INSENSITIVE),
Pattern.compile("(eval\\((.|\\n)*\\)|xpression\\((.|\\n)*\\))", Pattern.CASE_INSENSITIVE)
);
/**
* XSS 非法字符过滤
* 内容以<!--HTML-->开头的用以下规则保留标签去掉js脚本
* 1、<\s*(script|link|style|iframe)\s([\s\S]+?)<\/\s*\1\s*>
* 2、\s*on[a-z]+\s*=\s*("[^"]+"|'[^']+'|[^\s]+)\s*(?=>)
* 3、\s*(href|src)\s*=\s*("\s*(javascript|vbscript):[^"]+"|'\s*(javascript|vbscript):[^']+'|(javascript|vbscript):[^\s]+)\s*(?=>)
* 4、epression\((.|\n)*\);?
* 其它情况下进行HTML4编码
* XSS 非法字符过滤,内容以<!--HTML-->开头的用以下规则(保留标签)
* @author ThinkGem
*/
public static String xssFilter(String text) {
String oriValue = StringUtils.trim(text);
if (text != null){
String oriValue = StringUtils.trim(text), value = oriValue;
value = p1.matcher(value).replaceAll("");
value = p2.matcher(value).replaceAll("");
value = p3.matcher(value).replaceAll("");
value = p4.matcher(value).replaceAll("");
String value = oriValue;
for (Pattern pattern : xssPatterns) {
Matcher matcher = pattern.matcher(value);
if (matcher.find()) {
value = matcher.replaceAll(StringUtils.EMPTY);
}
}
// 如果开始不是HTMLXMLJOSN格式则再进行HTML的 "、<、> 转码。
if (!StringUtils.startsWithIgnoreCase(value, "<!--HTML-->") // HTML
&& !StringUtils.startsWithIgnoreCase(value, "<?xml ") // XML
@@ -215,7 +219,7 @@ public class EncodeUtils {
value = value.replaceAll("\"", "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
}
if (logger.isInfoEnabled() && !value.equals(oriValue)){
logger.info("xssFilter: {} to {}", text, value);
logger.info("xssFilter: {} <=<=<= {}", value, text);
}
return value;
}
@@ -223,7 +227,7 @@ public class EncodeUtils {
}
// 预编译SQL过滤正则表达式
private static Pattern p5 = Pattern.compile("(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\\b(select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)", Pattern.CASE_INSENSITIVE);
private static Pattern sqlPattern = Pattern.compile("(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\\b(select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)", Pattern.CASE_INSENSITIVE);
/**
* SQL过滤防止注入传入参数输入有select相关代码替换空。
@@ -231,13 +235,48 @@ public class EncodeUtils {
*/
public static String sqlFilter(String text){
if (text != null){
String value = p5.matcher(text).replaceAll("");
String value = text;
Matcher matcher = sqlPattern.matcher(text);
if (matcher.find()) {
value = matcher.replaceAll(StringUtils.EMPTY);
}
if (logger.isWarnEnabled() && !value.equals(text)){
logger.warn("sqlFilter: {} to {}", text, value);
logger.info("sqlFilter: {} <=<=<= {}", value, text);
return StringUtils.EMPTY;
}
return value;
}
return null;
}
// public static void main(String[] args) {
// xssFilter("你好,<script>alert(document.cookie)</script>我还在。");
// xssFilter("你好,<strong>加粗文字</strong>我还在。");
// xssFilter("<!--HTML-->你好,\"><strong>加粗文字</strong>我还在。");
// xssFilter("<!--HTML-->你好,<iframe src=\"abcdef\"></iframe><strong>加粗文字</strong>我还在。");
// xssFilter("<!--HTML-->你好,<iframe src=\"abcdef\"/><strong>加粗文字</strong>我还在。");
// xssFilter("<!--HTML-->你好,<iframe src=\"abcdef\"><strong>加粗文字</strong>我还在。");
// xssFilter("<!--HTML-->你好,<script type=\"text/javascript\">alert(document.cookie)</script>我还在。");
// xssFilter("<!--HTML-->你好,<script\n type=\"text/javascript\">\nalert(document.cookie)\n</script>我还在。");
// xssFilter("<!--HTML-->你好,<script src='' onerror='alert(document.cookie)'></script>我还在。");
// xssFilter("<!--HTML-->你好,<script type=text/javascript>alert()我还在。");
// xssFilter("<!--HTML-->你好,<script>alert(document.cookie)</script>我还在。");
// xssFilter("<!--HTML-->你好,<script>window.location='url'我还在。");
// xssFilter("<!--HTML-->你好,</script></iframe>我还在。");
// xssFilter("<!--HTML-->你好eval(abc)我还在。");
// xssFilter("<!--HTML-->你好xpression(abc)我还在。");
// xssFilter("<!--HTML-->你好,<img src='abc.jpg' onerror='location='';alert(document.cookie);'></img>我还在。");
// xssFilter("<!--HTML-->你好,<img src='abc.jpg' onerror='alert(document.cookie);'/>我还在。");
// xssFilter("<!--HTML-->你好,<img src='abc.jpg' onerror='alert(document.cookie);'>我还在。");
// xssFilter("<!--HTML-->你好,<a onload='alert(\"abc\")'>hello</a>我还在。");
// xssFilter("<!--HTML-->你好,<a href=\"/abc\">hello</a>我还在。");
// xssFilter("<!--HTML-->你好,<a href='/abc'>hello</a>我还在。");
// xssFilter("<!--HTML-->你好,<a href='vbscript:alert(\"abc\");'>hello</a>我还在。");
// xssFilter("<!--HTML-->你好,<a href='javascript:alert(\"abc\");'>hello</a>我还在。");
// xssFilter("<!--HTML-->你好,?abc=def&hello=123&world={\"a\":1}我还在。");
// sqlFilter("你好select * from xxx where abc=def and 1=1我还在。");
// sqlFilter("你好insert into xxx values(1,2,3,4,5)我还在。");
// sqlFilter("你好delete from xxx我还在。");
// }
}

View File

@@ -3,12 +3,16 @@
*/
package com.jeesite.common.codec;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import com.jeesite.common.io.IOUtils;
/**
* MD5不可逆加密工具类
* @author ThinkGem
@@ -17,7 +21,6 @@ public class Md5Utils {
private static final String MD5 = "MD5";
private static final String DEFAULT_ENCODING = "UTF-8";
/**
* 对输入字符串进行md5散列.
@@ -63,5 +66,36 @@ public class Md5Utils {
public static byte[] md5(InputStream input) throws IOException {
return DigestUtils.digest(input, MD5);
}
/**
* 获取文件的MD5值
*/
public static String md5File(File file) {
return md5File(file, -1);
}
/**
* 获取文件的MD5值支持获取文件部分的MD5值
*/
public static String md5File(File file, int size) {
if (file != null && file.exists()){
InputStream in = null;
try {
byte[] bytes = null;
in = FileUtils.openInputStream(file);
if (size != -1 && file.length() >= size){
bytes = IOUtils.toByteArray(in, size);
}else{
bytes = IOUtils.toByteArray(in);
}
return EncodeUtils.encodeHex(md5(bytes));
} catch (IOException e) {
return StringUtils.EMPTY;
} finally {
IOUtils.closeQuietly(in);
}
}
return StringUtils.EMPTY;
}
}

View File

@@ -383,7 +383,8 @@ public class ListUtils extends org.apache.commons.collections.ListUtils {
public static <T> List<T> listOrderBy(List<T> list, String orderBy){
if (list != null && StringUtils.isNotBlank(orderBy)){
final String[] ss = orderBy.trim().split(" ");
if (ss != null && ss.length == 2){
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) {
@@ -395,12 +396,13 @@ public class ListUtils extends org.apache.commons.collections.ListUtils {
s1 = ObjectUtils.toString(ReflectUtils.invokeGetter(o1, ss[0]));
s2 = ObjectUtils.toString(ReflectUtils.invokeGetter(o2, ss[0]));
}
if ("asc".equals(ss[1])){
if ("asc".equalsIgnoreCase(t)){
return s1.compareTo(s2);
}else{
return s2.compareTo(s1);
}
}});
}
});
}
}
return list;

View File

@@ -814,14 +814,14 @@ public class FileUtils extends org.apache.commons.io.FileUtils {
try {
out.close();
} catch (IOException e) {
logger.error(e.getMessage(), e);
// logger.error(e.getMessage(), e);
}
}
if (raf != null) {
try {
raf.close();
} catch (IOException e) {
logger.error(e.getMessage(), e);
// logger.error(e.getMessage(), e);
}
}
}

View File

@@ -170,7 +170,7 @@ public class PropertiesUtils {
while(m.find()) {
String g = m.group();
String keyChild = g.replaceAll("\\$\\{", "").replaceAll("\\}", "");
value = value.replace(g, getProperty(keyChild));
value = StringUtils.replace(value, g, getProperty(keyChild));
}
return value;
}else{

View File

@@ -17,6 +17,10 @@ public class ByteUtils {
* @return
*/
public static String formatByteSize(long byteSize) {
if (byteSize <= -1){
return String.valueOf(byteSize);
}
double size = 1.0 * byteSize;

View File

@@ -4,6 +4,7 @@
package com.jeesite.common.lang;
import java.math.BigDecimal;
import java.text.DecimalFormat;
/**
* BigDecimal工具类
@@ -92,4 +93,19 @@ public class NumberUtils extends org.apache.commons.lang3.math.NumberUtils {
return bg.setScale(0, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 格式化数值类型
* @param data
* @param pattern
*/
public static String formatNumber(Object data, String pattern) {
DecimalFormat df = null;
if (pattern == null) {
df = new DecimalFormat();
} else {
df = new DecimalFormat(pattern);
}
return df.format(data);
}
}

View File

@@ -14,13 +14,14 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.nustaq.serialization.FSTConfiguration;
import org.springframework.beans.BeanUtils;
import org.springframework.core.NamedThreadLocal;
import com.jeesite.common.io.IOUtils;
/**
* 对象操作工具类, 继承org.apache.commons.lang3.ObjectUtils类
* @author ThinkGem
* @version 2014-6-29
* @version 2018-08-11
*/
public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {
@@ -212,73 +213,14 @@ public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {
}
return object;
}
// // Kryo不是线程安全的所以要建立一个线程变量每一个线程实例化一次
// public static final ThreadLocal<Kryo> kryos = new ThreadLocal<Kryo>() {
// @Override
// protected Kryo initialValue() {
// Kryo kryo = new Kryo();
// // 设置false关闭注册行为 Kryo支持对注册行为如kryo.register(SomeClazz.class);
// // 这会赋予该Class一个从0开始的编号但Kryo使用注册行为最大的问题在于
// // 其不保证同一个Class每一次注册的号码想用这与注册的顺序有关也就意味着在不同的机器、
// // 同一个机器重启前后都有可能拥有不同的编号,这会导致序列化产生问题,所以在分布式项目中,一般关闭注册行为。
// kryo.setRegistrationRequired(false);
// // 支持循环引用
// kryo.setReferences(true);
// return kryo;
// };
// };
//
// /**
// * Kryo序列化对象
// * @param object
// * @return
// */
// public static byte[] serializeKryo(Object object) {
// byte[] bytes = null;
// Output output = null;
// try {
// if (object != null) {
// output = new Output(1024, -1);
// kryos.get().writeClassAndObject(output, object);
// bytes = output.toBytes();
// }
// } catch (Exception e) {
// e.printStackTrace();
// } finally {
// if (output != null) {
// output.close();
// }
// }
// return bytes;
// }
//
// /**
// * Kryo反序列化对象
// * @param bytes
// * @return
// */
// public static Object unserializeKryo(byte[] bytes) {
// Object object = null;
// Input input = null;
// try {
// if (bytes != null && bytes.length > 0) {
// input = new Input(bytes, 0, bytes.length);
// object = kryos.get().readClassAndObject(input);
// }
// } catch (Exception e) {
// e.printStackTrace();
// } finally {
// if (input != null) {
// input.close();
// }
// }
// return object;
// }
// FST序列化配置对象
private static FSTConfiguration fst = FSTConfiguration.createDefaultConfiguration();
private static ThreadLocal<FSTConfiguration> fst = new NamedThreadLocal<FSTConfiguration>("FSTConfiguration") {
public FSTConfiguration initialValue() {
return FSTConfiguration.createDefaultConfiguration();
}
};
/**
* FST 序列化对象
* @param object
@@ -289,7 +231,7 @@ public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {
return null;
}
long beginTime = System.currentTimeMillis();
byte[] bytes = fst.asByteArray(object);
byte[] bytes = fst.get().asByteArray(object);
long totalTime = System.currentTimeMillis() - beginTime;
if (totalTime > 3000){
System.out.println("Fst serialize time: " + TimeUtils.formatDateAgo(totalTime));
@@ -307,7 +249,7 @@ public class ObjectUtils extends org.apache.commons.lang3.ObjectUtils {
return null;
}
long beginTime = System.currentTimeMillis();
Object object = fst.asObject(bytes);
Object object = fst.get().asObject(bytes);
long totalTime = System.currentTimeMillis() - beginTime;
if (totalTime > 3000){
System.out.println("Fst unserialize time: " + TimeUtils.formatDateAgo(totalTime));

View File

@@ -250,16 +250,14 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
if (s == null) {
return null;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == SEPARATOR) {
upperCase = true;
upperCase = i != 1; // 不允许第二个字符是大写
} else if (upperCase) {
sb.append(Character.toUpperCase(c));
upperCase = false;
@@ -267,7 +265,6 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
sb.append(c);
}
}
return sb.toString();
}
@@ -297,18 +294,14 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
if (s == null) {
return null;
}
StringBuilder sb = new StringBuilder();
boolean upperCase = false;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
boolean nextUpperCase = true;
if (i < (s.length() - 1)) {
nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
}
if ((i > 0) && Character.isUpperCase(c)) {
if (!upperCase || !nextUpperCase) {
sb.append(SEPARATOR);
@@ -317,10 +310,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
} else {
upperCase = false;
}
sb.append(Character.toLowerCase(c));
}
return sb.toString();
}

View File

@@ -11,6 +11,7 @@ import java.util.TimeZone;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
@@ -46,6 +47,8 @@ public class JsonMapper extends ObjectMapper {
}
public JsonMapper() {
// Spring ObjectMapper 初始化配置,支持 @JsonView
new Jackson2ObjectMapperBuilder().configure(this);
// 为Null时不序列化
this.setSerializationInclusion(Include.NON_NULL);
// 允许单引号
@@ -61,7 +64,7 @@ public class JsonMapper extends ObjectMapper {
@Override
public void serialize(Object value, JsonGenerator jgen,
SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeString("");
jgen.writeString(StringUtils.EMPTY);
}
});
// // 统一默认Date类型转换格式。如果设置Bean中的@JsonFormat将失效

View File

@@ -21,6 +21,7 @@ import org.dom4j.Element;
import org.dom4j.Namespace;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import com.fasterxml.jackson.databind.JavaType;
@@ -46,6 +47,8 @@ public class XmlMapper extends com.fasterxml.jackson.dataformat.xml.XmlMapper{
* 构造方法
*/
public XmlMapper() {
// Spring ObjectMapper 初始化配置,支持 @JsonView
new Jackson2ObjectMapperBuilder().configure(this);
// 设置时区
this.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
}

View File

@@ -24,12 +24,12 @@ public class EmailUtils {
* @return
*/
public static boolean send(String toAddress, String subject, String content) {
PropertiesUtils loader = PropertiesUtils.getInstance();
String fromAddress = loader.getProperty("msg.email.fromAddress");
String fromPassword = loader.getProperty("msg.email.fromPassword");
String fromHostName = loader.getProperty("msg.email.fromHostName");
String sslOnConnect = loader.getProperty("msg.email.sslOnConnect", "false");
String sslSmtpPort = loader.getProperty("msg.email.sslSmtpPort");
PropertiesUtils props = PropertiesUtils.getInstance();
String fromAddress = props.getProperty("msg.email.fromAddress");
String fromPassword = props.getProperty("msg.email.fromPassword");
String fromHostName = props.getProperty("msg.email.fromHostName");
String sslOnConnect = props.getProperty("msg.email.sslOnConnect", "false");
String sslSmtpPort = props.getProperty("msg.email.sslSmtpPort");
return send(fromAddress, fromPassword, fromHostName, sslOnConnect, sslSmtpPort, toAddress, subject, content);
}

View File

@@ -1,141 +1,43 @@
package com.jeesite.common.msg;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jeesite.common.io.PropertiesUtils;
import com.jeesite.common.lang.DateUtils;
/**
* 发送短信(乐云短信
* 发送短信(请实现send方法
*/
public class SmsUtils {
private final static Logger logger = LoggerFactory.getLogger(SmsUtils.class);
private final static PropertiesUtils props = PropertiesUtils.getInstance();
private final static String url = props.getProperty("msg.sms.url", "http://lehuo520.cn/a/sms/api");
private final static String data = props.getProperty("msg.sms.data", "username=jeesite&password=jeesite.com");
private final static String prefix = props.getProperty("msg.sms.prefix", "【JeeSite】");
private final static String suffix = props.getProperty("msg.sms.suffix", "");
// public static void main(String[] args) {
// String phone = "18500000000"; // 收短信人手机号码;例如:18500000000 支持多号码号码之间用英文逗号隔开最多100个
// String content = "您好您的验证码是123456请勿透露给其他人感谢您的使用。"; // 输入需要发送内容;例如:你好这是一条测试短信
// String smsid = ""; // 短信id查询短信状态报告时需要可为空
// System.out.println(send(content, phone)); // 发短信
// System.out.println(status(smsid, phone)); // 取状态
// System.out.println(reply()); //取上行 回复短信
// }
/**
* 发送短信
* @param content 接受内容
* @param phone 接受手机号码
* @return {"result":"0","describing""提交成功","sms":[{"phone":"18073110001,18073110002","smsid":"83bd18f1d48b4cc9b9fe7810c768ac43","status":"3"}]}
* 模拟发送短信
* @param content 短信内容
* @param mobile 接受手机号码
*/
public static String send(String content, String phone) {
return send(content, phone, null);
public static String send(String content, String mobile) {
// PropertiesUtils props = PropertiesUtils.getInstance();
// String url = props.getProperty("msg.sms.url");
// String data = props.getProperty("msg.sms.data");
// String prefix = props.getProperty("msg.sms.prefix", "");
// String suffix = props.getProperty("msg.sms.suffix", "");
// Connection conn = Jsoup.connect(url);
// conn.postDataCharset("UTF-8");
// conn.method(Method.POST);
// for (String param : StringUtils.split(data, "&")){
// String[] ss = StringUtils.split(param, "=");
// if (ss.length == 1){
// conn.data(ss[0], "");
// }else if (ss.length == 2){
// conn.data(ss[0], ss[1]);
// }
// }
// // 手机号码
// conn.data("mobile", mobile);
// // 短信内容
// conn.data("content", prefix + content + suffix);
logger.warn("模拟发送短信成功!请实现 "+SmsUtils.class+" 的 send 方法。");
return "{result:0,message:\"模拟发送短信成功!\"}";
}
/**
* 发送短信
* @param content 接受内容
* @param phone 接受手机号码
* @param sendtime 发送时间为空立即发送
* @return {"result":"0","describing""提交成功","sms":[{"phone":"18073110001,18073110002","smsid":"83bd18f1d48b4cc9b9fe7810c768ac43","status":"3"}]}
*/
public static String send(String content, String phone, Date sendTime) {
String res = "";
try {
String param = data + "&phone=" + phone + "&content=" + URLEncoder
.encode(prefix + content + suffix, "UTF-8")
+ "&sendTime=" + (sendTime != null ? DateUtils
.formatDate(sendTime, "yyyyMMddHHmm") : "");
res = connectURL(url + "/send", param);
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
return res;
}
/**
* 获取状态
* @param smsid,phone可为空,为空取最近两天未获取状态报告,沦询间隔时间不能低于5分钟
* @return 请求错误返回页面示例: {"result":"-1","describing""帐号不存在,请检查用户名或者密码是否正确","sms":[]} 请求成功返回页面示例:
* {"result":"0","describing""提交成功","sms":[{"phone":"18073110001","smsid":"83bd18f1d48b4cc9b9fe7810c768ac43","status":"7"},{"phone":"18073110001","smsid":"83bd18f1d48b4cc9b9fe7810c768ac43","status":"8"}]}
*/
public static String status(String smsid, String phone) {
String res = "";
try {
String param = data + "&smsid=" + smsid;
res = connectURL(url + "/status", param);
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
return res;
}
/**
* 获取回复
* @param smsid:下发短信对应短信IDtaskId同一批任务ID
* @return {"result":"0","sms":[{"phone":"18073110001","neirong":"已收到","taskId":"83bd18f1d48b4cc9b9fe7810c768ac43"},"smsId":"83bd18f1d48b48j9b9fe7810c768ac43"}]}
*/
public static String reply() {
String res = "";
try {
String param = data;
res = connectURL(url + "/query", param);
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
return res;
}
/**
* 进行http提交
* @param
* @return
* @throws IOException
* @throws Exception
*/
private static String connectURL(String url, String param) throws IOException {
String res = "";
HttpURLConnection urlConn = null;
URL url1 = new URL(url);
urlConn = (HttpURLConnection) url1.openConnection();
urlConn.setRequestMethod("POST");
urlConn.setDoOutput(true);
OutputStream out = null;
BufferedReader rd = null;
try{
out = urlConn.getOutputStream();
out.write(param.getBytes("UTF-8"));
out.flush();
rd = new BufferedReader(new InputStreamReader(urlConn.getInputStream(), "UTF-8"));
StringBuffer sb = new StringBuffer();
int ch;
while ((ch = rd.read()) > -1) {
sb.append((char) ch);
}
res = sb.toString().trim();
}finally {
if (out!=null){
out.close();
}
if (rd!=null){
rd.close();
}
}
return res;
}
}

View File

@@ -2,7 +2,8 @@ package com.jeesite.common.network;
import javax.servlet.http.HttpServletRequest;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.io.PropertiesUtils;
import com.jeesite.common.lang.StringUtils;
public class IpUtils {
@@ -16,20 +17,23 @@ public class IpUtils {
if (request == null) {
return "unknown";
}
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
String ip = null;
String xffName = PropertiesUtils.getInstance()
.getProperty("shiro.remoteAddrHeaderName");
if (StringUtils.isNotBlank(xffName)){
ip = request.getHeader(xffName);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return StringUtils.split(ObjectUtils.toString(ip), ",")[0];
if (StringUtils.isNotBlank(ip)){
ip = EncodeUtils.xssFilter(ip);
ip = StringUtils.split(ip, ",")[0];
}
if (StringUtils.isBlank(ip)){
ip = "unknown";
}
return ip;
}
/**

View File

@@ -76,7 +76,9 @@ public class ReflectUtils {
public static Object getFieldValue(final Object obj, final String fieldName) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
//throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
logger.warn("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return null;
}
Object result = null;
try {
@@ -93,7 +95,9 @@ public class ReflectUtils {
public static void setFieldValue(final Object obj, final String fieldName, final Object value) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) {
throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
//throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
logger.warn("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
return;
}
try {
field.set(obj, value);
@@ -114,7 +118,9 @@ public class ReflectUtils {
}
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
if (method == null) {
throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
//throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
logger.warn("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try {
return method.invoke(obj, args);
@@ -132,7 +138,10 @@ public class ReflectUtils {
public static Object 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 + "] 方法 ");
logger.warn("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
return null;
}
try {
// 类型转换(将参数数据类型转换为目标方法参数类型)
@@ -174,7 +183,11 @@ public class ReflectUtils {
* 如向上转型到Object仍无法找到, 返回null.
*/
public static Field getAccessibleField(final Object obj, final String fieldName) {
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()) {
try {
@@ -197,7 +210,11 @@ public class ReflectUtils {
*/
public static Method getAccessibleMethod(final Object obj, final String methodName,
final Class<?>... parameterTypes) {
Validate.notNull(obj, "object can't be null");
// 为空不报错。直接返回 null
// Validate.notNull(obj, "object can't be null");
if (obj == null){
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
try {
@@ -219,7 +236,11 @@ public class ReflectUtils {
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
*/
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) {
Validate.notNull(obj, "object can't be null");
// 为空不报错。直接返回 null
// Validate.notNull(obj, "object can't be null");
if (obj == null){
return null;
}
Validate.notBlank(methodName, "methodName can't be blank");
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) {
Method[] methods = searchType.getDeclaredMethods();

View File

@@ -0,0 +1,24 @@
package com.jeesite.common.ueditor;
public class Encoder {
public static String toUnicode ( String input ) {
StringBuilder builder = new StringBuilder();
char[] chars = input.toCharArray();
for ( char ch : chars ) {
if ( ch < 256 ) {
builder.append( ch );
} else {
builder.append( "\\u" + Integer.toHexString( ch& 0xffff ) );
}
}
return builder.toString();
}
}

View File

@@ -0,0 +1,170 @@
package com.jeesite.common.ueditor;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import com.jeesite.common.web.http.ServletUtils;
public class PathFormat {
private static final String TIME = "time";
private static final String FULL_YEAR = "yyyy";
private static final String YEAR = "yy";
private static final String MONTH = "mm";
private static final String DAY = "dd";
private static final String HOUR = "hh";
private static final String MINUTE = "ii";
private static final String SECOND = "ss";
private static final String RAND = "rand";
private static final String USERID = "userid"; // ThinkGem 添加自定义变量获取当前用户ID
private static Date currentDate = null;
private static Pattern pattern = Pattern.compile( "\\{([^\\}]+)\\}", Pattern.CASE_INSENSITIVE );
public static String parse ( String input ) {
Matcher matcher = pattern.matcher(input);
PathFormat.currentDate = new Date();
StringBuffer sb = new StringBuffer();
while ( matcher.find() ) {
matcher.appendReplacement(sb, PathFormat.getString( matcher.group( 1 ) ) );
}
matcher.appendTail(sb);
return sb.toString();
}
/**
* 格式化路径, 把windows路径替换成标准路径
* @param input 待格式化的路径
* @return 格式化后的路径
*/
public static String format ( String input ) {
return input.replace( "\\", "/" );
}
public static String parse ( String input, String filename ) {
Matcher matcher = pattern.matcher(input);
String matchStr = null;
PathFormat.currentDate = new Date();
StringBuffer sb = new StringBuffer();
while ( matcher.find() ) {
matchStr = matcher.group( 1 );
if ( matchStr.indexOf( "filename" ) != -1 ) {
filename = filename.replace( "$", "\\$" ).replaceAll( "[\\/:*?\"<>|]", "" );
matcher.appendReplacement(sb, filename );
} else {
matcher.appendReplacement(sb, PathFormat.getString( matchStr ) );
}
}
matcher.appendTail(sb);
return sb.toString();
}
private static String getString ( String pattern ) {
pattern = pattern.toLowerCase();
// time 处理
if ( pattern.indexOf( PathFormat.TIME ) != -1 ) {
return PathFormat.getTimestamp();
} else if ( pattern.indexOf( PathFormat.FULL_YEAR ) != -1 ) {
return PathFormat.getFullYear();
} else if ( pattern.indexOf( PathFormat.YEAR ) != -1 ) {
return PathFormat.getYear();
} else if ( pattern.indexOf( PathFormat.MONTH ) != -1 ) {
return PathFormat.getMonth();
} else if ( pattern.indexOf( PathFormat.DAY ) != -1 ) {
return PathFormat.getDay();
} else if ( pattern.indexOf( PathFormat.HOUR ) != -1 ) {
return PathFormat.getHour();
} else if ( pattern.indexOf( PathFormat.MINUTE ) != -1 ) {
return PathFormat.getMinute();
} else if ( pattern.indexOf( PathFormat.SECOND ) != -1 ) {
return PathFormat.getSecond();
} else if ( pattern.indexOf( PathFormat.RAND ) != -1 ) {
return PathFormat.getRandom( pattern );
} else if ( pattern.indexOf( PathFormat.USERID ) != -1 ) {
return PathFormat.getUserid( pattern );
}
return pattern;
}
private static String getTimestamp () {
return System.currentTimeMillis() + "";
}
private static String getFullYear () {
return new SimpleDateFormat( "yyyy" ).format( PathFormat.currentDate );
}
private static String getYear () {
return new SimpleDateFormat( "yy" ).format( PathFormat.currentDate );
}
private static String getMonth () {
return new SimpleDateFormat( "MM" ).format( PathFormat.currentDate );
}
private static String getDay () {
return new SimpleDateFormat( "dd" ).format( PathFormat.currentDate );
}
private static String getHour () {
return new SimpleDateFormat( "HH" ).format( PathFormat.currentDate );
}
private static String getMinute () {
return new SimpleDateFormat( "mm" ).format( PathFormat.currentDate );
}
private static String getSecond () {
return new SimpleDateFormat( "ss" ).format( PathFormat.currentDate );
}
private static String getRandom ( String pattern ) {
int length = 0;
pattern = pattern.split( ":" )[ 1 ].trim();
length = Integer.parseInt( pattern );
return ( Math.random() + "" ).replace( ".", "" ).substring( 0, length );
}
private static String getUserid(String pattern) {
String userId = null;
HttpServletRequest request = ServletUtils.getRequest();
if (request != null){
userId = (String)request.getSession().getAttribute("userCode");
}
return StringUtils.isNotBlank(userId) ? userId : "0";
}
}

View File

@@ -0,0 +1,42 @@
package com.jeesite.common.ueditor.define;
import java.util.Map;
import java.util.HashMap;
/**
* 定义请求action类型
* @author hancong03@baidu.com
*/
@SuppressWarnings("serial")
public final class ActionMap {
// 获取配置请求
public static final int CONFIG = 0;
public static final int UPLOAD_IMAGE = 1;
public static final int UPLOAD_SCRAWL = 2;
public static final int UPLOAD_VIDEO = 3;
public static final int UPLOAD_FILE = 4;
public static final int CATCH_IMAGE = 5;
public static final int LIST_FILE = 6;
public static final int LIST_IMAGE = 7;
public static final Map<String, Integer> mapping;
static {
mapping = new HashMap<String, Integer>(){{
put( "config", ActionMap.CONFIG );
put( "uploadimage", ActionMap.UPLOAD_IMAGE );
put( "uploadscrawl", ActionMap.UPLOAD_SCRAWL );
put( "uploadvideo", ActionMap.UPLOAD_VIDEO );
put( "uploadfile", ActionMap.UPLOAD_FILE );
put( "catchimage", ActionMap.CATCH_IMAGE );
put( "listfile", ActionMap.LIST_FILE );
put( "listimage", ActionMap.LIST_IMAGE );
}};
}
public static int getType ( String key ) {
return ActionMap.mapping.get( key );
}
}

View File

@@ -0,0 +1,5 @@
package com.jeesite.common.ueditor.define;
public enum ActionState {
UNKNOW_ERROR
}

View File

@@ -0,0 +1,78 @@
package com.jeesite.common.ueditor.define;
import java.util.HashMap;
import java.util.Map;
public final class AppInfo {
public static final int SUCCESS = 0;
public static final int MAX_SIZE = 1;
public static final int PERMISSION_DENIED = 2;
public static final int FAILED_CREATE_FILE = 3;
public static final int IO_ERROR = 4;
public static final int NOT_MULTIPART_CONTENT = 5;
public static final int PARSE_REQUEST_ERROR = 6;
public static final int NOTFOUND_UPLOAD_DATA = 7;
public static final int NOT_ALLOW_FILE_TYPE = 8;
public static final int INVALID_ACTION = 101;
public static final int CONFIG_ERROR = 102;
public static final int PREVENT_HOST = 201;
public static final int CONNECTION_ERROR = 202;
public static final int REMOTE_FAIL = 203;
public static final int NOT_DIRECTORY = 301;
public static final int NOT_EXIST = 302;
public static final int ILLEGAL = 401;
@SuppressWarnings("serial")
public static Map<Integer, String> info = new HashMap<Integer, String>(){{
put( AppInfo.SUCCESS, "SUCCESS" );
// 无效的Action
put( AppInfo.INVALID_ACTION, "\u65E0\u6548\u7684Action" );
// 配置文件初始化失败
put( AppInfo.CONFIG_ERROR, "\u914D\u7F6E\u6587\u4EF6\u521D\u59CB\u5316\u5931\u8D25" );
// 抓取远程图片失败
put( AppInfo.REMOTE_FAIL, "\u6293\u53D6\u8FDC\u7A0B\u56FE\u7247\u5931\u8D25" );
// 被阻止的远程主机
put( AppInfo.PREVENT_HOST, "\u88AB\u963B\u6B62\u7684\u8FDC\u7A0B\u4E3B\u673A" );
// 远程连接出错
put( AppInfo.CONNECTION_ERROR, "\u8FDC\u7A0B\u8FDE\u63A5\u51FA\u9519" );
// "文件大小超出限制"
put( AppInfo.MAX_SIZE, "\u6587\u4ef6\u5927\u5c0f\u8d85\u51fa\u9650\u5236" );
// 权限不足, 多指写权限
put( AppInfo.PERMISSION_DENIED, "\u6743\u9650\u4E0D\u8DB3" );
// 创建文件失败
put( AppInfo.FAILED_CREATE_FILE, "\u521B\u5EFA\u6587\u4EF6\u5931\u8D25" );
// IO错误
put( AppInfo.IO_ERROR, "IO\u9519\u8BEF" );
// 上传表单不是multipart/form-data类型
put( AppInfo.NOT_MULTIPART_CONTENT, "\u4E0A\u4F20\u8868\u5355\u4E0D\u662Fmultipart/form-data\u7C7B\u578B" );
// 解析上传表单错误
put( AppInfo.PARSE_REQUEST_ERROR, "\u89E3\u6790\u4E0A\u4F20\u8868\u5355\u9519\u8BEF" );
// 未找到上传数据
put( AppInfo.NOTFOUND_UPLOAD_DATA, "\u672A\u627E\u5230\u4E0A\u4F20\u6570\u636E" );
// 不允许的文件类型
put( AppInfo.NOT_ALLOW_FILE_TYPE, "\u4E0D\u5141\u8BB8\u7684\u6587\u4EF6\u7C7B\u578B" );
// 指定路径不是目录
put( AppInfo.NOT_DIRECTORY, "\u6307\u5B9A\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55" );
// 指定路径并不存在
put( AppInfo.NOT_EXIST, "\u6307\u5B9A\u8DEF\u5F84\u5E76\u4E0D\u5B58\u5728" );
// callback参数名不合法
put( AppInfo.ILLEGAL, "Callback\u53C2\u6570\u540D\u4E0D\u5408\u6CD5" );
}};
public static String getStateInfo ( int key ) {
return AppInfo.info.get( key );
}
}

View File

@@ -0,0 +1,92 @@
package com.jeesite.common.ueditor.define;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import com.jeesite.common.ueditor.Encoder;
public class BaseState implements State {
private boolean state = false;
private String info = null;
private Map<String, String> infoMap = new HashMap<String, String>();
public BaseState () {
this.state = true;
}
public BaseState ( boolean state ) {
this.setState( state );
}
public BaseState ( boolean state, String info ) {
this.setState( state );
this.info = info;
}
public BaseState ( boolean state, int infoCode ) {
this.setState( state );
this.info = AppInfo.getStateInfo( infoCode );
}
@Override
public boolean isSuccess () {
return this.state;
}
public void setState ( boolean state ) {
this.state = state;
}
public void setInfo ( String info ) {
this.info = info;
}
public void setInfo ( int infoCode ) {
this.info = AppInfo.getStateInfo( infoCode );
}
@Override
public String toJSONString() {
return this.toString();
}
@Override
public String toString () {
String key = null;
String stateVal = this.isSuccess() ? AppInfo.getStateInfo( AppInfo.SUCCESS ) : this.info;
StringBuilder builder = new StringBuilder();
builder.append( "{\"state\": \"" + stateVal + "\"" );
Iterator<String> iterator = this.infoMap.keySet().iterator();
while ( iterator.hasNext() ) {
key = iterator.next();
builder.append( ",\"" + key + "\": \"" + this.infoMap.get(key) + "\"" );
}
builder.append( "}" );
return Encoder.toUnicode( builder.toString() );
}
@Override
public void putInfo(String name, String val) {
this.infoMap.put(name, val);
}
@Override
public void putInfo(String name, long val) {
this.putInfo(name, val+"");
}
}

View File

@@ -0,0 +1,32 @@
package com.jeesite.common.ueditor.define;
import java.util.HashMap;
import java.util.Map;
public class FileType {
public static final String JPG = "JPG";
@SuppressWarnings("serial")
private static final Map<String, String> types = new HashMap<String, String>(){{
put( FileType.JPG, ".jpg" );
}};
public static String getSuffix ( String key ) {
return FileType.types.get( key );
}
/**
* 根据给定的文件名,获取其后缀信息
* @param filename
* @return
*/
public static String getSuffixByFilename ( String filename ) {
return filename.substring( filename.lastIndexOf( "." ) ).toLowerCase();
}
}

View File

@@ -0,0 +1,21 @@
package com.jeesite.common.ueditor.define;
import java.util.HashMap;
import java.util.Map;
public class MIMEType {
@SuppressWarnings("serial")
public static final Map<String, String> types = new HashMap<String, String>(){{
put( "image/gif", ".gif" );
put( "image/jpeg", ".jpg" );
put( "image/jpg", ".jpg" );
put( "image/png", ".png" );
put( "image/bmp", ".bmp" );
}};
public static String getSuffix ( String mime ) {
return MIMEType.types.get( mime );
}
}

View File

@@ -0,0 +1,111 @@
package com.jeesite.common.ueditor.define;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.jeesite.common.ueditor.Encoder;
/**
* 多状态集合状态
* 其包含了多个状态的集合, 其本身自己也是一个状态
* @author hancong03@baidu.com
*/
public class MultiState implements State {
private boolean state = false;
private String info = null;
private Map<String, Long> intMap = new HashMap<String, Long>();
private Map<String, String> infoMap = new HashMap<String, String>();
private List<String> stateList = new ArrayList<String>();
public MultiState ( boolean state ) {
this.state = state;
}
public MultiState ( boolean state, String info ) {
this.state = state;
this.info = info;
}
public MultiState ( boolean state, int infoKey ) {
this.state = state;
this.info = AppInfo.getStateInfo( infoKey );
}
@Override
public boolean isSuccess() {
return this.state;
}
public void addState ( State state ) {
stateList.add( state.toJSONString() );
}
/**
* 该方法调用无效果
*/
@Override
public void putInfo(String name, String val) {
this.infoMap.put(name, val);
}
@Override
public String toJSONString() {
String stateVal = this.isSuccess() ? AppInfo.getStateInfo( AppInfo.SUCCESS ) : this.info;
StringBuilder builder = new StringBuilder();
builder.append( "{\"state\": \"" + stateVal + "\"" );
// 数字转换
Iterator<String> iterator = this.intMap.keySet().iterator();
while ( iterator.hasNext() ) {
stateVal = iterator.next();
builder.append( ",\""+ stateVal +"\": " + this.intMap.get( stateVal ) );
}
iterator = this.infoMap.keySet().iterator();
while ( iterator.hasNext() ) {
stateVal = iterator.next();
builder.append( ",\""+ stateVal +"\": \"" + this.infoMap.get( stateVal ) + "\"" );
}
builder.append( ", list: [" );
iterator = this.stateList.iterator();
while ( iterator.hasNext() ) {
builder.append( iterator.next() + "," );
}
if ( this.stateList.size() > 0 ) {
builder.deleteCharAt( builder.length() - 1 );
}
builder.append( " ]}" );
return Encoder.toUnicode( builder.toString() );
}
@Override
public void putInfo(String name, long val) {
this.intMap.put( name, val );
}
}

View File

@@ -0,0 +1,17 @@
package com.jeesite.common.ueditor.define;
/**
* 处理状态接口
* @author hancong03@baidu.com
*/
public interface State {
public boolean isSuccess ();
public void putInfo( String name, String val );
public void putInfo ( String name, long val );
public String toJSONString ();
}

View File

@@ -0,0 +1,124 @@
package com.jeesite.common.ueditor.hunter;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.FileUtils;
import com.jeesite.common.ueditor.PathFormat;
import com.jeesite.common.ueditor.define.AppInfo;
import com.jeesite.common.ueditor.define.BaseState;
import com.jeesite.common.ueditor.define.MultiState;
import com.jeesite.common.ueditor.define.State;
public class FileManager {
public static final String USERFILES_BASE_URL = "/userfiles/";
private String dir = null;
private String rootPath = null;
private String[] allowFiles = null;
private int count = 0;
public FileManager ( Map<String, Object> conf ) {
this.rootPath = (String)conf.get( "rootPath" );
this.dir = this.rootPath + (String)conf.get( "dir" );
this.allowFiles = this.getAllowFiles( conf.get("allowFiles") );
this.count = (Integer)conf.get( "count" );
}
public State listFile (HttpServletRequest request, int index ) {
// File dir = new File( this.dir );
File dir = new File( PathFormat.parse(this.dir) ); // ThinkGem 路径中有变量时变量不转化问题
State state = null;
if ( !dir.exists() ) {
return new BaseState( false, AppInfo.NOT_EXIST );
}
if ( !dir.isDirectory() ) {
return new BaseState( false, AppInfo.NOT_DIRECTORY );
}
Collection<File> list = FileUtils.listFiles( dir, this.allowFiles, true );
if ( index < 0 || index > list.size() ) {
state = new MultiState( true );
} else {
Object[] fileList = Arrays.copyOfRange( list.toArray(), index, index + this.count );
state = this.getState(request, fileList );
}
state.putInfo( "start", index );
state.putInfo( "total", list.size() );
return state;
}
private State getState (HttpServletRequest request, Object[] files ) {
MultiState state = new MultiState( true );
BaseState fileState = null;
File file = null;
for ( Object obj : files ) {
if ( obj == null ) {
break;
}
file = (File)obj;
fileState = new BaseState( true );
//fileState.putInfo( "url", PathFormat.format( this.getPath( file ) ) );
// ThinkGem 将绝对路径转换为虚拟路径
String url = PathFormat.format( this.getPath( file ) );
int index = url.indexOf(USERFILES_BASE_URL);
if(index > 0) {
url = url.substring(index + USERFILES_BASE_URL.length());
}
fileState.putInfo( "url", request.getContextPath() + USERFILES_BASE_URL + url );
state.addState( fileState );
}
return state;
}
private String getPath ( File file ) {
String path = file.getAbsolutePath();
return path.replace( this.rootPath, "/" );
}
private String[] getAllowFiles ( Object fileExt ) {
String[] exts = null;
String ext = null;
if ( fileExt == null ) {
return new String[ 0 ];
}
exts = (String[])fileExt;
for ( int i = 0, len = exts.length; i < len; i++ ) {
ext = exts[ i ];
exts[ i ] = ext.replace( ".", "" );
}
return exts;
}
}

View File

@@ -0,0 +1,145 @@
package com.jeesite.common.ueditor.hunter;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.jeesite.common.ueditor.PathFormat;
import com.jeesite.common.ueditor.define.AppInfo;
import com.jeesite.common.ueditor.define.BaseState;
import com.jeesite.common.ueditor.define.MIMEType;
import com.jeesite.common.ueditor.define.MultiState;
import com.jeesite.common.ueditor.define.State;
import com.jeesite.common.ueditor.upload.StorageManager;
/**
* 图片抓取器
* @author hancong03@baidu.com
*/
public class ImageHunter {
private HttpServletRequest request = null;
private String filename = null;
private String savePath = null;
private String rootPath = null;
private List<String> allowTypes = null;
private long maxSize = -1;
private List<String> filters = null;
public ImageHunter (HttpServletRequest request, Map<String, Object> conf ) {
this.request = request;
this.filename = (String)conf.get( "filename" );
this.savePath = (String)conf.get( "savePath" );
this.rootPath = (String)conf.get( "rootPath" );
this.maxSize = (Long)conf.get( "maxSize" );
this.allowTypes = Arrays.asList( (String[])conf.get( "allowFiles" ) );
this.filters = Arrays.asList( (String[])conf.get( "filter" ) );
}
public State capture ( String[] list ) {
MultiState state = new MultiState( true );
for ( String source : list ) {
state.addState( captureRemoteData( source ) );
}
return state;
}
public State captureRemoteData ( String urlStr ) {
HttpURLConnection connection = null;
URL url = null;
String suffix = null;
try {
url = new URL( urlStr );
if ( !validHost( url.getHost() ) ) {
return new BaseState( false, AppInfo.PREVENT_HOST );
}
connection = (HttpURLConnection) url.openConnection();
connection.setInstanceFollowRedirects( true );
connection.setUseCaches( true );
if ( !validContentState( connection.getResponseCode() ) ) {
return new BaseState( false, AppInfo.CONNECTION_ERROR );
}
suffix = MIMEType.getSuffix( connection.getContentType() );
if ( !validFileType( suffix ) ) {
return new BaseState( false, AppInfo.NOT_ALLOW_FILE_TYPE );
}
if ( !validFileSize( connection.getContentLength() ) ) {
return new BaseState( false, AppInfo.MAX_SIZE );
}
String savePath = this.getPath( this.savePath, this.filename, suffix );
String physicalPath = this.rootPath + savePath;
State state = StorageManager.saveFileByInputStream( connection.getInputStream(), physicalPath );
if ( state.isSuccess() ) {
state.putInfo( "url", request.getContextPath() + PathFormat.format( savePath ) );
state.putInfo( "source", urlStr );
}
return state;
} catch ( Exception e ) {
return new BaseState( false, AppInfo.REMOTE_FAIL );
}
}
private String getPath ( String savePath, String filename, String suffix ) {
return PathFormat.parse( savePath + suffix, filename );
}
private boolean validHost ( String hostname ) {
try {
InetAddress ip = InetAddress.getByName(hostname);
if (ip.isSiteLocalAddress()) {
return false;
}
} catch (UnknownHostException e) {
return false;
}
return !filters.contains( hostname );
}
private boolean validContentState ( int code ) {
return HttpURLConnection.HTTP_OK == code;
}
private boolean validFileType ( String type ) {
return this.allowTypes.contains( type );
}
private boolean validFileSize ( int size ) {
return size < this.maxSize;
}
}

View File

@@ -0,0 +1,55 @@
package com.jeesite.common.ueditor.upload;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.codec.binary.Base64;
import com.jeesite.common.ueditor.PathFormat;
import com.jeesite.common.ueditor.define.AppInfo;
import com.jeesite.common.ueditor.define.BaseState;
import com.jeesite.common.ueditor.define.FileType;
import com.jeesite.common.ueditor.define.State;
public final class Base64Uploader {
public static State save(HttpServletRequest request, String content, Map<String, Object> conf) {
byte[] data = decode(content);
long maxSize = ((Long) conf.get("maxSize")).longValue();
if (!validSize(data, maxSize)) {
return new BaseState(false, AppInfo.MAX_SIZE);
}
String suffix = FileType.getSuffix("JPG");
String savePath = PathFormat.parse((String) conf.get("savePath"),
(String) conf.get("filename"));
savePath = savePath + suffix;
String physicalPath = (String) conf.get("rootPath") + savePath;
State storageState = StorageManager.saveBinaryFile(data, physicalPath);
if (storageState.isSuccess()) {
String ctx = request.getContextPath(); // ThinkGem 修正上传图片后返回无contextpath问题
storageState.putInfo("url", ctx + PathFormat.format(savePath));
storageState.putInfo("type", suffix);
storageState.putInfo("original", "");
}
return storageState;
}
private static byte[] decode(String content) {
return Base64.decodeBase64(content);
}
private static boolean validSize(byte[] data, long length) {
return data.length <= length;
}
}

View File

@@ -0,0 +1,178 @@
package com.jeesite.common.ueditor.upload;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import com.jeesite.common.io.FileUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.media.VideoUtils;
import com.jeesite.common.ueditor.PathFormat;
import com.jeesite.common.ueditor.define.ActionMap;
import com.jeesite.common.ueditor.define.AppInfo;
import com.jeesite.common.ueditor.define.BaseState;
import com.jeesite.common.ueditor.define.FileType;
import com.jeesite.common.ueditor.define.State;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.Thumbnails.Builder;
public class BinaryUploader {
public static final State save(HttpServletRequest request,
Map<String, Object> conf) {
FileItemStream fileStream = null; // 原始上传
MultipartFile fileStream2 = null; // Spring MVC 上传
boolean isAjaxUpload = request.getHeader( "X_Requested_With" ) != null;
if (!ServletFileUpload.isMultipartContent(request)) {
return new BaseState(false, AppInfo.NOT_MULTIPART_CONTENT);
}
ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
if ( isAjaxUpload ) {
upload.setHeaderEncoding( "UTF-8" );
}
try {
FileItemIterator iterator = upload.getItemIterator(request);
while (iterator.hasNext()) {
fileStream = iterator.next();
if (!fileStream.isFormField()) {
break;
}
fileStream = null;
}
if (fileStream == null) {
// 原始上传无文件则检查是否是Spring MVC上传 ThinkGem
MultipartFile file = null;
if (request instanceof MultipartHttpServletRequest){
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
Iterator<String> it = multiRequest.getFileNames();
while (it.hasNext()) {
file = multiRequest.getFile(it.next());
break;
}
}
if (file != null && !file.isEmpty() && file.getOriginalFilename() != null) {
fileStream2 = file;
}
}
if (fileStream == null && fileStream2 == null) {
return new BaseState(false, AppInfo.NOTFOUND_UPLOAD_DATA);
}
String savePath = (String) conf.get("savePath");
String originFileName = fileStream != null ? fileStream.getName() : fileStream2.getOriginalFilename();
String suffix = FileType.getSuffixByFilename(originFileName);
originFileName = originFileName.substring(0,
originFileName.length() - suffix.length());
savePath = savePath + suffix;
long maxSize = ((Long) conf.get("maxSize")).longValue();
if (!validType(suffix, (String[]) conf.get("allowFiles"))) {
return new BaseState(false, AppInfo.NOT_ALLOW_FILE_TYPE);
}
savePath = PathFormat.parse(savePath, originFileName);
String physicalPath = FileUtils.path((String) conf.get("rootPath") + savePath);
InputStream is = fileStream != null ? fileStream.openStream() : fileStream2.getInputStream();
State storageState = StorageManager.saveFileByInputStream(is, physicalPath, maxSize);
is.close();
if (storageState.isSuccess()) {
int actionCode = ((Integer) conf.get("actionCode")).intValue();
String ctx = request.getContextPath(); // ThinkGem 修正上传图片后返回无contextpath问题
// 上传图片后,进行图片压缩
if (actionCode == ActionMap.UPLOAD_IMAGE){
// 如果开启了压缩图片
if ((Boolean)conf.get("imageCompressEnable")){
Integer width = (Integer)conf.get("imageCompressBorder");
// 过滤掉gif图片因为gif图片转换后会出现黑色背景的情况gif基本也没有比较大的图片
if (StringUtils.inString(FileUtils.getFileExtension(physicalPath),
"png","jpg","jpeg","bmp","ico")){
Builder<File> file = Thumbnails.of(physicalPath);
BufferedImage bufferedImage = ImageIO.read(new File(physicalPath));
if (bufferedImage != null){
if (bufferedImage.getWidth() <= width){
file.width(bufferedImage.getWidth());
}else{
file.width(width);
}
file.toFile(physicalPath);
}
}
}
}
// 上传成功后 转换格式 按照新的视频格式 返回前台 ThinkGem
else if(actionCode == ActionMap.UPLOAD_VIDEO){
final VideoUtils v = new VideoUtils(physicalPath);
// 先截图
if (v.cutPic()){
// 开启进程,在转换视频文件
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
v.convert();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
storageState.putInfo("url", ctx + PathFormat.format(savePath) + "." + v.getOutputFileExtension());
storageState.putInfo("type", "." + v.getOutputFileExtension());
storageState.putInfo("original", originFileName +"."+ v.getInputFileExtension());
return storageState;
}
}
storageState.putInfo("url", ctx + PathFormat.format(savePath));
storageState.putInfo("type", suffix);
storageState.putInfo("original", originFileName + suffix);
}
return storageState;
} catch (FileUploadException e) {
return new BaseState(false, AppInfo.PARSE_REQUEST_ERROR);
} catch (IOException e) {
return new BaseState(false, AppInfo.IO_ERROR);
}
}
private static boolean validType(String type, String[] allowTypes) {
List<String> list = Arrays.asList(allowTypes);
return list.contains(type);
}
}

View File

@@ -0,0 +1,213 @@
package com.jeesite.common.ueditor.upload;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import com.jeesite.common.idgen.IdGenerate;
import com.jeesite.common.io.FileUtils;
import com.jeesite.common.io.PropertiesUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.ueditor.define.AppInfo;
import com.jeesite.common.ueditor.define.BaseState;
import com.jeesite.common.ueditor.define.State;
public class StorageManager {
public static final int BUFFER_SIZE = 8192;
public StorageManager() {
}
public static State saveBinaryFile(byte[] data, String path) {
File file = new File(path);
State state = valid(file);
if (!state.isSuccess()) {
return state;
}
BufferedOutputStream bos = null;
try {
bos = new BufferedOutputStream(new FileOutputStream(file));
bos.write(data);
} catch (IOException ioe) {
return new BaseState(false, AppInfo.IO_ERROR);
}finally {
if (bos != null){
try {
bos.flush();
bos.close();
} catch (IOException e) {
;
}
}
}
// 验证允许的上传的文件类型(如果没有设置则不验证,默认不设置)
String allowContentTypes = PropertiesUtils.getInstance()
.getProperty("file.allowContentTypes");
if(StringUtils.isNotBlank(allowContentTypes)){
String rct = FileUtils.getRealContentType(file);
if (!StringUtils.inString(rct, allowContentTypes.split(","))){
file.delete();
return new BaseState(false, AppInfo.NOT_ALLOW_FILE_TYPE);
}
}
state = new BaseState(true, file.getAbsolutePath());
state.putInfo( "size", data.length );
state.putInfo( "title", file.getName() );
return state;
}
public static State saveFileByInputStream(InputStream is, String path, long maxSize) {
State state = null;
File tmpFile = getTmpFile();
byte[] dataBuf = new byte[ 2048 ];
BufferedInputStream bis = new BufferedInputStream(is, StorageManager.BUFFER_SIZE);
BufferedOutputStream bos = null;
try {
try{
bos = new BufferedOutputStream(
new FileOutputStream(tmpFile), StorageManager.BUFFER_SIZE);
int count = 0;
while ((count = bis.read(dataBuf)) != -1) {
bos.write(dataBuf, 0, count);
}
}finally {
if (bos != null){
bos.flush();
bos.close();
}
}
if (tmpFile.length() > maxSize) {
tmpFile.delete();
return new BaseState(false, AppInfo.MAX_SIZE);
}
// 验证允许的上传的文件类型(如果没有设置则不验证,默认不设置)
String allowContentTypes = PropertiesUtils.getInstance()
.getProperty("file.allowContentTypes");
if(StringUtils.isNotBlank(allowContentTypes)){
String rct = FileUtils.getRealContentType(tmpFile);
if (!StringUtils.inString(rct, allowContentTypes.split(","))){
tmpFile.delete();
return new BaseState(false, AppInfo.NOT_ALLOW_FILE_TYPE);
}
}
state = saveTmpFile(tmpFile, path);
if (!state.isSuccess()) {
tmpFile.delete();
}
return state;
} catch (IOException e) {
;
}finally {
if (bis != null){
try {
bis.close();
} catch (IOException e) {
;
}
}
}
return new BaseState(false, AppInfo.IO_ERROR);
}
public static State saveFileByInputStream(InputStream is, String path) {
State state = null;
File tmpFile = getTmpFile();
byte[] dataBuf = new byte[ 2048 ];
BufferedInputStream bis = new BufferedInputStream(is, StorageManager.BUFFER_SIZE);
try {
BufferedOutputStream bos = null;
try{
bos = new BufferedOutputStream(new FileOutputStream(tmpFile),
StorageManager.BUFFER_SIZE);
int count = 0;
while ((count = bis.read(dataBuf)) != -1) {
bos.write(dataBuf, 0, count);
}
}finally {
if (bos != null){
bos.flush();
bos.close();
}
}
state = saveTmpFile(tmpFile, path);
if (!state.isSuccess()) {
tmpFile.delete();
}
return state;
} catch (IOException e) {
;
}finally {
if (bis != null){
try {
bis.close();
} catch (IOException e) {
;
}
}
}
return new BaseState(false, AppInfo.IO_ERROR);
}
private static File getTmpFile() {
// File tmpDir = FileUtils.getTempDirectory();
File tmpDir = new File(System.getProperty("java.io.tmpdir"));
// String tmpFileName = (Math.random() * 10000 + "").replace(".", "");
// return new File(tmpDir, tmpFileName);
return new File(tmpDir, IdGenerate.randomBase62(10));
}
private static State saveTmpFile(File tmpFile, String path) {
State state = null;
File targetFile = new File(path);
if (targetFile.canWrite()) {
return new BaseState(false, AppInfo.PERMISSION_DENIED);
}
try {
FileUtils.moveFile(tmpFile, targetFile);
} catch (IOException e) {
return new BaseState(false, AppInfo.IO_ERROR);
}
state = new BaseState(true);
state.putInfo( "size", targetFile.length() );
state.putInfo( "title", targetFile.getName() );
return state;
}
private static State valid(File file) {
File parentPath = file.getParentFile();
if ((!parentPath.exists()) && (!parentPath.mkdirs())) {
return new BaseState(false, AppInfo.FAILED_CREATE_FILE);
}
if (!parentPath.canWrite()) {
return new BaseState(false, AppInfo.PERMISSION_DENIED);
}
return new BaseState(true);
}
}

View File

@@ -0,0 +1,32 @@
package com.jeesite.common.ueditor.upload;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.jeesite.common.ueditor.define.State;
public class Uploader {
private HttpServletRequest request = null;
private Map<String, Object> conf = null;
public Uploader(HttpServletRequest request, Map<String, Object> conf) {
this.request = request;
this.conf = conf;
}
public final State doExec() {
String filedName = (String) this.conf.get("fieldName");
State state = null;
if ("true".equals(this.conf.get("isBase64"))) {
state = Base64Uploader.save(this.request, this.request.getParameter(filedName),
this.conf);
} else {
state = BinaryUploader.save(this.request, this.conf);
}
return state;
}
}

View File

@@ -3,6 +3,7 @@
*/
package com.jeesite.common.utils.excel;
import java.io.Closeable;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -13,8 +14,10 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletResponse;
@@ -36,6 +39,7 @@ import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.collect.SetUtils;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.reflect.ReflectUtils;
@@ -47,9 +51,9 @@ import com.jeesite.common.utils.excel.annotation.ExcelFields;
/**
* 导出Excel文件导出“XLSX”格式支持大数据量导出 @see org.apache.poi.ss.SpreadsheetVersion
* @author ThinkGem
* @version 2013-04-21
* @version 2018-08-11
*/
public class ExcelExport {
public class ExcelExport implements Closeable{
private static Logger log = LoggerFactory.getLogger(ExcelExport.class);
@@ -76,7 +80,12 @@ public class ExcelExport {
/**
* 注解列表Object[]{ ExcelField, Field/Method }
*/
List<Object[]> annotationList;
private List<Object[]> annotationList;
/**
* 用于清理缓存
*/
private Set<Class<?>> fieldTypes = SetUtils.newHashSet();
/**
* 构造函数
@@ -431,6 +440,7 @@ public class ExcelExport {
if(val == null){
cell.setCellValue("");
}else if(fieldType != Class.class){
fieldTypes.add(fieldType); // 先存起来,方便完成后清理缓存
cell.setCellValue((String)fieldType.getMethod("setValue", Object.class).invoke(null, val));
try{
defaultDataFormat = (String)fieldType.getMethod("getDataFormat").invoke(null);
@@ -456,8 +466,11 @@ public class ExcelExport {
cell.setCellValue((Date) val);
defaultDataFormat = "yyyy-MM-dd HH:mm";
}else {
cell.setCellValue((String)Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
"fieldtype."+val.getClass().getSimpleName()+"Type")).getMethod("setValue", Object.class).invoke(null, val));
// 如果没有指定 fieldType切自行根据类型查找相应的转换类com.jeesite.common.utils.excel.fieldtype.值的类名+Type
Class<?> fieldType2 = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
"fieldtype."+val.getClass().getSimpleName()+"Type"));
fieldTypes.add(fieldType2); // 先存起来,方便完成后清理缓存
cell.setCellValue((String)fieldType2.getMethod("setValue", Object.class).invoke(null, val));
}
}
// if (val != null){
@@ -574,12 +587,31 @@ public class ExcelExport {
/**
* 清理临时文件
* @deprecated see close()
*/
public ExcelExport dispose(){
try {
this.close();
} catch (Exception e) {
e.printStackTrace();
}
return this;
}
@Override
public void close() {
if (wb instanceof SXSSFWorkbook){
((SXSSFWorkbook)wb).dispose();
}
return this;
Iterator<Class<?>> it = fieldTypes.iterator();
while(it.hasNext()){
Class<?> clazz = it.next();
try {
clazz.getMethod("clearCache").invoke(null);
} catch (Exception e) {
// 报错忽略,有可能没实现此方法
}
}
}
// /**

View File

@@ -3,6 +3,7 @@
*/
package com.jeesite.common.utils.excel;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -15,6 +16,7 @@ import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
@@ -34,6 +36,7 @@ import org.springframework.web.multipart.MultipartFile;
import com.jeesite.common.callback.MethodCallback;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.collect.SetUtils;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.lang.StringUtils;
@@ -45,9 +48,9 @@ import com.jeesite.common.utils.excel.annotation.ExcelFields;
/**
* 导入Excel文件支持“XLS”和“XLSX”格式
* @author ThinkGem
* @version 2014-8-19
* @version 2018-08-11
*/
public class ExcelImport {
public class ExcelImport implements Closeable {
private static Logger log = LoggerFactory.getLogger(ExcelImport.class);
@@ -66,6 +69,11 @@ public class ExcelImport {
*/
private int headerNum;
/**
* 用于清理缓存
*/
private Set<Class<?>> fieldTypes = SetUtils.newHashSet();
/**
* 构造函数
* @param path 导入文件对象,读取第一个工作表
@@ -418,6 +426,7 @@ public class ExcelImport {
try {
if (StringUtils.isNotBlank(ef.attrName())){
if (ef.fieldType() != Class.class){
fieldTypes.add(ef.fieldType()); // 先存起来,方便完成后清理缓存
val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val);
}
}else{
@@ -445,10 +454,14 @@ public class ExcelImport {
}
}else{
if (ef.fieldType() != Class.class){
fieldTypes.add(ef.fieldType()); // 先存起来,方便完成后清理缓存
val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val.toString());
}else{
val = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
"fieldtype."+valType.getSimpleName()+"Type")).getMethod("getValue", String.class).invoke(null, val.toString());
// 如果没有指定 fieldType切自行根据类型查找相应的转换类com.jeesite.common.utils.excel.fieldtype.值的类名+Type
Class<?> fieldType2 = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
"fieldtype."+valType.getSimpleName()+"Type"));
fieldTypes.add(fieldType2); // 先存起来,方便完成后清理缓存
val = fieldType2.getMethod("getValue", String.class).invoke(null, val.toString());
}
}
}
@@ -481,6 +494,19 @@ public class ExcelImport {
}
return dataList;
}
@Override
public void close() {
Iterator<Class<?>> it = fieldTypes.iterator();
while(it.hasNext()){
Class<?> clazz = it.next();
try {
clazz.getMethod("clearCache").invoke(null);
} catch (Exception e) {
// 报错忽略,有可能没实现此方法
}
}
}
// /**
// * 导入测试

View File

@@ -37,4 +37,11 @@ public class MoneyType {
return "0.00";
}
/**
* 清理缓存
*/
public static void clearCache(){
}
}

View File

@@ -78,6 +78,21 @@ public class ServletUtils {
return response;
}
/**
* 支持AJAX的页面跳转
*/
public static void redirectUrl(HttpServletRequest request, HttpServletResponse response, String url){
try {
if (ServletUtils.isAjaxRequest(request)){
request.getRequestDispatcher(url).forward(request, response); // AJAX不支持Redirect改用Forward
}else{
response.sendRedirect(request.getContextPath() + url);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 是否是Ajax异步请求
* @param request
@@ -173,9 +188,10 @@ public class ServletUtils {
resultMap.put("data", data);
}
}
HttpServletRequest request = ServletUtils.getRequest();
HttpServletRequest request = getRequest();
String uri = request.getRequestURI();
if (StringUtils.endsWithIgnoreCase(uri, ".xml")){
if (StringUtils.endsWithIgnoreCase(uri, ".xml") || StringUtils
.equalsIgnoreCase(request.getParameter("__ajax"), "xml")){
return XmlMapper.toXml(resultMap);
}else{
String functionName = request.getParameter("__callback");
@@ -202,7 +218,7 @@ public class ServletUtils {
/**
* 直接将结果JSON字符串渲染到客户端支持JsonP请求参数加__callback=回调函数名)
* @param response 渲染对象:{result:'true',message:'',data:{}}
* @param result Global.TRUE or Globle.False
* @param result 结果标识:Global.TRUE or Globle.False
* @param message 执行消息
* @param data 消息数据
* @return null
@@ -212,16 +228,18 @@ public class ServletUtils {
}
/**
* 将对象转换为JSON字符串渲染到客户端支持JsonP请求参数加__callback=回调函数名)
* 将对象转换为JSON、XML、JSONP字符串渲染到客户端JsonP请求参数加__callback=回调函数名)
* @param request 请求对象用来得到输出格式的指令JSON、XML、JSONP
* @param response 渲染对象
* @param object 待转换JSON并渲染的对象
* @return null
*/
public static String renderObject(HttpServletResponse response, Object object) {
HttpServletRequest request = ServletUtils.getRequest();
HttpServletRequest request = getRequest();
String uri = request.getRequestURI();
if (StringUtils.endsWithIgnoreCase(uri, ".xml")){
return XmlMapper.toXml(object);
if (StringUtils.endsWithIgnoreCase(uri, ".xml") || StringUtils
.equalsIgnoreCase(request.getParameter("__ajax"), "xml")){
return renderString(response, XmlMapper.toXml(object));
}else{
String functionName = request.getParameter("__callback");
if (StringUtils.isNotBlank(functionName)){
@@ -250,8 +268,18 @@ public class ServletUtils {
*/
public static String renderString(HttpServletResponse response, String string, String type) {
try {
// response.reset(); // 注释掉否则以前设置的Header会被清理掉如ajax登录设置记住我Cookie
response.setContentType(type == null ? "application/json" : type);
// response.reset(); // 注释掉否则以前设置的Header会被清理掉如ajax登录设置记住我Cookie信息
if (type == null){
if ((StringUtils.startsWith(string, "{") && StringUtils.endsWith(string, "}"))
|| (StringUtils.startsWith(string, "[") && StringUtils.endsWith(string, "]"))){
type = "application/json";
}else if (StringUtils.startsWith(string, "<") && StringUtils.endsWith(string, ">")){
type = "application/xml";
}else{
type = "text/html";
}
}
response.setContentType(type);
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
} catch (IOException e) {

View File

@@ -11,8 +11,8 @@
</page_setting>
<category_index>0</category_index>
<zoom>1.0</zoom>
<x>54</x>
<y>1963</y>
<x>1503</x>
<y>1793</y>
<default_color>
<r>128</r>
<g>128</g>
@@ -13933,7 +13933,7 @@
<default_value></default_value>
<auto_increment>false</auto_increment>
<foreign_key>false</foreign_key>
<not_null>true</not_null>
<not_null>false</not_null>
<primary_key>false</primary_key>
<unique_key>false</unique_key>
<character_set></character_set>

View File

@@ -175,7 +175,7 @@ CREATE TABLE [js_sys_config]
[id] varchar(64) NOT NULL,
[config_name] nvarchar(100) NOT NULL,
[config_key] varchar(100) NOT NULL,
[config_value] nvarchar(1000) NOT NULL,
[config_value] nvarchar(1000),
[is_sys] char(1) NOT NULL,
[create_by] varchar(64) NOT NULL,
[create_date] datetime NOT NULL,

View File

@@ -176,7 +176,7 @@ CREATE TABLE js_sys_config
id varchar(64) NOT NULL COMMENT '编号',
config_name varchar(100) NOT NULL COMMENT '名称',
config_key varchar(100) NOT NULL COMMENT '参数键',
config_value varchar(1000) NOT NULL COMMENT '参数值',
config_value varchar(1000) COMMENT '参数值',
is_sys char(1) NOT NULL COMMENT '系统内置1是 0否',
create_by varchar(64) NOT NULL COMMENT '创建者',
create_date datetime NOT NULL COMMENT '创建时间',

View File

@@ -175,7 +175,7 @@ CREATE TABLE js_sys_config
id varchar2(64) NOT NULL,
config_name nvarchar2(100) NOT NULL,
config_key varchar2(100) NOT NULL,
config_value nvarchar2(1000) NOT NULL,
config_value nvarchar2(1000),
is_sys char(1) NOT NULL,
create_by varchar2(64) NOT NULL,
create_date timestamp NOT NULL,

View File

@@ -175,7 +175,7 @@ CREATE TABLE js_sys_config
id varchar(64) NOT NULL,
config_name varchar(100) NOT NULL,
config_key varchar(100) NOT NULL,
config_value varchar(1000) NOT NULL,
config_value varchar(1000),
is_sys char(1) NOT NULL,
create_by varchar(64) NOT NULL,
create_date timestamp NOT NULL,

View File

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

View File

@@ -23,6 +23,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jeesite.common.codec.DesUtils;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.config.Global;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.lang.StringUtils;
@@ -31,6 +32,7 @@ import com.jeesite.common.shiro.authc.FormToken;
import com.jeesite.common.shiro.realm.BaseAuthorizingRealm;
import com.jeesite.common.shiro.realm.LoginInfo;
import com.jeesite.common.web.http.ServletUtils;
import com.jeesite.modules.sys.utils.UserUtils;
/**
* 表单验证(包含验证码)过滤类
@@ -93,7 +95,7 @@ public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.
}
// 登录成功后,判断是否需要记住用户名
if (WebUtils.isTrue(request, DEFAULT_REMEMBER_USERCODE_PARAM)) {
rememberUserCodeCookie.setValue(username);
rememberUserCodeCookie.setValue(EncodeUtils.xssFilter(username));
rememberUserCodeCookie.saveTo((HttpServletRequest)request, (HttpServletResponse)response);
} else {
rememberUserCodeCookie.removeFrom((HttpServletRequest)request, (HttpServletResponse)response);
@@ -157,6 +159,9 @@ public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.
return captcha;
}
/**
* 跳转登录页时,跳转到默认首页
*/
@Override
protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
PermissionsAuthorizationFilter.redirectToDefaultPath(request, response);
@@ -208,6 +213,18 @@ public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.
boolean isLogin = WebUtils.isTrue(request, "__login");
return super.isLoginSubmission(request, response) || isLogin;
}
/**
* 执行登录方法
*/
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
// 是否在登录后生成新的Session默认false
if (Global.getPropertyToBoolean("shiro.isGenerateNewSessionAfterLogin", "false")){
UserUtils.getSubject().logout();
}
return super.executeLogin(request, response);
}
/**
* 登录成功调用事件

View File

@@ -39,17 +39,19 @@ public class LogoutFilter extends org.apache.shiro.web.filter.authc.LogoutFilter
String redirectUrl = getRedirectUrl(request, response, subject);
//try/catch added for SHIRO-298:
try {
// 记录用户退出日志(@Deprecated v4.0.5支持setAuthorizingRealm之后版本可删除此if子句
if (authorizingRealm == null){
LogUtils.saveLog(UserUtils.getUser(), ServletUtils.getRequest(),
"系统退出", Log.TYPE_LOGIN_LOGOUT);
Object principal = subject.getPrincipal();
if (principal != null){
// 记录用户退出日志(@Deprecated v4.0.5支持setAuthorizingRealm之后版本可删除此if子句
if (authorizingRealm == null){
LogUtils.saveLog(UserUtils.getUser(), ServletUtils.getRequest(),
"系统退出", Log.TYPE_LOGIN_LOGOUT);
}
// 退出成功之前初始化授权信息并处理登录后的操作
else{
authorizingRealm.onLogoutSuccess((LoginInfo)subject.getPrincipal(),
(HttpServletRequest)request);
}
}
// 退出成功之前初始化授权信息并处理登录后的操作
else{
authorizingRealm.onLogoutSuccess((LoginInfo)subject.getPrincipal(),
(HttpServletRequest)request);
}
// 退出登录
subject.logout();
} catch (SessionException ise) {

View File

@@ -46,7 +46,6 @@ public class CasAuthorizingRealm extends BaseAuthorizingRealm {
private UserService userService;
private EmpUserService empUserService;
///////////// CAS /////////////
private CasOutHandler casOutHandler;
private String casServerUrl; // CAS 服务器地址
private String casServerCallbackUrl; // CAS 服务器回调地址
@@ -56,10 +55,7 @@ public class CasAuthorizingRealm extends BaseAuthorizingRealm {
super();
this.setAuthenticationTokenClass(CasToken.class);
}
/*
* 获取登录令牌
*/
@Override
protected FormToken getFormToken(AuthenticationToken authcToken) {
@@ -105,9 +101,6 @@ public class CasAuthorizingRealm extends BaseAuthorizingRealm {
return token;
}
/*
* 获取用户信息
*/
@Override
protected User getUserInfo(FormToken token) {
@@ -117,7 +110,7 @@ public class CasAuthorizingRealm extends BaseAuthorizingRealm {
// 如果允许客户端创建账号,则创建账号
if (ObjectUtils.toBoolean(attrs.get("isAllowClientCreateUser"))){
// 获取CAS传递过来的用户属性信息
user = new User(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("userCode"))));
user.setLoginCode(EncodeUtils.decodeUrl(ObjectUtils.toString(attrs.get("loginCode"))));
@@ -178,9 +171,6 @@ public class CasAuthorizingRealm extends BaseAuthorizingRealm {
return user;
}
/*
* 认证密码匹配调用方法
*/
@Override
protected void assertCredentialsMatch(AuthenticationToken authcToken,
AuthenticationInfo info) throws AuthenticationException {

View File

@@ -5,6 +5,8 @@ package com.jeesite.common.utils.excel.fieldtype;
import java.util.List;
import org.springframework.core.NamedThreadLocal;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.modules.sys.entity.Area;
import com.jeesite.modules.sys.utils.AreaUtils;
@@ -12,12 +14,12 @@ import com.jeesite.modules.sys.utils.AreaUtils;
/**
* 字段类型转换
* @author ThinkGem
* @version 2013-03-10
* @version 2018-08-11
* @example fieldType = AreaType.class
*/
public class AreaType {
private static ThreadLocal<List<Area>> cache = new ThreadLocal<>();
private static ThreadLocal<List<Area>> cache = new NamedThreadLocal<>("AreaType");
/**
* 获取对象值(导入)
@@ -45,4 +47,12 @@ public class AreaType {
}
return "";
}
/**
* 清理缓存
*/
public static void clearCache(){
cache.remove();
}
}

View File

@@ -5,6 +5,8 @@ package com.jeesite.common.utils.excel.fieldtype;
import java.util.List;
import org.springframework.core.NamedThreadLocal;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.modules.sys.entity.Company;
import com.jeesite.modules.sys.utils.EmpUtils;
@@ -12,12 +14,12 @@ import com.jeesite.modules.sys.utils.EmpUtils;
/**
* 字段类型转换
* @author ThinkGem
* @version 2015-03-24
* @version 2018-08-11
* @example fieldType = CompanyType.class
*/
public class CompanyType {
private static ThreadLocal<List<Company>> cache = new ThreadLocal<>();
private static ThreadLocal<List<Company>> cache = new NamedThreadLocal<>("CompanyType");
/**
* 获取对象值(导入)
@@ -45,4 +47,11 @@ public class CompanyType {
}
return "";
}
/**
* 清理缓存
*/
public static void clearCache(){
cache.remove();
}
}

View File

@@ -5,6 +5,8 @@ package com.jeesite.common.utils.excel.fieldtype;
import java.util.List;
import org.springframework.core.NamedThreadLocal;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.modules.sys.entity.Office;
import com.jeesite.modules.sys.utils.EmpUtils;
@@ -12,12 +14,12 @@ import com.jeesite.modules.sys.utils.EmpUtils;
/**
* 字段类型转换
* @author ThinkGem
* @version 2013-03-10
* @version 2018-08-11
* @example fieldType = OfficeType.class
*/
public class OfficeType {
private static ThreadLocal<List<Office>> cache = new ThreadLocal<>();
private static ThreadLocal<List<Office>> cache = new NamedThreadLocal<>("OfficeType");
/**
* 获取对象值(导入)
@@ -45,4 +47,11 @@ public class OfficeType {
}
return "";
}
/**
* 清理缓存
*/
public static void clearCache(){
cache.remove();
}
}

View File

@@ -5,6 +5,8 @@ package com.jeesite.common.utils.excel.fieldtype;
import java.util.List;
import org.springframework.core.NamedThreadLocal;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.utils.SpringUtils;
@@ -14,13 +16,13 @@ import com.jeesite.modules.sys.service.PostService;
/**
* 字段类型转换
* @author ThinkGem
* @version 2015-03-24
* @version 2018-08-11
* @example fieldType = PostListType.class
*/
public class PostListType {
private static PostService postService = SpringUtils.getBean(PostService.class);
private static ThreadLocal<List<Post>> cache = new ThreadLocal<>();
private static ThreadLocal<List<Post>> cache = new NamedThreadLocal<>("PostListType");
/**
* 获取对象值(导入)
@@ -53,4 +55,11 @@ public class PostListType {
}
return "";
}
/**
* 清理缓存
*/
public static void clearCache(){
cache.remove();
}
}

View File

@@ -14,9 +14,12 @@ import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.annotation.Order;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.config.Global;
@@ -44,6 +47,20 @@ import com.jeesite.common.shiro.web.WebSecurityManager;
@Configuration
public class ShiroConfig {
/**
* Apache Shiro Filter
* @throws Exception
*/
@Bean
@Order(3000)
@ConditionalOnMissingBean(name="shiroFilterProxy")
public FilterRegistrationBean shiroFilterProxy(ShiroFilterFactoryBean shiroFilter) throws Exception {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter((Filter) shiroFilter.getInstance());
bean.addUrlPatterns("/*");
return bean;
}
/**
* CAS登录过滤器
*/
@@ -101,7 +118,7 @@ public class ShiroConfig {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager);
bean.setLoginUrl(Global.getProperty("shiro.loginUrl"));
bean.setSuccessUrl(Global.getProperty("shiro.successUrl"));
bean.setSuccessUrl(Global.getProperty("adminPath")+"/index");
Map<String, Filter> filters = bean.getFilters();
filters.put("cas", shiroCasFilter(casAuthorizingRealm));
filters.put("authc", shiroAuthcFilter(authorizingRealm));

View File

@@ -3,19 +3,16 @@
*/
package com.jeesite.modules.config.web;
import javax.servlet.Filter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.web.filter.CharacterEncodingFilter;
import com.jeesite.common.config.Global;
import com.jeesite.common.shiro.web.ShiroFilterFactoryBean;
import com.jeesite.common.web.PageCachingFilter;
/**
@@ -24,28 +21,15 @@ import com.jeesite.common.web.PageCachingFilter;
* @version 2017年11月30日
*/
@Configuration
public class FilterConfig {
/**
* Encoding Filter
*/
@Bean
@Order(1000)
public FilterRegistrationBean characterEncodingFilter() {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new CharacterEncodingFilter());
bean.addInitParameter("encoding", "UTF-8");
bean.addInitParameter("forceEncoding", "true");
bean.addUrlPatterns("/*");
return bean;
}
public class PageCacheConfig {
/**
* PageCache Filter, cache .html suffix.
*/
@Bean
@Order(2000)
@ConditionalOnProperty(name = "ehcache.pageCaching.enabled", havingValue = "true")
@ConditionalOnMissingBean(name="pageCachingFilter")
public FilterRegistrationBean pageCachingFilter(EhCacheManagerFactoryBean ehCacheManager) {
FilterRegistrationBean bean = new FilterRegistrationBean();
PageCachingFilter pageCachingFilter = new PageCachingFilter();
@@ -56,18 +40,5 @@ public class FilterConfig {
"ehcache.pageCaching.urlPatterns"), ","));
return bean;
}
/**
* Apache Shiro Filter
* @throws Exception
*/
@Bean
@Order(3000)
public FilterRegistrationBean shiroFilterProxy(ShiroFilterFactoryBean shiroFilter) throws Exception {
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter((Filter) shiroFilter.getInstance());
bean.addUrlPatterns("/*");
return bean;
}
}

View File

@@ -12,6 +12,7 @@ import org.springframework.core.NamedThreadLocal;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.jeesite.common.lang.ByteUtils;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.lang.TimeUtils;
import com.jeesite.common.service.BaseService;
@@ -21,12 +22,12 @@ import com.jeesite.modules.sys.utils.UserUtils;
/**
* 日志拦截器
* @author ThinkGem
* @version 2014-8-19
* @version 2018-08-11
*/
public class LogInterceptor extends BaseService implements HandlerInterceptor {
private static final ThreadLocal<Long> startTimeThreadLocal =
new NamedThreadLocal<Long>("ThreadLocal StartTime");
new NamedThreadLocal<Long>("LogInterceptor StartTime");
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
@@ -61,10 +62,10 @@ public class LogInterceptor extends BaseService implements HandlerInterceptor {
// 打印JVM信息。
if (logger.isDebugEnabled()){
logger.debug("计时结束: {} 用时: {} URI: {} 最大内存: {}m 已分配内存: {}m 已分配内存中的剩余空间: {}m 最大可用内存: {}m",
DateUtils.formatDate(endTime, "hh:mm:ss.SSS"), TimeUtils.formatDateAgo(executeTime),
request.getRequestURI(), Runtime.getRuntime().maxMemory()/1024/1024, Runtime.getRuntime().totalMemory()/1024/1024, Runtime.getRuntime().freeMemory()/1024/1024,
(Runtime.getRuntime().maxMemory()-Runtime.getRuntime().totalMemory()+Runtime.getRuntime().freeMemory())/1024/1024);
Runtime runtime = Runtime.getRuntime();
logger.debug("计时结束: {} 用时: {} URI: {} 总内存: {} 已用内存: {}",
DateUtils.formatDate(endTime, "hh:mm:ss.SSS"), TimeUtils.formatDateAgo(executeTime), request.getRequestURI(),
ByteUtils.formatByteSize(runtime.totalMemory()), ByteUtils.formatByteSize(runtime.totalMemory()-runtime.freeMemory()));
}
}

View File

@@ -116,8 +116,7 @@ public class EmpUserService extends CrudService<EmpUserDao, EmpUser> {
int successNum = 0; int failureNum = 0;
StringBuilder successMsg = new StringBuilder();
StringBuilder failureMsg = new StringBuilder();
try {
ExcelImport ei = new ExcelImport(file, 2, 0);
try(ExcelImport ei = new ExcelImport(file, 2, 0)){
List<EmpUser> list = ei.getDataList(EmpUser.class);
for (EmpUser user : list) {
try{

View File

@@ -3,14 +3,11 @@
*/
package com.jeesite.modules.sys.service;
import java.util.Date;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.jeesite.common.entity.Page;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.service.CrudService;
import com.jeesite.modules.sys.dao.LogDao;
import com.jeesite.modules.sys.entity.Log;
@@ -29,20 +26,17 @@ public class LogService extends CrudService<LogDao, Log> {
*/
@Override
public Page<Log> findPage(Page<Log> page, Log log) {
// 设置默认时间范围,默认当前月
if (log.getCreateDate_gte() == null){
log.setCreateDate_gte(DateUtils.setDays(new Date(), 1));
}
if (log.getCreateDate_lte() == null){
log.setCreateDate_lte(DateUtils.addDays(DateUtils.addMonths(log.getCreateDate_gte(), 1), -1));
}
// // 设置默认时间范围,默认当前月
// if (log.getCreateDate_gte() == null){
// log.setCreateDate_gte(DateUtils.setDays(new Date(), 1));
// }
// if (log.getCreateDate_lte() == null){
// log.setCreateDate_lte(DateUtils.addDays(DateUtils.addMonths(log.getCreateDate_gte(), 1), -1));
// }
// 普通用户看自己的,管理员看全部的。
if (!log.getCurrentUser().isAdmin()){
log.setCreateBy(log.getCurrentUser().getUserCode());
}
return super.findPage(page, log);
}

View File

@@ -8,6 +8,7 @@ import java.util.Map;
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;
@@ -34,6 +35,7 @@ import com.jeesite.modules.sys.utils.UserUtils;
*/
@Controller
@RequestMapping(value = "${adminPath}/sys/area")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class AreaController extends BaseController {
@Autowired

View File

@@ -11,6 +11,7 @@ import javax.servlet.http.HttpServletResponse;
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;
@@ -39,6 +40,7 @@ import com.jeesite.modules.sys.utils.UserUtils;
*/
@Controller
@RequestMapping(value = "${adminPath}/sys/company")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class CompanyController extends BaseController {
@Autowired

View File

@@ -3,13 +3,12 @@
*/
package com.jeesite.modules.sys.web;
import java.util.Date;
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.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -17,7 +16,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.jeesite.common.entity.Page;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.web.BaseController;
import com.jeesite.modules.sys.entity.Log;
import com.jeesite.modules.sys.service.LogService;
@@ -29,6 +27,7 @@ import com.jeesite.modules.sys.service.LogService;
*/
@Controller
@RequestMapping(value = "${adminPath}/sys/log")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class LogController extends BaseController {
@Autowired
@@ -48,13 +47,13 @@ public class LogController extends BaseController {
@RequiresPermissions("sys:log:view")
@RequestMapping(value = "list")
public String list(Log log, Model model) {
// 设置默认时间范围,默认当前月
if (log.getCreateDate_gte() == null){
log.setCreateDate_gte(DateUtils.setDays(new Date(), 1));
}
if (log.getCreateDate_lte() == null){
log.setCreateDate_lte(DateUtils.addDays(DateUtils.addMonths(log.getCreateDate_gte(), 1), -1));
}
// // 设置默认时间范围,默认当前月
// if (log.getCreateDate_gte() == null){
// log.setCreateDate_gte(DateUtils.setDays(new Date(), 1));
// }
// if (log.getCreateDate_lte() == null){
// log.setCreateDate_lte(DateUtils.addDays(DateUtils.addMonths(log.getCreateDate_gte(), 1), -1));
// }
model.addAttribute("log", log);
return "modules/sys/logList";
}

View File

@@ -24,7 +24,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.jeesite.common.config.Global;
import com.jeesite.common.lang.ObjectUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.shiro.filter.FormAuthenticationFilter;
import com.jeesite.common.shiro.realm.BaseAuthorizingRealm;
@@ -55,7 +54,8 @@ public class LoginController extends BaseController{
if (StringUtils.containsIgnoreCase(request.getRequestURI(), ";JSESSIONID=")){
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
return REDIRECT + adminPath + "/login" + queryString;
ServletUtils.redirectUrl(request, response, adminPath + "/login" + queryString);
return null;
}
LoginInfo loginInfo = UserUtils.getLoginInfo();
@@ -64,16 +64,8 @@ public class LoginController extends BaseController{
if(loginInfo != null){
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
String indexUrl = adminPath + "/index" + queryString;
if (ServletUtils.isAjaxRequest(request)){
try {
request.getRequestDispatcher(indexUrl).forward(request, response); // AJAX不支持Redirect改用Forward
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
return null;
}
return REDIRECT + indexUrl;
ServletUtils.redirectUrl(request, response, adminPath + "/index" + queryString);
return null;
}
// 如果是登录操作跳转到此则认为是登录失败支持GET登录时传递__login=true参数
@@ -87,7 +79,7 @@ public class LoginController extends BaseController{
}
// 是否显示验证码
model.addAttribute("isValidCodeLogin", ObjectUtils.toInteger(Global.getConfig("sys.login.failedNumAfterValidCode", "200")) == 0);
model.addAttribute("isValidCodeLogin", Global.getConfigToInteger("sys.login.failedNumAfterValidCode", "200") == 0);
//获取当前会话对象
Session session = UserUtils.getSession();
@@ -131,16 +123,8 @@ public class LoginController extends BaseController{
if(loginInfo != null){
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
String indexUrl = adminPath + "/index" + queryString;
if (ServletUtils.isAjaxRequest(request)){
try {
request.getRequestDispatcher(indexUrl).forward(request, response); // AJAX不支持Redirect改用Forward
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
return null;
}
return REDIRECT + indexUrl;
ServletUtils.redirectUrl(request, response, adminPath + "/index" + queryString);
return null;
}
String username = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_USERNAME_PARAM);
@@ -203,12 +187,16 @@ public class LoginController extends BaseController{
if (StringUtils.containsIgnoreCase(request.getRequestURI(), ";JSESSIONID=")){
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
return REDIRECT + adminPath + "/index" + queryString;
ServletUtils.redirectUrl(request, response, adminPath + "/index" + queryString);
return null;
}
// 验证下用户权限以便调用doGetAuthorizationInfo方法保存单点登录登出句柄
if (!SecurityUtils.getSubject().isPermitted("user")){
return REDIRECT + adminPath + "/login";
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
ServletUtils.redirectUrl(request, response, adminPath + "/login" + queryString);
return null;
}
//获取登录用户信息
@@ -217,46 +205,68 @@ public class LoginController extends BaseController{
// 未加载shiro模块时会为空直接访问则提示操作权限不足。
if(loginInfo == null){
UserUtils.getSubject().logout();
return REDIRECT + adminPath + "/login";
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
ServletUtils.redirectUrl(request, response, adminPath + "/login" + queryString);
return null;
}
// 当前用户对象信息
User user = UserUtils.get(loginInfo.getId());
if (user == null){
UserUtils.getSubject().logout();
return REDIRECT + adminPath + "/login";
String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString;
ServletUtils.redirectUrl(request, response, adminPath + "/login" + queryString);
return null;
}
model.addAttribute("user", user); // 设置当前用户信息
//获取当前会话对象
Session session = UserUtils.getSession();
// 设置共享SessionId的Cookie值第三方系统使用
String cookieName = Global.getProperty("session.shareSessionIdCookieName");
if (StringUtils.isNotBlank(cookieName)){
CookieUtils.setCookie((HttpServletResponse)response, cookieName, (String)session.getId());
}
// 如果是登录操作,则设置登录信息(移动端用)
model.addAttribute("result", Global.TRUE);
if (request.getParameter("username") != null && request.getParameter("password") != null){
// 是否是登录操作
boolean isLogin = "true".equals(session.getAttribute("__login"));
if (isLogin){
// 获取后接着清除,防止下次获取仍然认为是登录状态
session.removeAttribute("__login");
// 设置共享SessionId的Cookie值第三方系统使用
String cookieName = Global.getProperty("session.shareSessionIdCookieName");
if (StringUtils.isNotBlank(cookieName)){
CookieUtils.setCookie((HttpServletResponse)response, cookieName, (String)session.getId());
}
// 如果登录设置了语言,则切换语言
if (loginInfo.getParam("lang") != null){
Global.setLang(loginInfo.getParam("lang"), request, response);
}
model.addAttribute("message", text("sys.login.success"));
}else{
model.addAttribute("message", text("sys.login.getInfo"));
}
model.addAttribute("sessionid", (String)session.getId());
// 获取登录成功页面
String successUrl = Global.getProperty("shiro.successUrl");
if (!StringUtils.contains(successUrl, "://")){
successUrl = request.getContextPath() + successUrl;
}
// 登录操作如果是Ajax操作直接返回登录信息字符串。
if (ServletUtils.isAjaxRequest(request)){
model.addAttribute("result", Global.TRUE);
// 如果是登录,则返回登录成功信息,否则返回获取成功信息
if (isLogin){
model.addAttribute("message", text("sys.login.success"));
}else{
model.addAttribute("message", text("sys.login.getInfo"));
}
model.addAttribute("sessionid", (String)session.getId());
model.addAttribute("__url", successUrl); // 告诉浏览器登录后跳转的页面
return ServletUtils.renderObject(response, model);
}
// 如果是登录操作,则跳转到登录成功页
else if (isLogin){
return REDIRECT + successUrl;
}
// 是否允许刷新主页,如果已登录,再次访问主页,则退出原账号。
if (!ObjectUtils.toBoolean(Global.getConfig("shiro.isAllowRefreshIndex", "true"))){
if (!Global.getConfigToBoolean("shiro.isAllowRefreshIndex", "true")){
String logined = CookieUtils.getCookie(request, "LOGINED");
if (StringUtils.isBlank(logined) || "false".equals(logined)){
CookieUtils.setCookie(response, "LOGINED", "true");

View File

@@ -8,6 +8,7 @@ import java.util.Map;
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;
@@ -35,6 +36,7 @@ import com.jeesite.modules.sys.web.user.EmpUserController;
*/
@Controller
@RequestMapping(value = "${adminPath}/sys/office")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class OfficeController extends BaseController {
@Autowired

View File

@@ -17,6 +17,7 @@ import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
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.web.bind.annotation.RequestMapping;
@@ -24,6 +25,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.beust.jcommander.internal.Lists;
import com.beust.jcommander.internal.Maps;
import com.jeesite.common.cache.CacheUtils;
import com.jeesite.common.collect.MapUtils;
import com.jeesite.common.config.Global;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.lang.ObjectUtils;
@@ -41,6 +44,7 @@ import com.jeesite.modules.sys.utils.UserUtils;
*/
@Controller
@RequestMapping(value = "${adminPath}/sys/online")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class OnlineController extends BaseController{
@Autowired
@@ -143,6 +147,17 @@ public class OnlineController extends BaseController{
public String tickOut(String sessionId) {
Session session = sessionDAO.readSession(sessionId);
if (session != null){
@SuppressWarnings("unchecked")
Map<String, String> onlineTickOutMap = (Map<String, String>)CacheUtils.get("onlineTickOutMap");
if (onlineTickOutMap == null){
onlineTickOutMap = MapUtils.newConcurrentMap();
}
PrincipalCollection pc = (PrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
LoginInfo principal = (pc != null ? (LoginInfo)pc.getPrimaryPrincipal() : null);
if (principal != null){
onlineTickOutMap.put(principal.getId()+"_"+principal.getParam("deviceType", "PC"), StringUtils.EMPTY);
}
CacheUtils.put("onlineTickOutMap", onlineTickOutMap);
sessionDAO.delete(session);
return renderResult(Global.TRUE, "踢出已成功!");
}

View File

@@ -8,6 +8,7 @@ import javax.servlet.http.HttpServletResponse;
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;
@@ -29,6 +30,7 @@ import com.jeesite.modules.sys.service.PostService;
*/
@Controller
@RequestMapping(value = "${adminPath}/sys/post")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class PostController extends BaseController {
@Autowired

View File

@@ -9,6 +9,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
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.web.bind.annotation.PostMapping;
@@ -34,6 +35,7 @@ import com.jeesite.modules.sys.utils.ValidCodeUtils;
*/
@Controller
@RequestMapping(value = "/account")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class AccountController extends BaseController{
@Autowired

View File

@@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletResponse;
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;
@@ -35,6 +36,7 @@ import com.jeesite.modules.sys.utils.UserUtils;
*/
@Controller
@RequestMapping(value = "${adminPath}/sys/corpAdmin")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class CorpAdminController extends BaseController {
@Autowired

View File

@@ -13,6 +13,7 @@ import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.BeanUtils;
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;
@@ -22,12 +23,14 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.jeesite.common.codec.EncodeUtils;
import com.jeesite.common.collect.ListUtils;
import com.jeesite.common.collect.MapUtils;
import com.jeesite.common.config.Global;
import com.jeesite.common.entity.Page;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.lang.StringUtils;
import com.jeesite.common.mapper.JsonMapper;
import com.jeesite.common.utils.excel.ExcelExport;
import com.jeesite.common.utils.excel.annotation.ExcelField.Type;
import com.jeesite.common.web.BaseController;
@@ -52,6 +55,7 @@ import com.jeesite.modules.sys.utils.UserUtils;
*/
@Controller
@RequestMapping(value = "${adminPath}/sys/empUser")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class EmpUserController extends BaseController {
@Autowired
@@ -94,7 +98,8 @@ public class EmpUserController extends BaseController {
if (!(isAll != null && isAll)){
empUserService.addDataScopeFilter(empUser, UserDataScope.CTRL_PERMI_MANAGE);
}
Page<EmpUser> page = empUserService.findPage(new Page<EmpUser>(request, response), empUser);
empUser.setPage(new Page<EmpUser>(request, response));
Page<EmpUser> page = empUserService.findPage(empUser);
return page;
}
@@ -175,8 +180,9 @@ public class EmpUserController extends BaseController {
}
List<EmpUser> list = empUserService.findList(empUser);
String fileName = "用户数据" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
new ExcelExport("用户数据", EmpUser.class).setDataList(list)
.write(response, fileName).dispose();
try(ExcelExport ee = new ExcelExport("用户数据", EmpUser.class)){
ee.setDataList(list).write(response, fileName);
}
}
/**
@@ -194,8 +200,9 @@ public class EmpUserController extends BaseController {
}
List<EmpUser> list = ListUtils.newArrayList(empUser);
String fileName = "用户数据模板.xlsx";
new ExcelExport("用户数据", EmpUser.class, Type.IMPORT).setDataList(list)
.write(response, fileName).dispose();
try(ExcelExport ee = new ExcelExport("用户数据", EmpUser.class, Type.IMPORT)){
ee.setDataList(list).write(response, fileName);
}
}
/**
@@ -364,9 +371,9 @@ public class EmpUserController extends BaseController {
if (!(isAll != null && isAll)) {
empUserService.addDataScopeFilter(empUser);
}
List<User> list = userService.findList(empUser);
List<EmpUser> list = empUserService.findList(empUser);
for (int i = 0; i < list.size(); i++) {
User e = list.get(i);
EmpUser e = list.get(i);
Map<String, Object> map = MapUtils.newHashMap();
map.put("id", StringUtils.defaultIfBlank(idPrefix, "u_") + e.getId());
map.put("pId", StringUtils.defaultIfBlank(pId, "0"));
@@ -382,7 +389,10 @@ public class EmpUserController extends BaseController {
@RequiresPermissions("user")
@RequestMapping(value = "empUserSelect")
public String empUserSelect(EmpUser empUser, String selectData, String checkbox, Model model) {
model.addAttribute("selectData", selectData); // 指定默认选中的ID
String selectDataJson = EncodeUtils.decodeUrl(selectData);
if (JsonMapper.fromJson(selectDataJson, Map.class) != null){
model.addAttribute("selectData", selectDataJson);
}
model.addAttribute("checkbox", checkbox); // 是否显示复选框,支持多选
model.addAttribute("empUser", empUser); // ModelAttribute
return "modules/sys/user/empUserSelect";

View File

@@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletResponse;
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;
@@ -32,6 +33,7 @@ import com.jeesite.modules.sys.service.UserService;
*/
@Controller
@RequestMapping(value = "${adminPath}/sys/secAdmin")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class SecAdminController extends BaseController {
@Autowired

View File

@@ -25,6 +25,23 @@ jdbc:
# 最大连接数
maxActive: 20
# 获取连接等待超时时间单位毫秒4.0.6+
maxWait: 60000
# 从池中取出连接前进行检验如果检验失败则从池中去除连接并尝试取出另一个。4.0.6+
testOnBorrow: false
testOnReturn: false
# 间隔多久才进行一次检测检测需要关闭的空闲连接单位毫秒4.0.6+
timeBetweenEvictionRunsMillis: 60000
# 一个连接在池中最小生存的时间单位毫秒4.0.6+
minEvictableIdleTimeMillis: 300000
# 配置是否自动回收超时连接,超时时间,单位秒 4.0.6+
removeAbandoned: true
removeAbandonedTimeout: 1800
# # 多数据源名称列表,启用方式:@MyBatisDao(dataSourceName="ds2")
# dataSourceNames: ds2
#
@@ -73,7 +90,7 @@ redis:
pool:
maxIdle: 3
maxTotal: 20
# 是否启用Redis系统缓存及会话专业版
cacheAndSession: false
@@ -162,9 +179,19 @@ user:
registerUser:
enabled: false
userTypes: 0, 1
# 菜单管理
menu:
# 根据模块状态去更新相连的菜单状态仅作为微服务时设为false
updateStatusByModuleStatus: true
# 国际化管理(专业版+
lang:
enabled: true
# 任务调度(个人版+
job:
enabled: true
# 是否自动启动任务调度(可关闭)
autoStartup: true
@@ -177,12 +204,34 @@ job:
threadCount: 10
threadPriority: 5
# 调度设置集群中每一个实例都必须使用相同的instanceName名称 (区分特定的调度器实例)
# 每一个instanceId必须不同设置AUTO则自动生成
scheduler:
instanceName: JeeSiteScheduler
instanceId: AUTO
# 任务调度集群设置
jobStore:
isClustered: true
dataSourceName: job
clusterCheckinInterval: 1000
# 调度日志配置
log:
# 计划调度日志
scheduler:
enabled: true
# 是否只保存错误日志
errorLevel: true
# 任务执行日志
jobDetail:
enabled: true
# 是否只保存错误日志
errorLevel: true
# 计划触发日志
trigger:
enabled: false
# 内容管理
cms:
@@ -220,11 +269,19 @@ shiro:
# 是否加密单点登录安全Key
encryptKey: true
# 登录提交信息加密
# 登录提交信息加密(如果不需要加密,设置为空即可)
loginSubmit:
# 登录提交信息安全Key加密用户名、密码、验证码后再提交key设置为3个用逗号分隔
secretKey: thinkgem,jeesite,com
# 记住我密钥设置(设置为空则使用默认)
rememberMe:
# 密钥必须通过 com.jeesite.common.shiro.web.RememberMeManager 的main方法生成
secretKey: ~
# 指定获取客户端IP的Header名称防止IP伪造。指定为空则使用原生方法获取IP。
remoteAddrHeaderName: X-Forwarded-For
# 允许的请求方法设定,解决安全审计问题
allowRequestMethods: GET,POST
@@ -242,6 +299,9 @@ shiro:
# accessControlAllowOrigin: http://demo.jeesite.net
# accessControlAllowOrigin: '*'
# 是否在登录后生成新的Session默认false
isGenerateNewSessionAfterLogin: false
# URI 权限过滤器定义
filterChainDefinitions: |
/ReportServer/** = user
@@ -297,9 +357,12 @@ session:
# MyBatis 相关
mybatis:
# 扫描基础包设置Aliases、@MyBatisDao,如果多个,用“,”分隔
# @MyBatisDao、Aliases 扫描基础包,如果多个,用“,”分隔
scanBasePackage: com.jeesite.modules
# TypeHandlers 扫描基础包,如果多个,用“,”分隔
scanTypeHandlersPackage: ~
# Mapper文件刷新线程
mapper:
refresh:
@@ -347,6 +410,7 @@ web:
${adminPath}/login,
${adminPath}/desktop,
${adminPath}/sys/online/count,
${adminPath}/state/server/rtInfo,
${adminPath}/**/treeData,
${adminPath}/file/**,
${adminPath}/tags/*,
@@ -369,6 +433,10 @@ web:
validator:
id: '[a-zA-Z0-9_\-/\u4e00-\u9fa5]{0,64}'
user.loginCode: '[a-zA-Z0-9_\u4e00-\u9fa5]{4,20}'
# 关闭核心模块的Web功能仅作为微服务时设为false
core:
enabled: true
# 错误页面500.html是否输出错误信息正式环境为提供安全性可设置为false
error:
@@ -380,6 +448,7 @@ error:
#============================#
file:
enabled: true
# 文件上传根路径设置路径中不允许包含“userfiles”在指定目录中系统会自动创建userfiles目录如果不设置默认为contextPath路径
# baseDir: D:/jeesite

View File

@@ -0,0 +1,6 @@
UPDATE ${_prefix}sys_menu SET permission='sys:stste:cache' WHERE permission='sys:stste:ehcache';
UPDATE ${_prefix}sys_menu SET menu_href='/state/cache/index' WHERE menu_href='/state/ehcache';
UPDATE ${_prefix}sys_menu SET menu_href='/state/server/index' WHERE menu_href='/state/server';
commit;

View File

@@ -0,0 +1,6 @@
UPDATE ${_prefix}sys_menu SET permission='sys:stste:cache' WHERE permission='sys:stste:ehcache';
UPDATE ${_prefix}sys_menu SET menu_href='/state/cache/index' WHERE menu_href='/state/ehcache';
UPDATE ${_prefix}sys_menu SET menu_href='/state/server/index' WHERE menu_href='/state/server';
commit;

View File

@@ -0,0 +1,6 @@
UPDATE ${_prefix}sys_menu SET permission='sys:stste:cache' WHERE permission='sys:stste:ehcache';
UPDATE ${_prefix}sys_menu SET menu_href='/state/cache/index' WHERE menu_href='/state/ehcache';
UPDATE ${_prefix}sys_menu SET menu_href='/state/server/index' WHERE menu_href='/state/server';
commit;

View File

@@ -0,0 +1,6 @@
UPDATE ${_prefix}sys_menu SET permission='sys:stste:cache' WHERE permission='sys:stste:ehcache';
UPDATE ${_prefix}sys_menu SET menu_href='/state/cache/index' WHERE menu_href='/state/ehcache';
UPDATE ${_prefix}sys_menu SET menu_href='/state/server/index' WHERE menu_href='/state/server';
commit;

View File

@@ -3,4 +3,6 @@
4.0.2
4.0.3
4.0.4
4.0.5
4.0.5
4.0.6
4.0.7

View File

@@ -16,6 +16,7 @@ sys.login.accountDisabled=该帐号已停用。
sys.login.accountFreezed=该帐号已冻结。
sys.login.accountAudited=该帐号待审核。
sys.login.accountInvalid=该帐号无效。
sys.login.tickOutMessage=账号已被管理员移出在线,请重新登录。
sys.login.multiAddrMessage=账号已在其它地方登录,请重新登录。
sys.login.failedNumLock=登录失败,尝试次数过多,账号已锁定,请 {0} 分钟后重试.

View File

@@ -9,7 +9,7 @@
</style>
<link rel="stylesheet" href="../../themes/iframe.css" />
<script type="text/javascript" src="../internal.js"></script>
<script src="../../ueditor.parse.min.js"></script>
<script src="../../ueditor.parse.js"></script>
<title></title>
</head>
<body class="view">

View File

@@ -47,7 +47,7 @@ else {
href="http://jeesite.com">JeeSite ${@Global.getProperty('jeesiteVersion')}</a>
</div>
</div>
<% if (@ObjectUtils.toBoolean(@Global.getConfig('error.page.printErrorInfo', 'true'))){ %>
<% if (@Global.getConfigToBoolean('error.page.printErrorInfo', 'true')){ %>
<div class="box mt20">
${@StringUtils.toHtml(@ExceptionUtils.getStackTraceAsString(ex))}<br/>
此异常信息若不想输出可打开jeesite.yml文件设置error.page.printErrorInfo=false即可

View File

@@ -61,10 +61,10 @@
<label class="control-label">操作时间:</label>
<div class="control-inline">
<#form:input path="createDate_gte" readonly="readonly" maxlength="20" class="form-control Wdate-date"
dataFormat="date" onclick="WdatePicker({dateFmt:'yyyy-MM-dd',isShowClear:false,onpicked:function(){createDate_lte.click()}});"/>
dataFormat="date" onclick="WdatePicker({dateFmt:'yyyy-MM-dd',isShowClear:true,onpicked:function(){createDate_lte.click()}});"/>
&nbsp;--&nbsp;
<#form:input path="createDate_lte" readonly="readonly" maxlength="20" class="form-control Wdate-date"
dataFormat="date" onclick="WdatePicker({dateFmt:'yyyy-MM-dd',isShowClear:false});"/>
dataFormat="date" onclick="WdatePicker({dateFmt:'yyyy-MM-dd',isShowClear:true});"/>
</div>
</div>
<div class="form-group">

View File

@@ -10,11 +10,8 @@
<span class="info-box-text">CPU 使用率</span>
<span class="info-box-number">90<small>%</small></span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-red"><i class="fa fa-google-plus"></i></span>
@@ -22,11 +19,8 @@
<span class="info-box-text">关注数</span>
<span class="info-box-number">41,410</span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
<!-- fix for small devices only -->
<div class="clearfix visible-sm-block"></div>
@@ -38,11 +32,8 @@
<span class="info-box-text">因特网</span>
<span class="info-box-number">760</span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-yellow"><i class="fa fa-users"></i></span>
@@ -51,16 +42,13 @@
<span class="info-box-text">新用户</span>
<span class="info-box-number">2,000</span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
</div>
<!-- /.row -->
<!-- Chart boxes -->
<div class="row">
<div class="col-md-12">
<div class="box">
<div class="box box-widget">
<div class="box-header with-border">
<h3 class="box-title">月度报告</h3>
<div class="box-tools pull-right">
@@ -82,7 +70,6 @@
</button>
</div>
</div>
<!-- /.box-header -->
<div class="box-body">
<div class="row">
<div class="col-md-8">
@@ -157,9 +144,7 @@
myChart.setOption(option);
</script>
</div>
<!-- /.chart-responsive -->
</div>
<!-- /.col -->
<div class="col-md-4">
<p class="text-center">
<strong>完成目标</strong>
@@ -171,7 +156,6 @@
<div class="progress-bar progress-bar-aqua" style="width: 80%"></div>
</div>
</div>
<!-- /.progress-group -->
<div class="progress-group">
<span class="progress-text">完成购买率</span>
<span class="progress-number"><b>310</b>/400</span>
@@ -179,7 +163,6 @@
<div class="progress-bar progress-bar-red" style="width: 80%"></div>
</div>
</div>
<!-- /.progress-group -->
<div class="progress-group">
<span class="progress-text">产品访问量</span>
<span class="progress-number"><b>480</b>/800</span>
@@ -187,7 +170,6 @@
<div class="progress-bar progress-bar-green" style="width: 80%"></div>
</div>
</div>
<!-- /.progress-group -->
<div class="progress-group">
<span class="progress-text">查询访问量</span>
<span class="progress-number"><b>250</b>/500</span>
@@ -195,13 +177,9 @@
<div class="progress-bar progress-bar-yellow" style="width: 80%"></div>
</div>
</div>
<!-- /.progress-group -->
</div>
<!-- /.col -->
</div>
<!-- /.row -->
</div>
<!-- ./box-body -->
<div class="box-footer">
<div class="row">
<div class="col-sm-3 col-xs-6">
@@ -210,45 +188,33 @@
<h5 class="description-header">¥35,210.43</h5>
<span class="description-text">总营收</span>
</div>
<!-- /.description-block -->
</div>
<!-- /.col -->
<div class="col-sm-3 col-xs-6">
<div class="description-block border-right">
<span class="description-percentage text-yellow"><i class="fa fa-caret-left"></i> 0%</span>
<h5 class="description-header">¥10,390.90</h5>
<span class="description-text">总成本</span>
</div>
<!-- /.description-block -->
</div>
<!-- /.col -->
<div class="col-sm-3 col-xs-6">
<div class="description-block border-right">
<span class="description-percentage text-green"><i class="fa fa-caret-up"></i> 20%</span>
<h5 class="description-header">¥24,813.53</h5>
<span class="description-text">总利润</span>
</div>
<!-- /.description-block -->
</div>
<!-- /.col -->
<div class="col-sm-3 col-xs-6">
<div class="description-block">
<span class="description-percentage text-red"><i class="fa fa-caret-down"></i> 18%</span>
<h5 class="description-header">1200</h5>
<span class="description-text">目标完成</span>
</div>
<!-- /.description-block -->
</div>
</div>
<!-- /.row -->
</div>
<!-- /.box-footer -->
</div>
<!-- /.box -->
</div>
<!-- /.col -->
</div>
<!-- /.row -->
</div>
<footer class="main-footer m0">
<div class="pull-right hidden-xs">当前版本: ${@Global.getConfig('productVersion')}</div>

View File

@@ -15,7 +15,7 @@
<#form:hidden path="userCode"/>
<div class="box-body">
<div class="form-unit">基本信息</div>
<div class="row ${@ObjectUtils.toBoolean(@Global.getConfig('user.useCorpModel'))?'':'hide'}">
<div class="row ${@Global.getConfigToBoolean('user.useCorpModel', 'false')?'':'hide'}">
<div class="col-xs-6">
<div class="form-group">
<label class="col-sm-4 control-label" title="">

View File

@@ -8,7 +8,7 @@
<div class="box-tools pull-right">
<a href="#" class="btn btn-default" id="btnSearch" title="查询"><i class="fa fa-filter"></i> 查询</a>
<% if(hasPermi('sys:corpAdmin:edit')){ %>
<% if(@ObjectUtils.toBoolean(@Global.getConfig('user.useCorpModel'))){ %>
<% if(@Global.getConfigToBoolean('user.useCorpModel', 'false')){ %>
<a href="${ctx}/sys/corpAdmin/form?op=addCorp" class="btn btn-default btnTool" title="新增租户管理员"><i class="fa fa-plus"></i> 新增租户管理员</a>
<% }else{ %>
<a href="${ctx}/sys/corpAdmin/form?corpCode_=${user.currentUser.corpCode_}&corpName_=${user.currentUser.corpName_}&op=addAdmin" class="btn btn-default btnTool" title="新增管理员"><i class="fa fa-plus"></i> 新增管理员</a>
@@ -31,13 +31,13 @@
<#form:input path="userName" maxlength="100" class="form-control width-90"/>
</div>
</div>
<div class="form-group ${@ObjectUtils.toBoolean(@Global.getConfig('user.useCorpModel'))?'':'hide'}">
<div class="form-group ${@Global.getConfigToBoolean('user.useCorpModel', 'false')?'':'hide'}">
<label class="control-label">租户代码:</label>
<div class="control-inline">
<#form:input path="corpCode_" maxlength="100" class="form-control width-90"/>
</div>
</div>
<div class="form-group ${@ObjectUtils.toBoolean(@Global.getConfig('user.useCorpModel'))?'':'hide'}">
<div class="form-group ${@Global.getConfigToBoolean('user.useCorpModel', 'false')?'':'hide'}">
<label class="control-label">租户名称:</label>
<div class="control-inline">
<#form:input path="corpName_" maxlength="100" class="form-control width-90"/>
@@ -69,7 +69,7 @@ $('#dataGrid').dataGrid({
return '<a href="${ctx}/sys/corpAdmin/form?userCode='+row.userCode+'&op=edit" class="btnList" data-title="编辑用户">'+(val||row.id)+'</a>';
}},
{header:'用户昵称', name:'userName', index:'a.user_name', width:200, align:"center"},
<% if(@ObjectUtils.toBoolean(@Global.getConfig('user.useCorpModel'))){ %>
<% if(@Global.getConfigToBoolean('user.useCorpModel', 'false')){ %>
{header:'租户代码', name:'corpCode_', index:'a.corp_code', width:200, align:"center", formatter: function(val, obj, row, act){
return '<a href="javascript:" onclick="$(\'#corpCode_\').val(\''+val+'\');$(\'#searchForm\').submit()">'+val+'</a>';
}},
@@ -93,7 +93,7 @@ $('#dataGrid').dataGrid({
actions.push('<a href="${ctx}/sys/corpAdmin/enable?userCode='+row.userCode+'" class="btnList" title="启用用户" data-confirm="确认要启用该用户吗?"><i class="glyphicon glyphicon-ok-circle"></i></a>&nbsp;');
}
actions.push('<a href="${ctx}/sys/corpAdmin/delete?userCode='+row.userCode+'" class="btnList" title="删除用户" data-confirm="确认要删除该用户吗?"><i class="fa fa-trash-o"></i></a>&nbsp;');
<% if(@ObjectUtils.toBoolean(@Global.getConfig('user.useCorpModel'))){ %>
<% if(@Global.getConfigToBoolean('user.useCorpModel', 'false')){ %>
actions.push('<a href="${ctx}/sys/corpAdmin/form?corpCode_='+row.corpCode_+'&corpName_='+row.corpName_+'&op=addAdmin" class="btnList" title="新增管理员"><i class="fa fa-plus-square"></i></a>&nbsp;');
<% } %>
actions.push('<a href="javascript:" class="btnMore" title="更多操作"><i class="fa fa-chevron-circle-right"></i></a>&nbsp;');

View File

@@ -205,7 +205,7 @@ $('#btnImport').click(function(){
<div class="col-xs-12 col-xs-offset-1">
<input type="file" id="file" name="file" class="form-file"/>
<div class="mt10 pt5">
<#form:checkbox name="updateSupport" label="${text('否更新已经存在的用户数据')}" class="form-control"
<#form:checkbox name="updateSupport" label="${text('否更新已经存在的用户数据')}" class="form-control"
title="${text('如果用户编码已经存在,更新这条数据。')}"/> &nbsp;
<a href="${ctx}/sys/empUser/importTemplate" class="btn btn-default btn-xs"><i class="fa fa-file-excel-o"></i> ${text('')}</a>
</div>

View File

@@ -77,7 +77,7 @@
</div>
<% } %>
<script>
var selectData = JSON.parse(js.decodeUrl('${isNotBlank(selectData!) ? selectData! : "{\}"}')),
var selectData = ${isNotBlank(selectData!) ? selectData! : "{\}"},
selectNum = 0, dataGrid = $('#dataGrid').dataGrid({
searchForm: $("#searchForm"),
columnModel: [

View File

@@ -24,7 +24,7 @@ var bodyClass = 'fixed noscroll2 sidebar-mini ' + sidebarCollapse;
</div>
<% } %>
<div class="hide" id="desktopTabPage" data-title="${text('仪表盘')}"
data-url="${ctx}${@Global.getConfig('sys.index.desktopUrl', '/desktop')}"></div>
data-url="${ctx}${@Global.getConfig('sys.index.desktopUrl')}"></div>
<div class="hide" id="modifyPasswordTip" data-message="${modifyPasswordTip!}"></div>
<script src="${ctxStatic}/jquery-toastr/2.0/toastr.min.js?${_version}"></script>
<script src="${ctxStatic}/jquery-plugins/jquery.slimscroll.js"></script>

View File

@@ -1,14 +1,11 @@
<%
var langTypeList = @DictUtils.getDictList('sys_lang_type');
if (langTypeList.~size > 1){
%>
<% if (@com.jeesite.common.i18n.I18nLocaleResolver.enabled()){ %>
<li class="dropdown user-menu mr5">
<a href="javascript:" class="dropdown-toggle" data-toggle="dropdown" data-hover="dropdown">
<i class="fa icon-globe"></i>
</a>
<ul class="dropdown-menu">
<li class="mt5"></li>
<% for(var dict in langTypeList){ %>
<% for(var dict in @DictUtils.getDictList('sys_lang_type')){ %>
<li><a href="${ctxPath}/lang/${dict.dictValue}">${dict.dictLabel}</a></li>
<% } %>
<li class="mt10"></li>

View File

@@ -33,8 +33,8 @@
<div style="margin:8px 0 0;float:right;">
{{# $.each(d.msgContentEntity.buttons, function(idx, item){ }}
<button class="btn btn-default btn-sm" type="button"
data-href="${ctxPath}{{d.item.href}}"
onclick="readMsg(this, '${text('查看消息')}', '{{d.item.id}}');">{{d.item.name}}</button>&nbsp;
data-href="${ctxPath}{{item.href}}"
onclick="readMsg(this, '${text('查看消息')}', '{{item.id}}');">{{item.name}}</button>&nbsp;
{{# }); }}
<button type="button" class="btn btn-default btn-sm"
data-href="${ctx}/msg/readMsg?id={{d.id}}"

View File

@@ -5,7 +5,8 @@
</a>
<script>
function refreshOnlineCount(){
$.get('${ctx}/sys/online/count?__notUpdateSession=true&__t='+new Date().getTime(), function(data){
$.get('${ctx}/sys/online/count?__notUpdateSession=true&__t='
+ new Date().getTime(), function(data){
try{$('#onlineCount').html(Number(data))}catch(e){}
})
}

View File

@@ -24,7 +24,7 @@
<#form:input type="password" name="password" class="form-control required"
data-msg-required="${text('请填写登录密码.')}" placeholder="${text('登录密码')}" autocomplete="off"/>
</div>
<%/*<!-- if(@ObjectUtils.toBoolean(@Global.getConfig('user.useCorpModel'))){ %>
<%/*<!-- if(@Global.getConfigToBoolean('user.useCorpModel', 'false')){ %>
<div class="form-group has-feedback">
<select name="param_corpCode" class="form-control">
<% for(var user in @UserUtils.findCorpList()){ %>
@@ -55,20 +55,17 @@
<div class="row">
<div class="col-xs-12">
<a href="${ctxPath}/account/forgetPwd" class="pull-left">[ ${text('忘记密码')} ]</a>
<% if(@ObjectUtils.toBoolean(@Global.getConfig('user.registerUser'))){ %>
<% if(@Global.getConfigToBoolean('user.registerUser', 'false')){ %>
<a href="${ctxPath}/account/registerUser" class="pull-left ml10">[ ${text('注册账号')} ]</a>
<% } %>
<%
var langTypeList = @DictUtils.getDictList('sys_lang_type');
if (langTypeList.~size > 1){
%>
<% if (@com.jeesite.common.i18n.I18nLocaleResolver.enabled()){ %>
<div class="dropdown pull-right">
<a href="javascript:" class="dropdown-toggle" data-toggle="dropdown" data-hover="dropdown">
<i class="fa icon-globe"></i> ${@DictUtils.getDictLabel('sys_lang_type', lang(), 'zh_CN')}
</a>
<ul class="dropdown-menu">
<li class="mt5"></li>
<% for(var dict in langTypeList){ %>
<% for(var dict in @DictUtils.getDictList('sys_lang_type')){ %>
<li><a href="${ctxPath}/lang/${dict.dictValue}">${dict.dictLabel}</a></li>
<% } %>
<li class="mt10"></li>

View File

@@ -29,7 +29,7 @@ import com.jeesite.modules.sys.entity.User;
/**
* Mapper测试
* @author ThinkGem
* @version 2017年2月25日
* @version 2018-08-11
*/
@ActiveProfiles("test")
@SpringBootTest(classes=ApplicationTest.class)
@@ -50,7 +50,7 @@ public class DaoMapperTest extends BaseSpringContextTests {
public void testTableAnnotation() throws Exception{
try{
System.out.println("============ 插入批量插入测试 ============");
System.out.println("============ 插入批量插入测试 ============");
Config config = new Config();
config.setId("1");
config.setConfigKey("test");
@@ -64,13 +64,13 @@ public class DaoMapperTest extends BaseSpringContextTests {
System.out.println(configDao.insert(config));
System.out.println(configDao.insertBatch(ListUtils.newArrayList(config2, config3)));
System.out.println("============ 更新、删除测试 ============");
System.out.println("============ 更新测试 ============");
Area area = new Area();
area.setAreaCode("1");
area.setAreaName("你好");
area.setStatus("0");
Area where = new Area();
where.setAreaCode("2");
where.setId("2");
where.setId_in(new String[]{"1","2"});
where.setAreaName("你好2");
where.setStatus("0");
@@ -78,12 +78,18 @@ public class DaoMapperTest extends BaseSpringContextTests {
System.out.println(areaDao.updateByEntity(area, where));
System.out.println(areaDao.updateStatus(area));
System.out.println(areaDao.updateStatusByEntity(area, where));
System.out.println("============ 逻辑删除测试 ============");
System.out.println(areaDao.delete(area));
System.out.println(areaDao.delete(where));
System.out.println(areaDao.deleteByEntity(where));
System.out.println(areaDao.findList(area));
System.out.println(areaDao.delete((Area)where.clone()));
System.out.println(areaDao.deleteByEntity((Area)where.clone()));
System.out.println("============ 物理删除测试 ============");
System.out.println(areaDao.phyDelete((Area)where.clone()));
System.out.println(areaDao.phyDeleteByEntity((Area)where.clone()));
System.out.println("============ 基本信息查询测试 ============");
System.out.println(areaDao.findList(area));
User user = new User();
user.setUserType(User.USER_TYPE_NONE);
System.out.println(userDao.findList(user));
@@ -150,12 +156,12 @@ public class DaoMapperTest extends BaseSpringContextTests {
.andBracket("name", QueryType.EQ, "abc", 1).or("name", QueryType.EQ, "def", 2)
.or("name", QueryType.EQ, "ghi", 3).endBracket().toSql());
System.out.println(new Config().getSqlMap().getWhere()
.andBracket("name", QueryType.EQ, "val", 1)
.and("name", QueryType.NE, "val", 2).endBracket()
.orBracket("name", QueryType.NE, "val", 3)
.and("name", QueryType.NE, "val", 4).endBracket()
.orBracket("name", QueryType.NE, "val", 5)
.and("name", QueryType.EQ, "val", 6).endBracket().toSql());
.andBracket("name", QueryType.EQ, "val1", 1)
.and("name", QueryType.NE, "val2", 11).endBracket(1)
.orBracket("name", QueryType.NE, "val3", 2)
.and("name", QueryType.NE, "val4", 22).endBracket(2)
.orBracket("name", QueryType.NE, "val5", 3)
.and("name", QueryType.EQ, "val6", 33).endBracket(3).toSql());
System.out.println("============ 带括号空值测试 ============");
System.out.println(new Config("1").getSqlMap().getWhere()
@@ -170,6 +176,9 @@ public class DaoMapperTest extends BaseSpringContextTests {
System.out.println(new Config("1").getSqlMap().getWhere()
.andBracket("name", QueryType.EQ, "", 1).or("name", QueryType.EQ, "", 2)
.or("name", QueryType.EQ, "", 3).endBracket().toSql());
System.out.println(new Config().getSqlMap().getWhere()
.andBracket("name", QueryType.EQ, "", 1).or("name", QueryType.EQ, "", 2)
.or("name", QueryType.EQ, "", 3).endBracket().toSql());
System.out.println("============ 实体嵌套测试 ============");
Company company = new Company("1");
@@ -180,7 +189,6 @@ public class DaoMapperTest extends BaseSpringContextTests {
company.getArea().setCreateDate_gte(new Date());
company.getArea().setCreateDate_lte(new Date());
System.out.println(company.getSqlMap().getWhere().toSql());
}
}

View File

@@ -5,6 +5,7 @@ package com.jeesite.test;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@@ -18,9 +19,11 @@ import com.jeesite.modules.msg.entity.content.AppMsgContent;
import com.jeesite.modules.msg.entity.content.EmailMsgContent;
import com.jeesite.modules.msg.entity.content.PcMsgContent;
import com.jeesite.modules.msg.entity.content.SmsMsgContent;
import com.jeesite.modules.msg.service.MsgPushService;
import com.jeesite.modules.msg.task.impl.MsgLocalMergePushTask;
import com.jeesite.modules.msg.task.impl.MsgLocalPushTask;
import com.jeesite.modules.msg.utils.MsgPushUtils;
import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.utils.UserUtils;
/**
* 消息推送测试类
@@ -34,22 +37,21 @@ public class MsgPushTest extends BaseSpringContextTests {
@Test
public void testSend(){
for (int i=0; i<3; i++){
User user = UserUtils.get("system");
if (StringUtils.isAnyBlank(user.getMobile(), user.getEmail())){
throw new RuntimeException("请设置system用户的手机号码和邮箱地址");
}
for (int i=0; i<1; i++){
testPC();
testApp();
testSMS();
testMail();
testMailTpl();
}
for (int j=0; j<3; j++){
testTaskMergePush();
testTaskPush();
}
// testTask();
}
@Autowired
private MsgPushService msgPushService;
public void testTask(){
MsgLocalPushTask task = new MsgLocalPushTask();
task.setMsgPushService(msgPushService);
task.execute();
}
public void testPC(){
@@ -101,4 +103,27 @@ public class MsgPushTest extends BaseSpringContextTests {
MsgPushUtils.push(msgContent, "BizKey", "BizType", "system", new Date(), Global.YES);
}
public void testMailTpl(){
EmailMsgContent msgContent = new EmailMsgContent();
msgContent.setTitle("提示信息");
msgContent.setTplKey("mail_send_test");
msgContent.addTplData("keyword1", "小王");
msgContent.addTplData("keyword2", "2018-8-28 20:00");
msgContent.addTplData("keyword3", "ERP项目方案讨论视频会议");
// 即时推送模板消息,模板内容:你好,${keyword1},请于 ${keyword2},准时参加${keyword3}
MsgPushUtils.push(msgContent, "BizKey", "BizType", "system");
}
@Autowired
private MsgLocalMergePushTask msgLocalMergePushTask;
public void testTaskMergePush(){
msgLocalMergePushTask.execute();
}
@Autowired
private MsgLocalPushTask msgLocalPushTask;
public void testTaskPush(){
msgLocalPushTask.execute();
}
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>4.0.5-SNAPSHOT</version>
<version>4.0.7-SNAPSHOT</version>
<relativePath>../../parent/pom.xml</relativePath>
<!-- ====== 这是一个新增模块示例项目,你可以拷贝此项目,修改 artifactId 为您的模块即可 ====== -->

View File

@@ -11,7 +11,7 @@
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>4.0.5-SNAPSHOT</version>
<version>4.0.7-SNAPSHOT</version>
<packaging>pom</packaging>
<name>JeeSite Parent</name>
@@ -33,7 +33,7 @@
<mybatis.version>3.4.5</mybatis.version>
<mybatis-spring.version>1.3.1</mybatis-spring.version>
<jsqlparser.version>1.1</jsqlparser.version>
<druid.version>1.1.3</druid.version>
<druid.version>1.1.10</druid.version>
<shiro.version>1.4.0</shiro.version>
<beetl.version>2.7-SNAPSHOT</beetl.version>
<ehcache-web.version>2.0.4</ehcache-web.version>

View File

@@ -1,2 +0,0 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@@ -5,7 +5,7 @@
<groupId>com.jeesite</groupId>
<artifactId>jeesite-root</artifactId>
<version>4.0.5-SNAPSHOT</version>
<version>4.0.7-SNAPSHOT</version>
<packaging>pom</packaging>
<name>JeeSite</name>

View File

@@ -3,13 +3,13 @@
1. 不得应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为。
2. 付费之前请确认已通过社区版了解和试用“产品”,并确认产品功能符合您的需求;付费之后源代码与社区版本相同,不另外提供源代码,您只需上传许可文件即可;许可文件一经发出概不提供退货服务。
3. 您必须了解使用本软件的风险本软件无法保证100%没有漏洞,所以由软件漏洞造成的损失不予赔偿,也不承担任何因使用本软件而产生相关法律责任。请软件上线使用前进行足够的安全测试,以避免此问题发生。
4. 基于JeeSite开发的项目或产品名称以及公司名称同意支持JeeSite推广的案例公布。
4. 基于JeeSite开发的项目或产品名称以及公司名称同意支持和参与JeeSite推广的案例公布。
5. 若您已经购买本产品许可文件或以其它方式获得的许可文件,将被视为您对本服务条款全部的完全接受,如果您未能遵守本服务条款,您的许可授权将被终止,许可的权利将被收回,同时您应承担相应法律责任。
# 联系方式
QQ78112665
QQ1766571055
**请认准唯一捐赠收款账号**ThinkGem*震)
**请认准唯一收款账号(其它付款均不作为有效凭证)**
![ThinkGem的支付宝收款二维码](https://static.oschina.net/uploads/img/201803/16112020_sFWX.jpg "ThinkGem的支付宝收款二维码")

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="web">
<dependent-module archiveName="jeesite-module-core-4.0.5-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/jeesite-module-core/jeesite-module-core">
<dependent-module archiveName="jeesite-module-core-4.0.7-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/jeesite-module-core/jeesite-module-core">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module archiveName="jeesite-common-4.0.5-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/jeesite-common/jeesite-common">
<dependent-module archiveName="jeesite-common-4.0.7-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/jeesite-common/jeesite-common">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module archiveName="jeesite-framework-4.0.5-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/jeesite-framework/jeesite-framework">
<dependent-module archiveName="jeesite-framework-4.0.7-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/jeesite-framework/jeesite-framework">
<dependency-type>uses</dependency-type>
</dependent-module>
<property name="component.exclusion.patterns"/>

View File

@@ -175,7 +175,7 @@ CREATE TABLE [js_sys_config]
[id] varchar(64) NOT NULL,
[config_name] nvarchar(100) NOT NULL,
[config_key] varchar(100) NOT NULL,
[config_value] nvarchar(1000) NOT NULL,
[config_value] nvarchar(1000),
[is_sys] char(1) NOT NULL,
[create_by] varchar(64) NOT NULL,
[create_date] datetime NOT NULL,

View File

@@ -176,7 +176,7 @@ CREATE TABLE js_sys_config
id varchar(64) NOT NULL COMMENT '编号',
config_name varchar(100) NOT NULL COMMENT '名称',
config_key varchar(100) NOT NULL COMMENT '参数键',
config_value varchar(1000) NOT NULL COMMENT '参数值',
config_value varchar(1000) COMMENT '参数值',
is_sys char(1) NOT NULL COMMENT '系统内置1是 0否',
create_by varchar(64) NOT NULL COMMENT '创建者',
create_date datetime NOT NULL COMMENT '创建时间',

View File

@@ -175,7 +175,7 @@ CREATE TABLE js_sys_config
id varchar2(64) NOT NULL,
config_name nvarchar2(100) NOT NULL,
config_key varchar2(100) NOT NULL,
config_value nvarchar2(1000) NOT NULL,
config_value nvarchar2(1000),
is_sys char(1) NOT NULL,
create_by varchar2(64) NOT NULL,
create_date timestamp NOT NULL,

View File

@@ -175,7 +175,7 @@ CREATE TABLE js_sys_config
id varchar(64) NOT NULL,
config_name varchar(100) NOT NULL,
config_key varchar(100) NOT NULL,
config_value varchar(1000) NOT NULL,
config_value varchar(1000),
is_sys char(1) NOT NULL,
create_by varchar(64) NOT NULL,
create_date timestamp NOT NULL,

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId>
<version>4.0.5-SNAPSHOT</version>
<version>4.0.7-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
@@ -45,20 +45,6 @@
<version>${project.parent.version}</version>
</dependency>
<!-- 内容管理模块
<dependency>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-module-cms</artifactId>
<version>${project.parent.version}</version>
</dependency>-->
<!-- 微信模块
<dependency>
<groupId>com.jeesite</groupId>
<artifactId>jeesite-module-weixin</artifactId>
<version>${project.parent.version}</version>
</dependency>-->
<!-- 自定义jar依赖包演示
<dependency>
<groupId>com.jeesite</groupId>
@@ -90,8 +76,10 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<packagingExcludes></packagingExcludes>
<warSourceExcludes></warSourceExcludes>
<warSourceExcludes>
WEB-INF/classes/*.lic,
userfiles/**
</warSourceExcludes>
<webappDirectory>${project.build.directory}/${project.artifactId}</webappDirectory>
<warName>${finalName}</warName>
<archive>

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