将ueditor移动到module-core模块下

This commit is contained in:
thinkgem
2023-05-12 12:32:39 +08:00
parent ec36c14f9d
commit 0f7267ce19
35 changed files with 1477 additions and 1324 deletions

View File

@@ -0,0 +1,118 @@
package com.jeesite.common.ueditor;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.jeesite.common.config.Global;
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.State;
import com.jeesite.common.ueditor.hunter.FileManager;
import com.jeesite.common.ueditor.hunter.ImageHunter;
import com.jeesite.common.ueditor.upload.Uploader;
public class ActionEnter {
private HttpServletRequest request = null;
private String rootPath = null;
private String contextPath = null;
private String actionType = null;
private ConfigManager configManager = null;
public ActionEnter(HttpServletRequest request, String rootPath) {
this(request, rootPath, request.getParameter("action"));
}
public ActionEnter(HttpServletRequest request, String rootPath, String actionType) {
this.request = request;
this.rootPath = rootPath;
this.actionType = actionType;
this.contextPath = request.getContextPath();
this.configManager = ConfigManager.getInstance(this.rootPath, this.contextPath, request.getRequestURI());
}
public String exec() {
String callbackName = this.request.getParameter("callback");
if (callbackName != null) {
if (!validCallbackName(callbackName)) {
return new BaseState(false, AppInfo.ILLEGAL).toJSONString();
}
return callbackName + "(" + this.invoke() + ");";
} else {
return this.invoke();
}
}
public String invoke() {
if (actionType == null || !ActionMap.mapping.containsKey(actionType)) {
return new BaseState(false, AppInfo.INVALID_ACTION).toJSONString();
}
if (this.configManager == null || !this.configManager.valid()) {
return new BaseState(false, AppInfo.CONFIG_ERROR).toJSONString();
}
State state = null;
int actionCode = ActionMap.getType(this.actionType);
Map<String, Object> conf = null;
switch (actionCode) {
case ActionMap.CONFIG:
return this.configManager.getAllConfig().toString();
case ActionMap.UPLOAD_IMAGE:
case ActionMap.UPLOAD_SCRAWL:
case ActionMap.UPLOAD_VIDEO:
case ActionMap.UPLOAD_FILE:
if (Global.isDemoMode()) {
state = new BaseState(false, "演示模式,不允许操作!");
break;
}
conf = this.configManager.getConfig(actionCode);
state = new Uploader(request, conf).doExec();
break;
case ActionMap.CATCH_IMAGE:
if (Global.isDemoMode()) {
state = new BaseState(false, "演示模式,不允许操作!");
break;
}
conf = configManager.getConfig(actionCode);
String[] list = this.request.getParameterValues((String) conf.get("fieldName"));
state = new ImageHunter(request, conf).capture(list);
break;
case ActionMap.LIST_IMAGE:
case ActionMap.LIST_FILE:
if (Global.isDemoMode()) {
state = new BaseState(false, "演示模式,不允许操作!");
break;
}
conf = configManager.getConfig(actionCode);
int start = this.getStartIndex();
state = new FileManager(conf).listFile(this.request, start);
break;
}
return state.toJSONString();
}
public int getStartIndex() {
String start = this.request.getParameter("start");
try {
return Integer.parseInt(start);
} catch (Exception e) {
return 0;
}
}
/**
* callback参数验证
*/
public boolean validCallbackName(String name) {
if (name.matches("^[a-zA-Z_]+[\\w0-9_]*$")) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,142 @@
package com.jeesite.common.ueditor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jeesite.common.io.ResourceUtils;
import com.jeesite.common.ueditor.define.ActionMap;
/**
* 配置管理器
*
* @author hancong03@baidu.com
*/
public final class ConfigManager {
private final String rootPath;
private static final String configFileName = "config/ueditor.json";
private JSONObject jsonConfig = null;
// 涂鸦上传filename定义
private final static String SCRAWL_FILE_NAME = "scrawl";
// 远程图片抓取filename定义
private final static String REMOTE_FILE_NAME = "remote";
/*
* 通过一个给定的路径构建一个配置管理器, 该管理器要求地址路径所在目录下必须存在config.properties文件
*/
private ConfigManager(String rootPath, String contextPath, String uri) throws FileNotFoundException, IOException {
rootPath = rootPath.replace("\\", "/");
this.rootPath = rootPath;
this.initEnv();
}
/**
* 配置管理器构造工厂
*
* @param rootPath 服务器根路径
* @param contextPath 服务器所在项目路径
* @param uri 当前访问的uri
* @return 配置管理器实例或者null
*/
public static ConfigManager getInstance(String rootPath, String contextPath, String uri) {
try {
return new ConfigManager(rootPath, contextPath, uri);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 验证配置文件加载是否正确
public boolean valid() {
return this.jsonConfig != null;
}
public JSONObject getAllConfig() {
return this.jsonConfig;
}
public Map<String, Object> getConfig(int type) {
Map<String, Object> conf = new HashMap<String, Object>();
String savePath = null;
switch (type) {
case ActionMap.UPLOAD_FILE:
conf.put("isBase64", "false");
conf.put("maxSize", this.jsonConfig.getLong("fileMaxSize"));
conf.put("allowFiles", this.getArray("fileAllowFiles"));
conf.put("fieldName", this.jsonConfig.getString("fileFieldName"));
savePath = this.jsonConfig.getString("filePathFormat");
break;
case ActionMap.UPLOAD_IMAGE:
conf.put("isBase64", "false");
conf.put("maxSize", this.jsonConfig.getLong("imageMaxSize"));
conf.put("allowFiles", this.getArray("imageAllowFiles"));
conf.put("fieldName", this.jsonConfig.getString("imageFieldName"));
conf.put("imageCompressEnable", this.jsonConfig.getBoolean("imageCompressEnable"));
conf.put("imageCompressBorder", this.jsonConfig.getInteger("imageCompressBorder"));
savePath = this.jsonConfig.getString("imagePathFormat");
break;
case ActionMap.UPLOAD_VIDEO:
conf.put("maxSize", this.jsonConfig.getLong("videoMaxSize"));
conf.put("allowFiles", this.getArray("videoAllowFiles"));
conf.put("fieldName", this.jsonConfig.getString("videoFieldName"));
savePath = this.jsonConfig.getString("videoPathFormat");
break;
case ActionMap.UPLOAD_SCRAWL:
conf.put("filename", ConfigManager.SCRAWL_FILE_NAME);
conf.put("maxSize", this.jsonConfig.getLong("scrawlMaxSize"));
conf.put("fieldName", this.jsonConfig.getString("scrawlFieldName"));
conf.put("isBase64", "true");
savePath = this.jsonConfig.getString("scrawlPathFormat");
break;
case ActionMap.CATCH_IMAGE:
conf.put("filename", ConfigManager.REMOTE_FILE_NAME);
conf.put("filter", this.getArray("catcherLocalDomain"));
conf.put("maxSize", this.jsonConfig.getLong("catcherMaxSize"));
conf.put("allowFiles", this.getArray("catcherAllowFiles"));
conf.put("fieldName", this.jsonConfig.getString("catcherFieldName") + "[]");
savePath = this.jsonConfig.getString("catcherPathFormat");
break;
case ActionMap.LIST_IMAGE:
conf.put("allowFiles", this.getArray("imageManagerAllowFiles"));
conf.put("dir", this.jsonConfig.getString("imageManagerListPath"));
conf.put("count", this.jsonConfig.getInteger("imageManagerListSize"));
break;
case ActionMap.LIST_FILE:
conf.put("allowFiles", this.getArray("fileManagerAllowFiles"));
conf.put("dir", this.jsonConfig.getString("fileManagerListPath"));
conf.put("count", this.jsonConfig.getInteger("fileManagerListSize"));
break;
}
conf.put("actionCode", type);
conf.put("savePath", savePath);
conf.put("rootPath", this.rootPath);
return conf;
}
private void initEnv() {
String configContent = ResourceUtils.getResourceFileContent(
ConfigManager.configFileName).replaceAll("/\\*[\\s\\S]*?\\*/", "");
try {
JSONObject jsonConfig = JSONObject.parseObject(configContent);
this.jsonConfig = jsonConfig;
} catch (Exception e) {
this.jsonConfig = null;
}
}
private String[] getArray(String key) {
JSONArray jsonArray = this.jsonConfig.getJSONArray(key);
String[] result = new String[jsonArray.size()];
for (int i = 0, len = jsonArray.size(); i < len; i++) {
result[i] = jsonArray.getString(i);
}
return result;
}
}

View File

@@ -0,0 +1,18 @@
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,145 @@
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,43 @@
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,82 @@
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,28 @@
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,90 @@
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,18 @@
package com.jeesite.common.ueditor.define;
/**
* 处理状态接口
*
* @author hancong03@baidu.com
*/
public interface State {
boolean isSuccess();
void putInfo(String name, String val);
void putInfo(String name, long val);
String toJSONString();
}

View File

@@ -0,0 +1,98 @@
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(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,125 @@
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 org.apache.commons.io.IOUtils;
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);
} finally {
if (connection != null) {
IOUtils.close(connection);
}
}
}
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,49 @@
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", "");
// UEditor上传文件成功后调用事件
StorageManager.uploadFileSuccess(physicalPath, storageState);
}
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,142 @@
package com.jeesite.common.ueditor.upload;
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.servlet.http.HttpServletRequest;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import com.jeesite.common.image.ImageUtils;
import com.jeesite.common.io.FileUtils;
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;
public class BinaryUploader {
public static final State save(HttpServletRequest request, Map<String, Object> conf) {
String contentType = request.getContentType();
if (!("POST".equals(request.getMethod()) && contentType != null
&& contentType.startsWith("multipart/"))) {
return new BaseState(false, AppInfo.NOT_MULTIPART_CONTENT);
}
try {
MultipartFile file = null;
if (request instanceof MultipartHttpServletRequest) {
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
Iterator<String> it = multiRequest.getFileNames();
while (it.hasNext()) {
MultipartFile f = multiRequest.getFile(it.next());
if (f != null && !f.isEmpty() && f.getOriginalFilename() != null) {
file = f;
}
break;
}
}
if (file == null) {
return new BaseState(false, AppInfo.NOTFOUND_UPLOAD_DATA);
}
String savePath = (String) conf.get("savePath");
String originFileName = file.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 = null;
State storageState = null;
try {
is = file.getInputStream();
storageState = StorageManager.saveFileByInputStream(is, physicalPath, maxSize);
} finally {
if (is != null) {
is.close();
}
}
if (storageState != null && 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 maxWidth = (Integer) conf.get("imageCompressBorder");
ImageUtils.thumbnails(new File(physicalPath), maxWidth, -1, null);
}
}
// 上传成功后 转换格式 按照新的视频格式 返回前台 ThinkGem
else if (actionCode == ActionMap.UPLOAD_VIDEO) {
final VideoUtils v = new VideoUtils(physicalPath);
// 先截图
if (v.cutPic()) {
// 开启进程,在转换视频文件
Thread thread = new Thread("video-convert") {
@Override
public void run() {
try {
Thread.sleep(5000);
v.convert();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.setDaemon(true);
thread.start();
storageState.putInfo("url", ctx + PathFormat.format(savePath) + "." + v.getOutputFileExtension());
storageState.putInfo("type", "." + v.getOutputFileExtension());
storageState.putInfo("original", originFileName + "." + v.getInputFileExtension());
// Ueditor编辑器上传文件完成后调用事件
StorageManager.uploadFileSuccess(physicalPath, storageState);
return storageState;
}
}
storageState.putInfo("url", ctx + PathFormat.format(savePath));
storageState.putInfo("type", suffix);
storageState.putInfo("original", originFileName + suffix);
// UEditor上传文件成功后调用事件
StorageManager.uploadFileSuccess(physicalPath, storageState);
}
return storageState;
} 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,205 @@
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.IdGen;
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 = new File(System.getProperty("java.io.tmpdir"));
return new File(tmpDir, IdGen.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);
}
/**
* UEditor上传文件成功后调用事件
*
* @param physicalPath 上传文件实际路径
* @param storageState url 返回到客户端的文件访问地址
*/
public static void uploadFileSuccess(String physicalPath, State storageState) {
}
}

View File

@@ -0,0 +1,30 @@
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() {
State state = null;
String filedName = (String) this.conf.get("fieldName");
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

@@ -0,0 +1,43 @@
/**
* Copyright (c) 2013-Now http://jeesite.com All rights reserved.
* No deletion without permission, or be held responsible to law.
*/
package com.jeesite.modules.file.web;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.jeesite.common.config.Global;
import com.jeesite.common.ueditor.ActionEnter;
import com.jeesite.common.web.BaseController;
/**
* UEditor Controller
* @author ThinkGem
* @version 2019-10-3
*/
@Controller
@RequestMapping(value = "${adminPath}/file/ueditor")
@ConditionalOnProperty(name={"file.enabled","web.core.enabled"}, havingValue="true", matchIfMissing=true)
public class UeditorController extends BaseController {
@RequestMapping(value = "")
@ResponseBody
public String upload(HttpServletRequest request, HttpServletResponse response) {
return upload(null, request, response);
}
@RequestMapping(value = "{action}")
@ResponseBody
public String upload(@PathVariable String action, HttpServletRequest request, HttpServletResponse response) {
String rootPath = Global.getUserfilesBaseDir(null);
return new ActionEnter(request, rootPath, action).exec();
}
}