[ExtJS]使用JSP上傳檔案圖片-WYSIWYG所視即所得網頁編輯器外掛 with CKEditor

承前一篇使用Servlet上傳檔案,此篇改寫Servlet使用JSP來上傳圖片、Flash或檔案,取得設定檔部份由web.xml設定改成讀取外部properties設定檔,在前端javascript部份只需要修改CKConfig裡的上傳使用的三個參數就可以了。

          filebrowserUploadUrl : 'CKEditorUpload.jsp?Type=File',   
          filebrowserImageUploadUrl : 'CKEditorUpload.jsp?Type=Image',   
          filebrowserFlashUploadUrl : 'CKEditorUpload.jsp?Type=Flash',

CKEditorJSP.png

CKEditorJSP-ImageUpload3.png

CKEditorJSP-ImageUpload.png

CKEditorJSP-ImageUpload2.png




原始碼設定部份:

init.properties

baseDir=/UserFiles/

enabled=true
AllowedExtensionsFile=
DeniedExtensionsFile=html|htm|php|php2|php3|php4|php5|phtml|pwml|inc|asp|aspx|ascx|jsp|cfm|cfc|pl|bat|exe|com|dll|vbs|js|reg|cgi|htaccess|asis|ftl
AllowedExtensionsImage=jpg|gif|jpeg|png|bmp
DeniedExtensionsImage=
AllowedExtensionsFlashs=wf|fla
DeniedExtensionsFlash=

CKEditorUpload.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%><%!private org.apache.log4j.Logger logger = org.apache.log4j.Logger
            .getLogger(this.getClass());
    private static String baseDir;// CKEditor上傳檔案存放的目錄
    private static boolean debug = false;// 是否debug模式
    private static boolean enabled = false;
    private static java.util.Hashtable<String, java.util.ArrayList<String>> allowedExtensions;//可上傳的副檔名
    private static java.util.Hashtable<String, java.util.ArrayList<String>> deniedExtensions;//不可上傳的副檔名
    private static java.text.SimpleDateFormat dirFormatter;// 目錄格式yyyMM
    private static java.text.SimpleDateFormat fileFormatter;// 文件格式yyyyMMddHHmmssSSS
    private static java.util.Properties prof = null;

    //初始化
    public void init() throws ServletException {
        if (prof == null) {
            try {
                prof = yku.yslifes.PropertiesWithStream.loadInit();
            } catch (java.io.IOException e) {
                throw new ServletException("無法取得init.properties資料");
            }
        }

        //debug mode?
        logger.debug("---- SimpleUploaderServlet initialization started ----");
        // 目錄及文件的命名格式
        dirFormatter = new java.text.SimpleDateFormat("yyyyMM");
        fileFormatter = new java.text.SimpleDateFormat("yyyyMMddHHmmssSSS");
        // 存放檔案的根目錄
        baseDir = prof.getProperty("baseDir");
        // 是否可上傳檔案
        enabled = (new Boolean(prof.getProperty("enabled"))).booleanValue();
        if (baseDir == null)
            baseDir = "/UserFiles/";
        String realBaseDir = getServletContext().getRealPath(baseDir);
        java.io.File baseFile = new java.io.File(realBaseDir);
        if (!baseFile.exists()) {
            baseFile.mkdirs();
        }
        // 黑名單及白名單,可上傳之副檔名
        allowedExtensions = new java.util.Hashtable<String, java.util.ArrayList<String>>(
                3);
        deniedExtensions = new java.util.Hashtable<String, java.util.ArrayList<String>>(
                3);
        // 
        allowedExtensions.put("File",
                stringToArrayList(prof.getProperty("AllowedExtensionsFile")));
        deniedExtensions.put("File",
                stringToArrayList(prof.getProperty("DeniedExtensionsFile")));
        allowedExtensions.put("Image",
                stringToArrayList(prof.getProperty("AllowedExtensionsImage")));
        deniedExtensions.put("Image",
                stringToArrayList(prof.getProperty("DeniedExtensionsImage")));
        allowedExtensions.put("Flash",
                stringToArrayList(prof.getProperty("AllowedExtensionsFlash")));
        deniedExtensions.put("Flash",
                stringToArrayList(prof.getProperty("DeniedExtensionsFlash")));
        logger.debug("---- SimpleUploaderServlet initialization completed ----\r\n");

    }

    /**
     * 取得檔案檔名
     */
    private static String getNameWithoutExtension(String fileName) {
        return fileName.substring(0, fileName.lastIndexOf("."));
    }

    /**
     * 取得檔案副檔名
     */
    private String getExtension(String fileName) {
        return fileName.substring(fileName.lastIndexOf(".") + 1);
    }

    /**
     * 字串轉換成ArrayList
     */
    private java.util.ArrayList<String> stringToArrayList(String str) {
        logger.info(str);
        java.util.ArrayList<String> tmp = new java.util.ArrayList<String>();
        if (str != null) {
            String[] strArr = str.split("\\|");

            if (str.length() > 0) {
                for (int i = 0; i < strArr.length; ++i) {
                    logger.debug(i + " - " + strArr[i]);
                    tmp.add(strArr[i].toLowerCase());
                }
            }
        }
        return tmp;
    }

    /**
     * 判斷是否為可上傳檔案
     */
    private boolean extIsAllowed(String fileType, String ext) {
        ext = ext.toLowerCase();
        java.util.ArrayList<String> allowList = allowedExtensions.get(fileType);
        java.util.ArrayList<String> denyList = deniedExtensions.get(fileType);
        if (allowList.size() == 0) {
            if (denyList.contains(ext)) {
                return false;
            } else {
                return true;
            }
        }
        if (denyList.size() == 0) {
            if (allowList.contains(ext)) {
                return true;
            } else {
                return false;
            }
        }
        return false;
    }%>
