關於文章中的FTP上傳沒有附上代碼,很差意思,由於我以爲FTP上傳的類處處都是,而我用的是公司內部的FTP的API,不太方便暴露,因此就省略了~請見諒,請你們自行選擇FTP上傳類吧html
最近在項目中遇到了使用文本編輯器的狀況,可是根據項目要求,文本編輯器的圖片不能保存在本地服務器上,必須上傳到遠程文件服務器上,找了衆多資料,沒有找到答案,最後終於本身反編譯了百度的JAR包,完完整整的研究了一次邏輯,終於實現了該功能,這裏分享一下.以避免後來者枉費時間.java
步驟1.在本身的工程中實現一個ActionEnter類web
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; } }
這個類是反編譯的原有百度的代碼,只加入了兩行讀取配置文件的內容:apache
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便可json
步驟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()) { 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相關函數app
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服務器的工做了.dom