你的位置:首页 > Java教程

[Java教程]UEditor FTP上传


最近在项目中遇到了使用文本编辑器的情况,但是根据项目要求,文本编辑器的图片不能保存在本地服务器上,必须上传到远程文件服务器上,找了众多资料,没有找到答案,最后终于自己反编译了百度的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", ".  ], /* 上传文件格式显示 */  /* 列出指定目录下的图片 */  "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", ".  ] /* 列出的文件类型 */}

 步骤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()) {    storageState.putInfo("url", savePath);    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.xxxx.ueditor.upload;import com.baidu.ueditor.define.BaseState;import com.baidu.ueditor.define.State;import com.xxxx.common.util.FileToFTP;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 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);    }        try    {      FileToFTP t = new FileToFTP();      t.connect("");      if(! t.uploadWithRemoteDir(remoteDir,targetFile)){        return new BaseState(false, 4);      }    }catch (Exception e) {      return new BaseState(false, 4);    }        try    {      if(! keepLocalFile)        targetFile.delete();    }catch(Exception e){          }    state = new BaseState(true);    state.putInfo("size", targetFile.length());    state.putInfo("title", targetFile.getName());    return state; }}

 

到此就完成了UEditor上传FTP服务器的工作了.