<%
    response.setContentType("text/html; charset=UTF-8");
    response.setHeader("Cache-Control", "no-cache");
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>File Upload</title>
</head>
<body>
<%
    logger.debug("--- BEGIN DOPOST ---");
    //java.io.PrintWriter out = response.getWriter();
    // File/Image/Flash
    String typeStr = request.getParameter("Type");
    if (typeStr == null) {
        typeStr = "File";
    }
    logger.info(typeStr);
    // 取得目前時間
    java.util.Date dNow = new java.util.Date();
    // 要上傳的目錄
    String currentPath = baseDir + typeStr + "/"
            + dirFormatter.format(dNow);
    // Web的實際位置
    String currentDirPath = getServletContext()
            .getRealPath(currentPath);
    // 判斷檔案是否存在,不存在時則建立
    java.io.File dirTest = new java.io.File(currentDirPath);
    if (!dirTest.exists()) {
        dirTest.mkdirs();
    }
    // 檔案上傳後的目錄位置http://xxx.xxx.xx/123/
    currentPath = request.getContextPath() + currentPath;
    logger.info(currentDirPath);

    String newName = "";
    String fileUrl = "";
    String ErrorMsg = "";
    if (enabled) {
        // 使用Apache Common的fileupload上傳
        org.apache.commons.fileupload.FileItemFactory factory = new org.apache.commons.fileupload.disk.DiskFileItemFactory();
        org.apache.commons.fileupload.servlet.ServletFileUpload upload = new org.apache.commons.fileupload.servlet.ServletFileUpload(
                factory);
        try {
            java.util.List items = upload.parseRequest(request);
            //存放上傳的欄位名稱
            java.util.Map fields = new java.util.HashMap();
            java.util.Iterator<org.apache.commons.fileupload.FileItem> iter = items
                    .iterator();
            while (iter.hasNext()) {
                org.apache.commons.fileupload.FileItem item = iter
                        .next();
                if (item.isFormField())
                    fields.put(item.getFieldName(), item.getString());
                else
                    fields.put(item.getFieldName(), item);
            }

            // CKEditor上傳form的upload元件名稱是upload
            org.apache.commons.fileupload.FileItem uplFile = (org.apache.commons.fileupload.FileItem) fields
                    .get("upload");
            // 取得文件名稱做處理
            String fileNameLong = uplFile.getName();
            fileNameLong = fileNameLong.replace('\\', '/');
            String[] pathParts = fileNameLong.split("/");
            String fileName = pathParts[pathParts.length - 1];
            // 取得副檔名
            String ext = getExtension(fileName);
            // 實際要存檔的名稱
            fileName = fileFormatter.format(dNow) + "." + ext;
            // 上傳檔案的檔名
            String nameWithoutExt = getNameWithoutExtension(fileName);
            java.io.File pathToSave = new java.io.File(currentDirPath,
                    fileName);
            logger.info("檔案名稱:" + currentDirPath + fileName);
            fileUrl = currentPath + "/" + fileName;
            if (extIsAllowed(typeStr, ext)) {
                int counter = 1;
                while (pathToSave.exists()) {
                    newName = nameWithoutExt + "_" + counter + "."
                            + ext;
                    fileUrl = currentPath + "/" + newName;
                    pathToSave = new java.io.File(currentDirPath,
                            newName);
                    counter++;
                }
                uplFile.write(pathToSave);
            } else {
                ErrorMsg = "無效的檔案類型 ";
                logger.info("無效的檔案類型: " + ext);
            }
        } catch (Exception ex) {
            ErrorMsg = "無法得知的錯誤!";
            logger.info(ex);
            ex.printStackTrace();
        }
    } else {
        ErrorMsg = "未啟用CKEditor上傳功能!!";
        logger.info("未啟用CKEditor上傳功能!!");
    }
    // CKEditorFuncNum是要回傳位置
    String callback = request.getParameter("CKEditorFuncNum");
    out.println("<script type=\"text/javascript\">");
    if (ErrorMsg.equals("")) {

        out.println("window.parent.CKEDITOR.tools.callFunction("
                + callback + ",'" + fileUrl + "',''" + ")");
    } else {
        out.println("alert('" + ErrorMsg + "')");
        out.println("history.back();");
    }
    out.println("</script>");
    out.flush();
    //out.close();
    logger.debug("--- END DOPOST ---");
