原作者地址:点击打开链接
以下为复制(其中我修改了某些地方标红):
最近在项目中遇到了使用文本编辑器的情况,但是根据项目要求,文本编辑器的图片不能保存在本地服务器上,必须
上传到远程文件服务器上,找了众多资料,没有找到答案,最后终于自己反编译了百度的JAR包,完完整整的研究了一
次逻辑,终于实现了该功能,这里分享一下.以免后来者枉费时间.
步骤1.在自己的工程中实现一个ActionEnter类
package com.xxxx.ueditor;
import com.baidu.ueditor.ConfigManager;
import com.baidu.ueditor.define.ActionMap;
import com.baidu.ueditor.define.BaseState;
import com.baidu.ueditor.define.State;
import com.baidu.ueditor.hunter.FileManager;
import com.baidu.ueditor.hunter.ImageHunter;
import com.xxxx.ueditor.upload.Uploader;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
public class ActionEnter
{
//日志器
protected Logger log = Logger.getLogger(ActionEnter.class);
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 = request;
this.rootPath = rootPath;
this.actionType = request.getParameter("action");
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, 401).toJSONString();
}
return callbackName + "(" + invoke() + ");";
}
String response = invoke();
log.debug(response);
return response;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public String invoke()
{
if ((this.actionType == null) || (!ActionMap.mapping.containsKey(this.actionType))) {
return new BaseState(false, 101).toJSONString();
}
if ((this.configManager == null) || (!this.configManager.valid())) {
return new BaseState(false, 102).toJSONString();
}
State state = null;
int actionCode = ActionMap.getType(this.actionType);
Map conf = null;
switch (actionCode)
{
case 0:
return this.configManager.getAllConfig().toString();
case 1:
case 2:
case 3:
case 4:
conf = this.configManager.getConfig(actionCode);
conf.put("useFtpUpload",this.configManager.getAllConfig().getString("useFtpUpload"));
conf.put("keepLocalFile",this.configManager.getAllConfig().getString("keepLocalFile"));
state = new Uploader(this.request, conf).doExec();
break;
case 5:
conf = this.configManager.getConfig(actionCode);
String[] list = this.request.getParameterValues((String)conf.get("fieldName"));
state = new ImageHunter(conf).capture(list);
break;
case 6:
case 7:
conf = this.configManager.getConfig(actionCode);
int start = getStartIndex();
state = new FileManager(conf).listFile(start);
}
return state.toJSONString();
}
public int getStartIndex()
{
String start = this.request.getParameter("start");
try
{
return Integer.parseInt(start); } catch (Exception e) {
}
return 0;
}
public boolean validCallbackName(String name)
{
if (name.matches("^[a-zA-Z_]+[\\w0-9_]*$")) {
return true;
}
return false;
}
}
这个类是反编译的原有百度的代码,只加入了两行读取配置文件的内容:
conf.put("useFtpUpload",this.configManager.getAllConfig().getString("useFtpUpload")); //是否使用
FTP上传
conf.put("keepLocalFile",this.configManager.getAllConfig().getString("keepLocalFile")); //是否上传
后保留本地服务器文件
步骤2.在ueditor目录下的jsp目录下,找到controller.jsp,修改ActionEnter的实现
<%@ page language="java" contentType="text/html; charset=UTF-8"
import="com.xxxx.ueditor.ActionEnter"
pageEncoding="UTF-8"%>
<%
request.setCharacterEncoding( "utf-8" );
response.setHeader("Content-Type" , "text/html");
String rootPath = application.getRealPath( "/" );
out.write( new ActionEnter( request, rootPath ).exec() );
%>
只修改一处import改为刚才创建的ActionEnter即可
步骤3.修改controller.jsp同级目录下的config.json,加入之前新增的两个配置项,并且修改prefix为文件服务器的域名
/* 前后端通信相关的配置,注释只允许使用多行方式 */
{
"useFtpUpload": "true", /* 是否使用FTP上传 */
"keepLocalFile": "true", /* 使用FTP上传后本地服务器是否保存 */
/* 上传图片配置项 */
"imageActionName": "uploadimage", /* 执行上传图片的action名称 */
"imageFieldName": "upfile", /* 提交的图片表单名称 */
"imageMaxSize": 3145728, /* 上传大小限制,单位B */
"imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 上传图片格式显示 */
"imageCompressEnable": true, /* 是否压缩图片,默认是true */
"imageCompressBorder": 1600, /* 图片压缩最长边限制 */
"imageInsertAlign": "none", /* 插入的图片浮动方式 */
"imageUrlPrefix": "http://localhost:8081/", /* 图片访问路径前缀 */
"imagePathFormat": "/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保
存路径和文件名格式 */
/* {filename} 会替换成原文件名,配置这项需要注意中文乱码问题 */
/* {rand:6} 会替换成随机数,后面的数字是随机数的位数 */
/* {time} 会替换成时间戳 */
/* {yyyy} 会替换成四位年份 */
/* {yy} 会替换成两位年份 */
/* {mm} 会替换成两位月份 */
/* {dd} 会替换成两位日期 */
/* {hh} 会替换成两位小时 */
/* {ii} 会替换成两位分钟 */
/* {ss} 会替换成两位秒 */
/* 非法字符 \ : * ? " < > | */
/* 具请体看线上文档: fex.baidu.com/ueditor/#use-
format_upload_filename */
/* 涂鸦图片上传配置项 */
"scrawlActionName": "uploadscrawl", /* 执行上传涂鸦的action名称 */
"scrawlFieldName": "upfile", /* 提交的图片表单名称 */
"scrawlPathFormat": "/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保
存路径和文件名格式 */
"scrawlMaxSize": 2048000, /* 上传大小限制,单位B */
"scrawlUrlPrefix": "", /* 图片访问路径前缀 */
"scrawlInsertAlign": "none",
/* 截图工具上传 */
"snapscreenActionName": "uploadimage", /* 执行上传截图的action名称 */
"snapscreenPathFormat": "/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定
义保存路径和文件名格式 */
"snapscreenUrlPrefix": "", /* 图片访问路径前缀 */
"snapscreenInsertAlign": "none", /* 插入的图片浮动方式 */
/* 抓取远程图片配置 */
"catcherLocalDomain": ["127.0.0.1", "localhost", "img.baidu.com"],
"catcherActionName": "catchimage", /* 执行抓取远程图片的action名称 */
"catcherFieldName": "source", /* 提交的图片列表表单名称 */
"catcherPathFormat": "/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义
保存路径和文件名格式 */
"catcherUrlPrefix": "", /* 图片访问路径前缀 */
"catcherMaxSize": 2048000, /* 上传大小限制,单位B */
"catcherAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 抓取图片格式显示 */
/* 上传视频配置 */
"videoActionName": "uploadvideo", /* 执行上传视频的action名称 */
"videoFieldName": "upfile", /* 提交的视频表单名称 */
"videoPathFormat": "/upload/video/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保
存路径和文件名格式 */
"videoUrlPrefix": "http://localhost:8081/", /* 视频访问路径前缀 */
"videoMaxSize": 102400000, /* 上传大小限制,单位B,默认100MB */
"videoAllowFiles": [
".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid"], /* 上传视频格式显
示 */
/* 上传文件配置 */
"fileActionName": "uploadfile", /* controller里,执行上传视频的action名称 */
"fileFieldName": "upfile", /* 提交的文件表单名称 */
"filePathFormat": "/upload/file/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存
路径和文件名格式 */
"fileUrlPrefix": "http://localhost:8081/", /* 文件访问路径前缀 */
"fileMaxSize": 51200000, /* 上传大小限制,单位B,默认50MB */
"fileAllowFiles": [
".png", ".jpg", ".jpeg", ".gif", ".bmp",
".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
], /* 上传文件格式显示 */
/* 列出指定目录下的图片 */
"imageManagerActionName": "listimage", /* 执行图片管理的action名称 */
"imageManagerListPath": "/upload/image/", /* 指定要列出图片的目录 */
"imageManagerListSize": 20, /* 每次列出文件数量 */
"imageManagerUrlPrefix": "http://localhost:8081/", /* 图片访问路径前缀 */
"imageManagerInsertAlign": "none", /* 插入的图片浮动方式 */
"imageManagerAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 列出的文件类型 */
/* 列出指定目录下的文件 */
"fileManagerActionName": "listfile", /* 执行文件管理的action名称 */
"fileManagerListPath": "/upload/file/", /* 指定要列出文件的目录 */
"fileManagerUrlPrefix": "http://localhost:8081/", /* 文件访问路径前缀 */
"fileManagerListSize": 20, /* 每次列出文件数量 */
"fileManagerAllowFiles": [
".png", ".jpg", ".jpeg", ".gif", ".bmp",
".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
] /* 列出的文件类型 */
}
步骤4.创建一个Uploader类,其他代码反编译百度,加入红色内容,通过配置文件配置是上传本地服务器还是远程FTP服务器
package com.xxxx.ueditor.upload;
import com.baidu.ueditor.define.State;
import com.baidu.ueditor.upload.Base64Uploader;
import com.baidu.ueditor.upload.BinaryUploader;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
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;
//保留原有逻辑,在json.config中加入是否使用FTP上传配置项
if ("true".equals(this.conf.get("isBase64")))
state = Base64Uploader.save(this.request.getParameter(filedName),
this.conf);
else {
if("true".equals(this.conf.get("useFtpUpload")))
state = FtpUploader.save(request, conf);
else
state = BinaryUploader.save(this.request, this.conf);
}
return state;
}
}
步骤5.创建一个FtpUploader类,内容是反编译的BinaryUploader,稍作修改,保证在远程服务器上创建路径和本地服务器的一致
package com.xxxx.ueditor.upload;
import com.baidu.ueditor.PathFormat;
import com.baidu.ueditor.define.BaseState;
import com.baidu.ueditor.define.FileType;
import com.baidu.ueditor.define.State;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
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;
public class FtpUploader
{
public static final State save(HttpServletRequest request, Map<String, Object> conf)
{
FileItemStream fileStream = null;
boolean isAjaxUpload = request.getHeader("X_Requested_With") != null;
if (!ServletFileUpload.isMultipartContent(request)) {
return new BaseState(false, 5);
}
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) {
return new BaseState(false, 7);
}
String savePath = (String)conf.get("savePath");
String originFileName = fileStream.getName();
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, 8);
}
savePath = PathFormat.parse(savePath, originFileName);
String remoteDir = "";
int pos = savePath.lastIndexOf("/");
if(pos > -1){
remoteDir = savePath.substring(0,pos + 1);
}
String physicalPath = (String)conf.get("rootPath") + savePath;
boolean keepLocalFile = "false".equals(conf.get("keepLocalFile")) ? false : true;
InputStream is = fileStream.openStream();
State storageState = StorageManager.saveFtpFileByInputStream(is, remoteDir,
physicalPath, maxSize, keepLocalFile);
is.close();
if (storageState.isSuccess()) {
<span style="color:#ff0000;"> //storageState.putInfo("url", savePath);这里返回地址为了返回的是,ftp服务器上的地址,所以这里注释掉</span>
storageState.putInfo("type", suffix);
storageState.putInfo("original", originFileName + suffix);
}
return storageState;
} catch (FileUploadException e) {
return new BaseState(false, 6);
} catch (IOException localIOException) {
}
return new BaseState(false, 4);
}
@SuppressWarnings("rawtypes")
private static boolean validType(String type, String[] allowTypes) {
List list = Arrays.asList(allowTypes);
return list.contains(type);
}
}
步骤6.创建一个StorageManager类,内容反编译百度原有内容,加入几个FTP相关函数
package com.witontek.mobilehospital.ueditor;
import com.baidu.ueditor.define.BaseState;
import com.baidu.ueditor.define.State;
import com.witontek.mobilehospital.tools.FileUtil;
import com.witontek.mobilehospital.tools.config.CommProperties;
import com.witontek.mobilehospital.tools.random.UUIDGenerator;
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 org.apache.commons.io.FileUtils;
public class StorageManager
{
public static final int BUFFER_SIZE = 8192;
public static State saveBinaryFile(byte[] data, String path)
{
File file = new File(path);
State state = valid(file);
if (!state.isSuccess()) {
return state;
}
try
{
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(file));
bos.write(data);
bos.flush();
bos.close();
} catch (IOException ioe) {
return new BaseState(false, 4);
}
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, 8192);
try
{
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(tmpFile), 8192);
int count = 0;
while ((count = bis.read(dataBuf)) != -1) {
bos.write(dataBuf, 0, count);
}
bos.flush();
bos.close();
if (tmpFile.length() > maxSize) {
tmpFile.delete();
return new BaseState(false, 1);
}
state = saveTmpFile(tmpFile, path);
if (!state.isSuccess()) {
tmpFile.delete();
}
return state;
}
catch (IOException localIOException) {
}
return new BaseState(false, 4);
}
public static State saveFileByInputStream(InputStream is, String path) {
State state = null;
File tmpFile = getTmpFile();
byte[] dataBuf = new byte[2048];
BufferedInputStream bis = new BufferedInputStream(is, 8192);
try
{
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(tmpFile), 8192);
int count = 0;
while ((count = bis.read(dataBuf)) != -1) {
bos.write(dataBuf, 0, count);
}
bos.flush();
bos.close();
state = saveTmpFile(tmpFile, path);
if (!state.isSuccess()) {
tmpFile.delete();
}
return state;
} catch (IOException localIOException) {
}
return new BaseState(false, 4);
}
private static File getTmpFile() {
File tmpDir = FileUtils.getTempDirectory();
double d = Math.random() * 10000.0D;
String tmpFileName = String.valueOf(d).replace(".", "");
return new File(tmpDir, tmpFileName);
}
private static State saveTmpFile(File tmpFile, String path) {
State state = null;
File targetFile = new File(path);
if (targetFile.canWrite())
return new BaseState(false, 2);
try
{
FileUtils.moveFile(tmpFile, targetFile);
} catch (IOException e) {
return new BaseState(false, 4);
}
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, 3);
}
if (!parentPath.canWrite()) {
return new BaseState(false, 2);
}
return new BaseState(true);
}
/**
* 上传FTP文件
* @param is
* @param path
* @param maxSize
* @return
*/
public static State saveFtpFileByInputStream(InputStream is, String remoteDir, String path, long maxSize,boolean keepLocalFile)
{
State state = null;
File tmpFile = getTmpFile();
byte[] dataBuf = new byte[2048];
BufferedInputStream bis = new BufferedInputStream(is, 8192);
try
{
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(tmpFile), 8192);
int count = 0;
while ((count = bis.read(dataBuf)) != -1) {
bos.write(dataBuf, 0, count);
}
bos.flush();
bos.close();
if (tmpFile.length() > maxSize) {
tmpFile.delete();
return new BaseState(false, 1);
}
state = saveFtpTmpFile(tmpFile, remoteDir, path, keepLocalFile);
if (!state.isSuccess()) {
tmpFile.delete();
}
return state;
}
catch (IOException localIOException) {
}
return new BaseState(false, 4);
}
private static String picturePath = CommProperties.getProp("NEWS")+"/picture/";
private static State saveFtpTmpFile(File tmpFile, String remoteDir, String path,boolean keepLocalFile) {
State state = null;
File targetFile = new File(path);
if (targetFile.canWrite())
return new BaseState(false, 2);
try
{
FileUtils.moveFile(tmpFile, targetFile);
} catch (IOException e) {
return new BaseState(false, 4);
}<span style="color:#ff0000;">//这里增加自己的上传到ftp服务器的代码</span>
<span style="color:#ff0000;"> double d = Math.random();
String fileName = UUIDGenerator.getUUID()+ d + ".jpg";
String ftpPath ;
try
{
File file = targetFile;
if (file != null) {
FileUtil.ftpUpload(file, fileName, "/news/ueditor");
}
ftpPath = picturePath + "ueditor/" + fileName;
}catch (Exception e) {
return new BaseState(false, 4);
}</span>
try
{
if(! keepLocalFile)
targetFile.delete();
}catch(Exception e){
}
state = new BaseState(true);
state.putInfo("size", targetFile.length());
state.putInfo("title",fileName);
<span style="color:#ff0000;">state.putInfo("url", ftpPath);//这里返回的是ftp服务器地址</span>
return state;
}
}
7.ftpUpload 上传到ftp服务器的代码
<span style="color:#ff0000;">/***
* ftp图片上传
*
* @param srcFile文件流
* @param destFileName上传后文件名
* @param destFoldName上传后文件包名
*/
public static void ftpUpload(File srcFile, String fileName, String foldName) {
FTPClient ftpClient = new FTPClient();
FileInputStream fis = null;
try {
ftpClient.connect(server);
ftpClient.login(uname, pwd);
fis = new FileInputStream(srcFile);
// 设置上传目录
ftpClient.changeWorkingDirectory(foldName);
ftpClient.setBufferSize(1024);
ftpClient.enterLocalPassiveMode();
if (FTPReply.isPositiveCompletion(ftpClient.sendCommand("OPTS UTF8", "ON"))) {
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码,否则就使用本地编码(GBK).
LOCAL_CHARSET = "UTF-8";
}
ftpClient.setControlEncoding(LOCAL_CHARSET);
fileName = new String(fileName.getBytes(LOCAL_CHARSET),SERVER_CHARSET);
// 设置文件类型(二进制)
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.storeFile(fileName, fis);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
ftpClient.disconnect();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("关闭FTP连接发生异常!", e);
}
}
}</span>
到此就完成了UEditor上传FTP服务器的工作了.