Compare commits

...

31 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
61 changed files with 1738 additions and 273 deletions

View File

@@ -21,7 +21,7 @@ JeeSite 自开源以来已被广大爱好者用到了企业、政府、医疗、
* 视图层Spring MVC 4.3、Beetl 2.7 替换JSP、Bootstrap 3.3、AdminLTE 2.4 * 视图层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 * 前端组件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 * 工具组件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> * 技术选型详情:<http://jeesite4.mydoc.io/?t=273599>
## 内置功能菜单 ## 内置功能菜单
@@ -38,6 +38,8 @@ JeeSite 自开源以来已被广大爱好者用到了企业、政府、医疗、
* 数据表格API (DataGrid.js)<http://jeesite4.mydoc.io/?t=301488> * 数据表格API (DataGrid.js)<http://jeesite4.mydoc.io/?t=301488>
* 修改 (默认) 视图,新增主题:<http://jeesite4.mydoc.io/?t=267355> * 修改 (默认) 视图,新增主题:<http://jeesite4.mydoc.io/?t=267355>
* 手机 API 接口调用、前后分离:<http://jeesite4.mydoc.io/?t=270527> * 手机 API 接口调用、前后分离:<http://jeesite4.mydoc.io/?t=270527>
* 代码生成工具使用手册:<http://jeesite4.mydoc.io/?t=316743>
* 常见问题:<http://jeesite4.mydoc.io/?t=284210>
# 快速体验 # 快速体验
@@ -95,6 +97,7 @@ JeeSite的小版本4.0.x升级是非常便捷的你只需要将 pom.xml
* GitHub<https://github.com/thinkgem/jeesite4> * GitHub<https://github.com/thinkgem/jeesite4>
* 作者博客:<https://my.oschina.net/thinkgem> * 作者博客:<https://my.oschina.net/thinkgem>
* 官方网站:<http://jeesite.com> * 官方网站:<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微信公众号") ![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> <parent>
<groupId>com.jeesite</groupId> <groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId> <artifactId>jeesite-parent</artifactId>
<version>4.0.6-SNAPSHOT</version> <version>4.0.7-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>

View File

