UEditor FTP上傳

關於文章中的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

相關文章
相關標籤/搜索