%>

</body>
</html>

example.js

/*!
 * Ext JS Library 3.0.0
 * Copyright(c) 2006-2009 Ext JS, LLC
 * [email protected]
 * http://www.extjs.com/license
 */
Ext.onReady(function(){

    //Ext.QuickTips.init();

    // turn on validation errors beside the field globally
    //Ext.form.Field.prototype.msgTarget = 'side';

    var bd = Ext.getBody();


    var Form = new Ext.FormPanel({
        id: 'Myorm',
        frame: true,
        labelAlign: 'top',
        title: 'CKEditor in ExtJS',
        bodyStyle:'padding:5px',
        url:"getHtml.jsp",
        width: 750,
        layout: 'form',    // Specifies that the items will now be arranged in columns
        items: [{
            //columnWidth: 1,
            xtype: 'fieldset',
            labelWidth: 90,
            title:'CKEditor',
            defaults: {width: 700, border:false},    // Default config options for child items
            defaultType: 'textfield',
            autoHeight: true,
            bodyStyle: Ext.isIE ? 'padding:0 0 5px 15px;' : 'padding:10px 15px;',
            border: false,
            style: {
                "margin-left": "10px", // when you add custom margin in IE 6...
                "margin-right": Ext.isIE6 ? (Ext.isStrict ? "-10px" : "-13px") : "0"  // you have to adjust for it somewhere else
            },
            items: [{
                xtype: 'ckeditor',
                fieldLabel: 'Editor',
                name: 'htmlcode',
                id:'htmlcode',
                CKConfig: {
                    /* Enter your CKEditor config paramaters here or define a custom CKEditor config file. */
                    customConfig : 'config.js', // This allows you to define the path to a custom CKEditor config file.
                    //toolbar: 'Full',
                    toolbar:[['Source'/*,'-','Save','NewPage','Preview','-','Templates'*/],
                             ['Cut','Copy','Paste','PasteText','PasteFromWord','-','Print', 'SpellChecker', 'Scayt'],
                             ['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
                             /*['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'],*/
                             ['BidiLtr', 'BidiRtl'],['Link','Unlink','Anchor'],
                             '/',
                             ['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],
                             ['NumberedList','BulletedList','-','Outdent','Indent','Blockquote','CreateDiv'],
                             ['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],
                             
                             ['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak'],
                             '/',
                             ['Styles','Format','Font','FontSize'],
                             ['TextColor','BGColor'],
                             ['Maximize', 'ShowBlocks','-'/*,'About'*/]

                             ],
                    skin : 'office2003',
                    filebrowserUploadUrl : 'CKEditorUpload.jsp?Type=File',   
                    filebrowserImageUploadUrl : 'CKEditorUpload.jsp?Type=Image',   
                    filebrowserFlashUploadUrl : 'CKEditorUpload.jsp?Type=Flash',
                    height : 200//,
                    //width: 700
                }
            }]
        }],buttons:[{
                         text:'Save',
                         name:'Save',
                         handler:function()
                         {
                             //alert(123);
                             Form.getForm().submit();
                         }//.createDelegate(Form.getForm())
                     }],
        renderTo: bd
    });
});

讀取properties的小程式yku.yslifes.PropertiesWithStream

package yku.yslifes;

import java.io.IOException;  
import java.io.InputStream;  
import java.util.Properties;  

public class PropertiesWithStream {  
    private org.apache.log4j.Logger logger =  org.apache.log4j.Logger.getLogger(this.getClass());
    public static Properties loadInit()throws java.io.IOException
    {
         PropertiesWithStream propLoader = new PropertiesWithStream();  
          
        System.out.println("--- Properties from Class.getResourceAsStream ---");  
        
        InputStream in = propLoader.getClass().getResourceAsStream(  
                "/init.properties");  
        Properties prop = propLoader.getPropertiesFromInputStream(in);
        propLoader.displayAllProperties(prop);
        return prop;
    }

  
    private  Properties getPropertiesFromInputStream(InputStream in)  
            throws IOException {  
        Properties prop = new Properties();  
        prop.load(in);  
        return prop;  
    }  
  
    private  void displayAllProperties(Properties prop) {  
        for (Object key : prop.keySet())  
            logger.info(key + " : " + prop.getProperty(key.toString()));  
    }  
}

註:form物件記得frame: true才能上傳圖片喔

原始碼下載

下一篇會介紹使用php實作上傳介面

發表迴響