@@ -3,12 +3,16 @@
*/ */
package com.jeesite.common.codec; package com.jeesite.common.codec;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.jeesite.common.io.IOUtils;
/** /**
* MD5不可逆加密工具类 * MD5不可逆加密工具类
* @author ThinkGem * @author ThinkGem
@@ -17,7 +21,6 @@ public class Md5Utils {
private static final String MD5 = "MD5"; private static final String MD5 = "MD5";
private static final String DEFAULT_ENCODING = "UTF-8"; private static final String DEFAULT_ENCODING = "UTF-8";
/** /**
* 对输入字符串进行md5散列. * 对输入字符串进行md5散列.
@@ -63,5 +66,36 @@ public class Md5Utils {
public static byte[] md5(InputStream input) throws IOException { public static byte[] md5(InputStream input) throws IOException {
return DigestUtils.digest(input, MD5); 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){ public static <T> List<T> listOrderBy(List<T> list, String orderBy){
if (list != null && StringUtils.isNotBlank(orderBy)){ if (list != null && StringUtils.isNotBlank(orderBy)){
final String[] ss = orderBy.trim().split(" "); 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>() { Collections.sort(list, new Comparator<T>() {
@Override @Override
public int compare(T o1, T o2) { 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])); s1 = ObjectUtils.toString(ReflectUtils.invokeGetter(o1, ss[0]));
s2 = ObjectUtils.toString(ReflectUtils.invokeGetter(o2, ss[0])); s2 = ObjectUtils.toString(ReflectUtils.invokeGetter(o2, ss[0]));
} }
if ("asc".equals(ss[1])){ if ("asc".equalsIgnoreCase(t)){
return s1.compareTo(s2); return s1.compareTo(s2);
}else{ }else{
return s2.compareTo(s1); return s2.compareTo(s1);
} }
}}); }
});
} }
} }
return list; return list;

View File

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

View File

@@ -4,6 +4,7 @@
package com.jeesite.common.lang; package com.jeesite.common.lang;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.DecimalFormat;
/** /**
* BigDecimal工具类 * BigDecimal工具类
@@ -92,4 +93,19 @@ public class NumberUtils extends org.apache.commons.lang3.math.NumberUtils {
return bg.setScale(0, BigDecimal.ROUND_HALF_UP).toString(); 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

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

View File

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

View File

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

View File

@@ -1,141 +1,43 @@
package com.jeesite.common.msg; 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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.jeesite.common.io.PropertiesUtils;
import com.jeesite.common.lang.DateUtils;
/** /**
* 发送短信(乐云短信 * 发送短信(请实现send方法
*/ */
public class SmsUtils { public class SmsUtils {
private final static Logger logger = LoggerFactory.getLogger(SmsUtils.class); 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 content 短信内容
* @param phone 接受手机号码 * @param mobile 接受手机号码
* @return {"result":"0","describing""提交成功","sms":[{"phone":"18073110001,18073110002","smsid":"83bd18f1d48b4cc9b9fe7810c768ac43","status":"3"}]}
*/ */
public static String send(String content, String phone) { public static String send(String content, String mobile) {
return send(content, phone, null); // 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

@@ -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

@@ -78,6 +78,21 @@ public class ServletUtils {
return response; 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异步请求 * 是否是Ajax异步请求
* @param request * @param request
@@ -173,9 +188,10 @@ public class ServletUtils {
resultMap.put("data", data); resultMap.put("data", data);
} }
} }
HttpServletRequest request = ServletUtils.getRequest(); HttpServletRequest request = getRequest();
String uri = request.getRequestURI(); String uri = request.getRequestURI();
if (StringUtils.endsWithIgnoreCase(uri, ".xml")){ if (StringUtils.endsWithIgnoreCase(uri, ".xml") || StringUtils
.equalsIgnoreCase(request.getParameter("__ajax"), "xml")){
return XmlMapper.toXml(resultMap); return XmlMapper.toXml(resultMap);
}else{ }else{
String functionName = request.getParameter("__callback"); String functionName = request.getParameter("__callback");
@@ -202,7 +218,7 @@ public class ServletUtils {
/** /**
* 直接将结果JSON字符串渲染到客户端支持JsonP请求参数加__callback=回调函数名) * 直接将结果JSON字符串渲染到客户端支持JsonP请求参数加__callback=回调函数名)
* @param response 渲染对象:{result:'true',message:'',data:{}} * @param response 渲染对象:{result:'true',message:'',data:{}}
* @param result Global.TRUE or Globle.False * @param result 结果标识:Global.TRUE or Globle.False
* @param message 执行消息 * @param message 执行消息
* @param data 消息数据 * @param data 消息数据
* @return null * @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 response 渲染对象
* @param object 待转换JSON并渲染的对象 * @param object 待转换JSON并渲染的对象
* @return null * @return null
*/ */
public static String renderObject(HttpServletResponse response, Object object) { public static String renderObject(HttpServletResponse response, Object object) {
HttpServletRequest request = ServletUtils.getRequest(); HttpServletRequest request = getRequest();
String uri = request.getRequestURI(); String uri = request.getRequestURI();
if (StringUtils.endsWithIgnoreCase(uri, ".xml")){ if (StringUtils.endsWithIgnoreCase(uri, ".xml") || StringUtils
return XmlMapper.toXml(object); .equalsIgnoreCase(request.getParameter("__ajax"), "xml")){
return renderString(response, XmlMapper.toXml(object));
}else{ }else{
String functionName = request.getParameter("__callback"); String functionName = request.getParameter("__callback");
if (StringUtils.isNotBlank(functionName)){ if (StringUtils.isNotBlank(functionName)){
@@ -250,8 +268,18 @@ public class ServletUtils {
*/ */
public static String renderString(HttpServletResponse response, String string, String type) { public static String renderString(HttpServletResponse response, String string, String type) {
try { try {
// response.reset(); // 注释掉否则以前设置的Header会被清理掉如ajax登录设置记住我Cookie // response.reset(); // 注释掉否则以前设置的Header会被清理掉如ajax登录设置记住我Cookie信息
response.setContentType(type == null ? "application/json" : type); 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.setCharacterEncoding("utf-8");
response.getWriter().print(string); response.getWriter().print(string);
} catch (IOException e) { } catch (IOException e) {

View File

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

View File

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

View File

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

View File

@@ -8,6 +8,7 @@ import java.util.Map;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -34,6 +35,7 @@ import com.jeesite.modules.sys.utils.UserUtils;
*/ */
@Controller @Controller
@RequestMapping(value = "${adminPath}/sys/area") @RequestMapping(value = "${adminPath}/sys/area")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class AreaController extends BaseController { public class AreaController extends BaseController {
@Autowired @Autowired

View File

@@ -11,6 +11,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -39,6 +40,7 @@ import com.jeesite.modules.sys.utils.UserUtils;
*/ */
@Controller @Controller
@RequestMapping(value = "${adminPath}/sys/company") @RequestMapping(value = "${adminPath}/sys/company")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class CompanyController extends BaseController { public class CompanyController extends BaseController {
@Autowired @Autowired

View File

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

View File

@@ -54,7 +54,8 @@ public class LoginController extends BaseController{
if (StringUtils.containsIgnoreCase(request.getRequestURI(), ";JSESSIONID=")){ if (StringUtils.containsIgnoreCase(request.getRequestURI(), ";JSESSIONID=")){
String queryString = request.getQueryString(); String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString; queryString = queryString == null ? "" : "?" + queryString;
return REDIRECT + adminPath + "/login" + queryString; ServletUtils.redirectUrl(request, response, adminPath + "/login" + queryString);
return null;
} }
LoginInfo loginInfo = UserUtils.getLoginInfo(); LoginInfo loginInfo = UserUtils.getLoginInfo();
@@ -63,16 +64,8 @@ public class LoginController extends BaseController{
if(loginInfo != null){ if(loginInfo != null){
String queryString = request.getQueryString(); String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString; queryString = queryString == null ? "" : "?" + queryString;
String indexUrl = adminPath + "/index" + queryString; ServletUtils.redirectUrl(request, response, adminPath + "/index" + queryString);
if (ServletUtils.isAjaxRequest(request)){ return null;
try {
request.getRequestDispatcher(indexUrl).forward(request, response); // AJAX不支持Redirect改用Forward
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
return null;
}
return REDIRECT + indexUrl;
} }
// 如果是登录操作跳转到此则认为是登录失败支持GET登录时传递__login=true参数 // 如果是登录操作跳转到此则认为是登录失败支持GET登录时传递__login=true参数
@@ -130,16 +123,8 @@ public class LoginController extends BaseController{
if(loginInfo != null){ if(loginInfo != null){
String queryString = request.getQueryString(); String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString; queryString = queryString == null ? "" : "?" + queryString;
String indexUrl = adminPath + "/index" + queryString; ServletUtils.redirectUrl(request, response, adminPath + "/index" + queryString);
if (ServletUtils.isAjaxRequest(request)){ return null;
try {
request.getRequestDispatcher(indexUrl).forward(request, response); // AJAX不支持Redirect改用Forward
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
return null;
}
return REDIRECT + indexUrl;
} }
String username = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_USERNAME_PARAM); String username = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_USERNAME_PARAM);
@@ -202,12 +187,16 @@ public class LoginController extends BaseController{
if (StringUtils.containsIgnoreCase(request.getRequestURI(), ";JSESSIONID=")){ if (StringUtils.containsIgnoreCase(request.getRequestURI(), ";JSESSIONID=")){
String queryString = request.getQueryString(); String queryString = request.getQueryString();
queryString = queryString == null ? "" : "?" + queryString; queryString = queryString == null ? "" : "?" + queryString;
return REDIRECT + adminPath + "/index" + queryString; ServletUtils.redirectUrl(request, response, adminPath + "/index" + queryString);
return null;
} }
// 验证下用户权限以便调用doGetAuthorizationInfo方法保存单点登录登出句柄 // 验证下用户权限以便调用doGetAuthorizationInfo方法保存单点登录登出句柄
if (!SecurityUtils.getSubject().isPermitted("user")){ 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;
} }
//获取登录用户信息 //获取登录用户信息
@@ -216,14 +205,20 @@ public class LoginController extends BaseController{
// 未加载shiro模块时会为空直接访问则提示操作权限不足。 // 未加载shiro模块时会为空直接访问则提示操作权限不足。
if(loginInfo == null){ if(loginInfo == null){
UserUtils.getSubject().logout(); 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()); User user = UserUtils.get(loginInfo.getId());
if (user == null){ if (user == null){
UserUtils.getSubject().logout(); 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); // 设置当前用户信息 model.addAttribute("user", user); // 设置当前用户信息
@@ -231,10 +226,10 @@ public class LoginController extends BaseController{
Session session = UserUtils.getSession(); Session session = UserUtils.getSession();
// 是否是登录操作 // 是否是登录操作
boolean isLogin = "true".equals(loginInfo.getParam("__login")); boolean isLogin = "true".equals(session.getAttribute("__login"));
if (isLogin){ if (isLogin){
// 获取后接着清除,防止下次获取仍然认为是登录状态 // 获取后接着清除,防止下次获取仍然认为是登录状态
loginInfo.getParams().remove("__login"); session.removeAttribute("__login");
// 设置共享SessionId的Cookie值第三方系统使用 // 设置共享SessionId的Cookie值第三方系统使用
String cookieName = Global.getProperty("session.shareSessionIdCookieName"); String cookieName = Global.getProperty("session.shareSessionIdCookieName");
if (StringUtils.isNotBlank(cookieName)){ if (StringUtils.isNotBlank(cookieName)){

View File

@@ -8,6 +8,7 @@ import java.util.Map;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -35,6 +36,7 @@ import com.jeesite.modules.sys.web.user.EmpUserController;
*/ */
@Controller @Controller
@RequestMapping(value = "${adminPath}/sys/office") @RequestMapping(value = "${adminPath}/sys/office")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class OfficeController extends BaseController { public class OfficeController extends BaseController {
@Autowired @Autowired

View File

@@ -17,6 +17,7 @@ import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext; import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping; 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.Lists;
import com.beust.jcommander.internal.Maps; 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.config.Global;
import com.jeesite.common.lang.DateUtils; import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.lang.ObjectUtils; import com.jeesite.common.lang.ObjectUtils;
@@ -41,6 +44,7 @@ import com.jeesite.modules.sys.utils.UserUtils;
*/ */
@Controller @Controller
@RequestMapping(value = "${adminPath}/sys/online") @RequestMapping(value = "${adminPath}/sys/online")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class OnlineController extends BaseController{ public class OnlineController extends BaseController{
@Autowired @Autowired
@@ -143,6 +147,17 @@ public class OnlineController extends BaseController{
public String tickOut(String sessionId) { public String tickOut(String sessionId) {
Session session = sessionDAO.readSession(sessionId); Session session = sessionDAO.readSession(sessionId);
if (session != null){ 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); sessionDAO.delete(session);
return renderResult(Global.TRUE, "踢出已成功!"); return renderResult(Global.TRUE, "踢出已成功!");
} }

View File

@@ -8,6 +8,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -29,6 +30,7 @@ import com.jeesite.modules.sys.service.PostService;
*/ */
@Controller @Controller
@RequestMapping(value = "${adminPath}/sys/post") @RequestMapping(value = "${adminPath}/sys/post")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class PostController extends BaseController { public class PostController extends BaseController {
@Autowired @Autowired

View File

@@ -9,6 +9,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -34,6 +35,7 @@ import com.jeesite.modules.sys.utils.ValidCodeUtils;
*/ */
@Controller @Controller
@RequestMapping(value = "/account") @RequestMapping(value = "/account")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class AccountController extends BaseController{ public class AccountController extends BaseController{
@Autowired @Autowired

View File

@@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -35,6 +36,7 @@ import com.jeesite.modules.sys.utils.UserUtils;
*/ */
@Controller @Controller
@RequestMapping(value = "${adminPath}/sys/corpAdmin") @RequestMapping(value = "${adminPath}/sys/corpAdmin")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class CorpAdminController extends BaseController { public class CorpAdminController extends BaseController {
@Autowired @Autowired

View File

@@ -13,6 +13,7 @@ import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -54,6 +55,7 @@ import com.jeesite.modules.sys.utils.UserUtils;
*/ */
@Controller @Controller
@RequestMapping(value = "${adminPath}/sys/empUser") @RequestMapping(value = "${adminPath}/sys/empUser")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class EmpUserController extends BaseController { public class EmpUserController extends BaseController {
@Autowired @Autowired
@@ -96,7 +98,8 @@ public class EmpUserController extends BaseController {
if (!(isAll != null && isAll)){ if (!(isAll != null && isAll)){
empUserService.addDataScopeFilter(empUser, UserDataScope.CTRL_PERMI_MANAGE); 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; return page;
} }

View File

@@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -32,6 +33,7 @@ import com.jeesite.modules.sys.service.UserService;
*/ */
@Controller @Controller
@RequestMapping(value = "${adminPath}/sys/secAdmin") @RequestMapping(value = "${adminPath}/sys/secAdmin")
@ConditionalOnProperty(name="web.core.enabled", havingValue="true", matchIfMissing=true)
public class SecAdminController extends BaseController { public class SecAdminController extends BaseController {
@Autowired @Autowired

View File

@@ -73,7 +73,7 @@ jdbc:
stat: stat:
enabled: true enabled: true
# Redis 配置2.x/3.x # Redis 配置
redis: redis:
enabled: false enabled: false
@@ -90,7 +90,7 @@ redis:
pool: pool:
maxIdle: 3 maxIdle: 3
maxTotal: 20 maxTotal: 20
# 是否启用Redis系统缓存及会话专业版 # 是否启用Redis系统缓存及会话专业版
cacheAndSession: false cacheAndSession: false
@@ -179,9 +179,19 @@ user:
registerUser: registerUser:
enabled: false enabled: false
userTypes: 0, 1 userTypes: 0, 1
# 菜单管理
menu:
# 根据模块状态去更新相连的菜单状态仅作为微服务时设为false
updateStatusByModuleStatus: true
# 国际化管理(专业版+
lang:
enabled: true
# 任务调度(个人版+ # 任务调度(个人版+
job: job:
enabled: true
# 是否自动启动任务调度(可关闭) # 是否自动启动任务调度(可关闭)
autoStartup: true autoStartup: true
@@ -194,12 +204,34 @@ job:
threadCount: 10 threadCount: 10
threadPriority: 5 threadPriority: 5
# 调度设置集群中每一个实例都必须使用相同的instanceName名称 (区分特定的调度器实例)
# 每一个instanceId必须不同设置AUTO则自动生成
scheduler:
instanceName: JeeSiteScheduler
instanceId: AUTO
# 任务调度集群设置 # 任务调度集群设置
jobStore: jobStore:
isClustered: true isClustered: true
dataSourceName: job dataSourceName: job
clusterCheckinInterval: 1000 clusterCheckinInterval: 1000
# 调度日志配置
log:
# 计划调度日志
scheduler:
enabled: true
# 是否只保存错误日志
errorLevel: true
# 任务执行日志
jobDetail:
enabled: true
# 是否只保存错误日志
errorLevel: true
# 计划触发日志
trigger:
enabled: false
# 内容管理 # 内容管理
cms: cms:
@@ -242,7 +274,12 @@ shiro:
# 登录提交信息安全Key加密用户名、密码、验证码后再提交key设置为3个用逗号分隔 # 登录提交信息安全Key加密用户名、密码、验证码后再提交key设置为3个用逗号分隔
secretKey: thinkgem,jeesite,com secretKey: thinkgem,jeesite,com
# 记住我密钥设置(设置为空则使用默认)
rememberMe:
# 密钥必须通过 com.jeesite.common.shiro.web.RememberMeManager 的main方法生成
secretKey: ~
# 指定获取客户端IP的Header名称防止IP伪造。指定为空则使用原生方法获取IP。 # 指定获取客户端IP的Header名称防止IP伪造。指定为空则使用原生方法获取IP。
remoteAddrHeaderName: X-Forwarded-For remoteAddrHeaderName: X-Forwarded-For
@@ -320,9 +357,12 @@ session:
# MyBatis 相关 # MyBatis 相关
mybatis: mybatis:
# 扫描基础包设置Aliases、@MyBatisDao,如果多个,用“,”分隔 # @MyBatisDao、Aliases 扫描基础包,如果多个,用“,”分隔
scanBasePackage: com.jeesite.modules scanBasePackage: com.jeesite.modules
# TypeHandlers 扫描基础包,如果多个,用“,”分隔
scanTypeHandlersPackage: ~
# Mapper文件刷新线程 # Mapper文件刷新线程
mapper: mapper:
refresh: refresh:
@@ -393,6 +433,10 @@ web:
validator: validator:
id: '[a-zA-Z0-9_\-/\u4e00-\u9fa5]{0,64}' id: '[a-zA-Z0-9_\-/\u4e00-\u9fa5]{0,64}'
user.loginCode: '[a-zA-Z0-9_\u4e00-\u9fa5]{4,20}' user.loginCode: '[a-zA-Z0-9_\u4e00-\u9fa5]{4,20}'
# 关闭核心模块的Web功能仅作为微服务时设为false
core:
enabled: true
# 错误页面500.html是否输出错误信息正式环境为提供安全性可设置为false # 错误页面500.html是否输出错误信息正式环境为提供安全性可设置为false
error: error:
@@ -404,6 +448,7 @@ error:
#============================# #============================#
file: file:
enabled: true
# 文件上传根路径设置路径中不允许包含“userfiles”在指定目录中系统会自动创建userfiles目录如果不设置默认为contextPath路径 # 文件上传根路径设置路径中不允许包含“userfiles”在指定目录中系统会自动创建userfiles目录如果不设置默认为contextPath路径
# baseDir: D:/jeesite # baseDir: D:/jeesite

View File

@@ -4,4 +4,5 @@
4.0.3 4.0.3
4.0.4 4.0.4
4.0.5 4.0.5
4.0.6 4.0.6
4.0.7

View File

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

View File

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

View File

@@ -61,10 +61,10 @@
<label class="control-label">操作时间:</label> <label class="control-label">操作时间:</label>
<div class="control-inline"> <div class="control-inline">
<#form:input path="createDate_gte" readonly="readonly" maxlength="20" class="form-control Wdate-date" <#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; &nbsp;--&nbsp;
<#form:input path="createDate_lte" readonly="readonly" maxlength="20" class="form-control Wdate-date" <#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> </div>
<div class="form-group"> <div class="form-group">

View File

@@ -205,7 +205,7 @@ $('#btnImport').click(function(){
<div class="col-xs-12 col-xs-offset-1"> <div class="col-xs-12 col-xs-offset-1">
<input type="file" id="file" name="file" class="form-file"/> <input type="file" id="file" name="file" class="form-file"/>
<div class="mt10 pt5"> <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; 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> <a href="${ctx}/sys/empUser/importTemplate" class="btn btn-default btn-xs"><i class="fa fa-file-excel-o"></i> ${text('')}</a>
</div> </div>

View File

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

View File

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

View File

@@ -58,17 +58,14 @@
<% if(@Global.getConfigToBoolean('user.registerUser', 'false')){ %> <% if(@Global.getConfigToBoolean('user.registerUser', 'false')){ %>
<a href="${ctxPath}/account/registerUser" class="pull-left ml10">[ ${text('注册账号')} ]</a> <a href="${ctxPath}/account/registerUser" class="pull-left ml10">[ ${text('注册账号')} ]</a>
<% } %> <% } %>
<% <% if (@com.jeesite.common.i18n.I18nLocaleResolver.enabled()){ %>
var langTypeList = @DictUtils.getDictList('sys_lang_type');
if (langTypeList.~size > 1){
%>
<div class="dropdown pull-right"> <div class="dropdown pull-right">
<a href="javascript:" class="dropdown-toggle" data-toggle="dropdown" data-hover="dropdown"> <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')} <i class="fa icon-globe"></i> ${@DictUtils.getDictLabel('sys_lang_type', lang(), 'zh_CN')}
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li class="mt5"></li> <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><a href="${ctxPath}/lang/${dict.dictValue}">${dict.dictLabel}</a></li>
<% } %> <% } %>
<li class="mt10"></li> <li class="mt10"></li>

View File

@@ -156,12 +156,12 @@ public class DaoMapperTest extends BaseSpringContextTests {
.andBracket("name", QueryType.EQ, "abc", 1).or("name", QueryType.EQ, "def", 2) .andBracket("name", QueryType.EQ, "abc", 1).or("name", QueryType.EQ, "def", 2)
.or("name", QueryType.EQ, "ghi", 3).endBracket().toSql()); .or("name", QueryType.EQ, "ghi", 3).endBracket().toSql());
System.out.println(new Config().getSqlMap().getWhere() System.out.println(new Config().getSqlMap().getWhere()
.andBracket("name", QueryType.EQ, "val", 1) .andBracket("name", QueryType.EQ, "val1", 1)
.and("name", QueryType.NE, "val", 2).endBracket() .and("name", QueryType.NE, "val2", 11).endBracket(1)
.orBracket("name", QueryType.NE, "val", 3) .orBracket("name", QueryType.NE, "val3", 2)
.and("name", QueryType.NE, "val", 4).endBracket() .and("name", QueryType.NE, "val4", 22).endBracket(2)
.orBracket("name", QueryType.NE, "val", 5) .orBracket("name", QueryType.NE, "val5", 3)
.and("name", QueryType.EQ, "val", 6).endBracket().toSql()); .and("name", QueryType.EQ, "val6", 33).endBracket(3).toSql());
System.out.println("============ 带括号空值测试 ============"); System.out.println("============ 带括号空值测试 ============");
System.out.println(new Config("1").getSqlMap().getWhere() System.out.println(new Config("1").getSqlMap().getWhere()
@@ -176,6 +176,9 @@ public class DaoMapperTest extends BaseSpringContextTests {
System.out.println(new Config("1").getSqlMap().getWhere() System.out.println(new Config("1").getSqlMap().getWhere()
.andBracket("name", QueryType.EQ, "", 1).or("name", QueryType.EQ, "", 2) .andBracket("name", QueryType.EQ, "", 1).or("name", QueryType.EQ, "", 2)
.or("name", QueryType.EQ, "", 3).endBracket().toSql()); .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("============ 实体嵌套测试 ============"); System.out.println("============ 实体嵌套测试 ============");
Company company = new Company("1"); Company company = new Company("1");
@@ -186,7 +189,6 @@ public class DaoMapperTest extends BaseSpringContextTests {
company.getArea().setCreateDate_gte(new Date()); company.getArea().setCreateDate_gte(new Date());
company.getArea().setCreateDate_lte(new Date()); company.getArea().setCreateDate_lte(new Date());
System.out.println(company.getSqlMap().getWhere().toSql()); System.out.println(company.getSqlMap().getWhere().toSql());
} }
} }

View File

@@ -5,6 +5,7 @@ package com.jeesite.test;
import java.util.Date; import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; 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.EmailMsgContent;
import com.jeesite.modules.msg.entity.content.PcMsgContent; import com.jeesite.modules.msg.entity.content.PcMsgContent;
import com.jeesite.modules.msg.entity.content.SmsMsgContent; 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.task.impl.MsgLocalPushTask;
import com.jeesite.modules.msg.utils.MsgPushUtils; 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 @Test
public void testSend(){ 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(); testPC();
testApp(); testApp();
testSMS(); testSMS();
testMail(); 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(){ public void testPC(){
@@ -101,4 +103,27 @@ public class MsgPushTest extends BaseSpringContextTests {
MsgPushUtils.push(msgContent, "BizKey", "BizType", "system", new Date(), Global.YES); 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> <parent>
<groupId>com.jeesite</groupId> <groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId> <artifactId>jeesite-parent</artifactId>
<version>4.0.6-SNAPSHOT</version> <version>4.0.7-SNAPSHOT</version>
<relativePath>../../parent/pom.xml</relativePath> <relativePath>../../parent/pom.xml</relativePath>
<!-- ====== 这是一个新增模块示例项目,你可以拷贝此项目,修改 artifactId 为您的模块即可 ====== --> <!-- ====== 这是一个新增模块示例项目,你可以拷贝此项目,修改 artifactId 为您的模块即可 ====== -->

View File

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

View File

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

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0"> <?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="web"> <wb-module deploy-name="web">
<dependent-module archiveName="jeesite-module-core-4.0.6-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> <dependency-type>uses</dependency-type>
</dependent-module> </dependent-module>
<dependent-module archiveName="jeesite-common-4.0.6-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> <dependency-type>uses</dependency-type>
</dependent-module> </dependent-module>
<dependent-module archiveName="jeesite-framework-4.0.6-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> <dependency-type>uses</dependency-type>
</dependent-module> </dependent-module>
<property name="component.exclusion.patterns"/> <property name="component.exclusion.patterns"/>

View File

@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>com.jeesite</groupId> <groupId>com.jeesite</groupId>
<artifactId>jeesite-parent</artifactId> <artifactId>jeesite-parent</artifactId>
<version>4.0.6-SNAPSHOT</version> <version>4.0.7-SNAPSHOT</version>
<relativePath>../parent/pom.xml</relativePath> <relativePath>../parent/pom.xml</relativePath>
</parent> </parent>
@@ -76,8 +76,10 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId> <artifactId>maven-war-plugin</artifactId>
<configuration> <configuration>
<packagingExcludes></packagingExcludes> <warSourceExcludes>
<warSourceExcludes></warSourceExcludes> WEB-INF/classes/*.lic,
userfiles/**
</warSourceExcludes>
<webappDirectory>${project.build.directory}/${project.artifactId}</webappDirectory> <webappDirectory>${project.build.directory}/${project.artifactId}</webappDirectory>
<warName>${finalName}</warName> <warName>${finalName}</warName>
<archive> <archive>

View File

@@ -8,8 +8,10 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import com.jeesite.common.entity.Page; import com.jeesite.common.entity.Page;
import com.jeesite.common.lang.DateUtils;
import com.jeesite.common.service.CrudService; import com.jeesite.common.service.CrudService;
import com.jeesite.modules.file.utils.FileUploadUtils; import com.jeesite.modules.file.utils.FileUploadUtils;
import com.jeesite.modules.sys.service.UserService;
import com.jeesite.modules.test.dao.TestDataChildDao; import com.jeesite.modules.test.dao.TestDataChildDao;
import com.jeesite.modules.test.dao.TestDataDao; import com.jeesite.modules.test.dao.TestDataDao;
import com.jeesite.modules.test.entity.TestData; import com.jeesite.modules.test.entity.TestData;
@@ -116,4 +118,12 @@ public class TestDataService extends CrudService<TestDataDao, TestData> {
testDataChildDao.delete(testDataChild); testDataChildDao.delete(testDataChild);
} }
/**
* 任务调度测试testDataService.executeTestTask(userService, 1, 2L, 3F, 4D, 'abc')
*/
public void executeTestTask(UserService userService, Integer i, Long l, Float f, Double d, String s){
System.out.println(DateUtils.getTime() + " 任务执行了~~~ bean: " + userService + ", i: " + i
+ ", l: " + l + ", f: " + f + ", d: " + d + ", s: " + s);
}
} }

View File

@@ -8,6 +8,7 @@ server:
spring: spring:
profiles: profiles:
# 当前激活环境名称,(注意:不可设置为 test 它是单元测试用的环境名称)
active: default active: default
main: main:

View File

@@ -14,12 +14,6 @@ copyrightYear: 2018
#是否演示模式 #是否演示模式
demoMode: false demoMode: false
#是否小程序
miniService: true
#是否小程序
miniConfig: true
#============================# #============================#
#===== Database sttings =====# #===== Database sttings =====#
#============================# #============================#
@@ -108,7 +102,7 @@ jdbc:
# stat: # stat:
# enabled: true # enabled: true
# Redis 配置2.x/3.x # Redis 配置
#redis: #redis:
# enabled: false # enabled: false
# #
@@ -208,8 +202,18 @@ jdbc:
# # 多租户模式SAAS模式专业版 # # 多租户模式SAAS模式专业版
# useCorpModel: false # useCorpModel: false
# 菜单管理
#menu:
# # 根据模块状态去更新相连的菜单状态仅作为微服务时设为false
# updateStatusByModuleStatus: true
# 国际化管理(专业版+
#lang:
# enabled: true
# 任务调度(个人版+ # 任务调度(个人版+
#job: #job:
# enabled: true
# #
# # 是否自动启动任务调度(可关闭) # # 是否自动启动任务调度(可关闭)
# autoStartup: true # autoStartup: true
@@ -222,12 +226,33 @@ jdbc:
# threadCount: 10 # threadCount: 10
# threadPriority: 5 # threadPriority: 5
# #
# # 调度设置集群中每一个实例都必须使用相同的instanceName名称 (区分特定的调度器实例)
# # 每一个instanceId必须不同设置AUTO则自动生成
# scheduler:
# instanceName: JeeSiteScheduler
# instanceId: AUTO
#
# # 任务调度集群设置 # # 任务调度集群设置
# jobStore: # jobStore:
# isClustered: true # isClustered: true
# dataSourceName: job # dataSourceName: job
# clusterCheckinInterval: 1000 # clusterCheckinInterval: 1000
# #
# # 调度日志
# log:
# # 计划调度日志
# scheduler:
# enabled: true
# # 是否只保存错误日志
# errorLevel: true
# # 任务执行日志
# jobDetail:
# enabled: true
# # 是否只保存错误日志
# errorLevel: true
# # 计划触发日志
# trigger:
# enabled: false
#============================# #============================#
#==== Framework settings ====# #==== Framework settings ====#
@@ -265,7 +290,12 @@ jdbc:
# #
# # 登录提交信息安全Key加密用户名、密码、验证码后再提交key设置为3个用逗号分隔 # # 登录提交信息安全Key加密用户名、密码、验证码后再提交key设置为3个用逗号分隔
# secretKey: thinkgem,jeesite,com # secretKey: thinkgem,jeesite,com
# #
# # 记住我密钥设置(设置为空则使用默认)
# rememberMe:
# # 密钥必须通过 com.jeesite.common.shiro.web.RememberMeManager 的main方法生成
# secretKey: ~
#
# # 指定获取客户端IP的Header名称防止IP伪造。指定为空则使用原生方法获取IP。 # # 指定获取客户端IP的Header名称防止IP伪造。指定为空则使用原生方法获取IP。
# remoteAddrHeaderName: X-Forwarded-For # remoteAddrHeaderName: X-Forwarded-For
# #
@@ -314,9 +344,12 @@ jdbc:
# MyBatis 相关 # MyBatis 相关
#mybatis: #mybatis:
# #
# # 扫描基础包设置Aliases、@MyBatisDao,如果多个,用“,”分隔 # # @MyBatisDao、Aliases 扫描基础包,如果多个,用“,”分隔
# scanBasePackage: com.jeesite.modules # scanBasePackage: com.jeesite.modules
# #
# # TypeHandlers 扫描基础包,如果多个,用“,”分隔
# scanTypeHandlersPackage: ~
#
# # Mapper文件刷新线程 # # Mapper文件刷新线程
# mapper: # mapper:
# refresh: # refresh:
@@ -382,6 +415,16 @@ jdbc:
# #
# # 静态文件后缀排除的url路径指定哪些uri路径不进行静态文件过滤。 # # 静态文件后缀排除的url路径指定哪些uri路径不进行静态文件过滤。
# staticFileExcludeUri: /druid/ # staticFileExcludeUri: /druid/
#
# # 自定义正则表达式验证(主键、登录名)
# 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 # 错误页面500.html是否输出错误信息正式环境为提供安全性可设置为false
#error: #error:
@@ -393,6 +436,7 @@ jdbc:
#============================# #============================#
#file: #file:
# enabled: true
# #
# # 文件上传根路径设置路径中不允许包含“userfiles”在指定目录中系统会自动创建userfiles目录如果不设置默认为contextPath路径 # # 文件上传根路径设置路径中不允许包含“userfiles”在指定目录中系统会自动创建userfiles目录如果不设置默认为contextPath路径
## baseDir: D:/jeesite ## baseDir: D:/jeesite