最近有个项目改版,然后我尝试着用SS2H来进行架构,因为以前一直喜欢WW,所以一直想还是跟着潮流走吧,反正Struts2就是WW,接着就动手改版!
当有个同事说“锋哥,FCKeditor编辑器上传图片报错,说找不到NewFile”。
我说“怎么可能,FCKeditor一直好的!”。
然后我就自己测试研究了一下!还真那么回事,然后我想了很多方式去测试。
最后在DEBUG模式里发现了,S2文件上传的拦截器拦截了commons-fileupload上传的文件。所以在FCKeditor的com.fredck.FCKeditor.uploader.SimpleUploaderServlet这个类找不到NewFile。
想了很久,决定去找一下FCKeditor的源码,在官网找到最后是3.X的吧,然后就把SimpleUploaderServlet这个类好好的读了一遍,着手重写,让它支持S2,整个过程只要修改文件上传拦截获取方式就可以,我也根据项目要求加了一些项目需要的文件目录和文件命名等。
先贴一下修改前源码:
/*
* FCKeditor - The text editor for internet
* Copyright (C) 2003-2005 Frederico Caldeira Knabben
*
* Licensed under the terms of the GNU Lesser General Public License:
* http://www.opensource.org/licenses/lgpl-license.php
*
* For further information visit:
* http://www.fckeditor.net/
*
* File Name: SimpleUploaderServlet.java
* Java File Uploader class.
*
* Version: 2.3
* Modified: 2005-08-11 16:29:00
*
* File Authors:
* Simone Chiaretta ([email protected])
*/
package com.fredck.FCKeditor.uploader;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import org.apache.commons.fileupload.*;
/**
* Servlet to upload files.<br>
*
* This servlet accepts just file uploads, eventually with a parameter specifying file type
*
* @author Simone Chiaretta ([email protected])
*/
public class SimpleUploaderServlet extends HttpServlet {
private static String baseDir;
private static boolean debug=false;
private static boolean enabled=false;
private static Hashtable allowedExtensions;
private static Hashtable deniedExtensions;
/**
* Initialize the servlet.<br>
* Retrieve from the servlet configuration the "baseDir" which is the root of the file repository:<br>
* If not specified the value of "/UserFiles/" will be used.<br>
* Also it retrieve all allowed and denied extensions to be handled.
*
*/
public void init() throws ServletException {
debug=(new Boolean(getInitParameter("debug"))).booleanValue();
if(debug) System.out.println("\r\n---- SimpleUploaderServlet initialization started ----");
baseDir=getInitParameter("baseDir");
enabled=(new Boolean(getInitParameter("enabled"))).booleanValue();
if(baseDir==null)
baseDir="/UserFiles/";
String realBaseDir=getServletContext().getRealPath(baseDir);
File baseFile=new File(realBaseDir);
if(!baseFile.exists()){
baseFile.mkdir();
}
allowedExtensions = new Hashtable(3);
deniedExtensions = new Hashtable(3);
allowedExtensions.put("File",stringToArrayList(getInitParameter("AllowedExtensionsFile")));
deniedExtensions.put("File",stringToArrayList(getInitParameter("DeniedExtensionsFile")));
allowedExtensions.put("Image",stringToArrayList(getInitParameter("AllowedExtensionsImage")));
deniedExtensions.put("Image",stringToArrayList(getInitParameter("DeniedExtensionsImage")));
allowedExtensions.put("Flash",stringToArrayList(getInitParameter("AllowedExtensionsFlash")));
deniedExtensions.put("Flash",stringToArrayList(getInitParameter("DeniedExtensionsFlash")));
if(debug) System.out.println("---- SimpleUploaderServlet initialization completed ----\r\n");
}
/**
* Manage the Upload requests.<br>
*
* The servlet accepts commands sent in the following format:<br>
* simpleUploader?Type=ResourceType<br><br>
* It store the file (renaming it in case a file with the same name exists) and then return an HTML file
* with a javascript command in it.
*
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (debug) System.out.println("--- BEGIN DOPOST ---");
response.setContentType("text/html; charset=UTF-8");
response.setHeader("Cache-Control","no-cache");
PrintWriter out = response.getWriter();
String typeStr=request.getParameter("Type");
String currentPath=baseDir+typeStr;
String currentDirPath=getServletContext().getRealPath(currentPath);
currentPath=request.getContextPath()+currentPath;
if (debug) System.out.println(currentDirPath);
String retVal="0";
String newName="";
String fileUrl="";
String errorMessage="";
if(enabled) {
DiskFileUpload upload = new DiskFileUpload();
try {
List items = upload.parseRequest(request);
Map fields=new HashMap();
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField())
fields.put(item.getFieldName(),item.getString());
else
fields.put(item.getFieldName(),item);
}
FileItem uplFile=(FileItem)fields.get("NewFile");
String fileNameLong=uplFile.getName();
fileNameLong=fileNameLong.replace('\\','/');
String[] pathParts=fileNameLong.split("/");
String fileName=pathParts[pathParts.length-1];
String nameWithoutExt=getNameWithoutExtension(fileName);
String ext=getExtension(fileName);
File pathToSave=new File(currentDirPath,fileName);
fileUrl=currentPath+"/"+fileName;
if(extIsAllowed(typeStr,ext)) {
int counter=1;
while(pathToSave.exists()){
newName=nameWithoutExt+"("+counter+")"+"."+ext;
fileUrl=currentPath+"/"+newName;
retVal="201";
pathToSave=new File(currentDirPath,newName);
counter++;
}
uplFile.write(pathToSave);
}
else {
retVal="202";
errorMessage="";
if (debug) System.out.println("Invalid file type: " + ext);
}
}catch (Exception ex) {
if (debug) ex.printStackTrace();
retVal="203";
}
}
else {
retVal="1";
errorMessage="This file uploader is disabled. Please check the WEB-INF/web.xml file";
}
out.println("<script type=\"text/javascript\">");
out.println("window.parent.OnUploadCompleted("+retVal+",'"+fileUrl+"','"+newName+"','"+errorMessage+"');");
out.println("</script>");
out.flush();
out.close();
if (debug) System.out.println("--- END DOPOST ---");
}
/*
* This method was fixed after Kris Barnhoorn (kurioskronic) submitted SF bug #991489
*/
private static String getNameWithoutExtension(String fileName) {
return fileName.substring(0, fileName.lastIndexOf("."));
}
/*
* This method was fixed after Kris Barnhoorn (kurioskronic) submitted SF bug #991489
*/
private String getExtension(String fileName) {
return fileName.substring(fileName.lastIndexOf(".")+1);
}
/**
* Helper function to convert the configuration string to an ArrayList.
*/
private ArrayList stringToArrayList(String str) {
if(debug) System.out.println(str);
String[] strArr=str.split("\\|");
ArrayList tmp=new ArrayList();
if(str.length()>0) {
for(int i=0;i<strArr.length;++i) {
if(debug) System.out.println(i +" - "+strArr[i]);
tmp.add(strArr[i].toLowerCase());
}
}
return tmp;
}
/**
* Helper function to verify if a file extension is allowed or not allowed.
*/
private boolean extIsAllowed(String fileType, String ext) {
ext=ext.toLowerCase();
ArrayList allowList=(ArrayList)allowedExtensions.get(fileType);
ArrayList denyList=(ArrayList)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;
}
}
修改后的源码:
/*
* FCKeditor - The text editor for internet
* Copyright (C) 2003-2005 Frederico Caldeira Knabben
*
* Licensed under the terms of the GNU Lesser General Public License:
* http://www.opensource.org/licenses/lgpl-license.php
*
* For further information visit:
* http://www.fckeditor.net/
*
* File Name: SimpleUploaderServlet.java
* Java File Uploader class.
*
* Version: 2.3
* Modified: 2005-08-11 16:29:00
*
* File Authors:
* Simone Chiaretta ([email protected])
*/
package com.fredck.FCKeditor.struts2;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.servlet.ServletRequestContext;
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
/**
* Servlet to upload files.<br>
*
* This servlet accepts just file uploads, eventually with a parameter
* specifying file type
*
* @author Simone Chiaretta ([email protected])
*/
public class SimpleUploaderServlet extends HttpServlet {
private static String baseDir;
private static boolean debug = false;
private static boolean enabled = false;
private static Hashtable<String, ArrayList<?>> exts;
private static Hashtable<String, String> maxSizes;
/**
* Initialize the servlet.<br>
* Retrieve from the servlet configuration the "baseDir" which is the root
* of the file repository:<br>
* If not specified the value of "/UserFiles/" will be used.<br>
* Also it retrieve all allowed and denied extensions to be handled.
*/
public void init() throws ServletException {
debug = (new Boolean(getInitParameter("debug"))).booleanValue();
if (debug)
{
System.out.println("\r\n---- SimpleUploaderServlet initialization started ----");
}
baseDir = getInitParameter("baseDir");
enabled = (new Boolean(getInitParameter("enabled"))).booleanValue();
if (baseDir == null)
{
baseDir = "/UserFiles/";
}
String realBaseDir = getServletContext().getRealPath(baseDir);
File baseFile = new File(realBaseDir);
if (!baseFile.exists()) {
baseFile.mkdir();
}
exts = new Hashtable<String, ArrayList<?>>();
maxSizes = new Hashtable<String, String>();
exts.put("Image", stringToArrayList(getInitParameter("ImageExt")));
maxSizes.put("Image", getInitParameter("ImageMaxSize"));
exts.put("Flash", stringToArrayList(getInitParameter("FlashExt")));
maxSizes.put("Flash", getInitParameter("FlashMaxSize"));
if (debug)
{
System.out.println("---- SimpleUploaderServlet initialization completed ----\r\n");
}
}
/**
* Manage the Upload requests.<br>
*
* The servlet accepts commands sent in the following format:<br>
* simpleUploader?Type=ResourceType<br>
*
* It store the file (renaming it in case a file with the same name exists)
* and then return an HTML file with a javascript command in it.
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.struts2Uploader(request, response);
}
/**
* Manage the Upload requests.<br>
*
* The servlet accepts commands sent in the following format:<br>
* struts2Uploader?Type=ResourceType<br>
*
* It store the file (renaming it in case a file with the same name exists)
* and then return an HTML file with a javascript command in it.
*/
@SuppressWarnings("unchecked")
public void struts2Uploader(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (debug)
{
System.out.println("--- BEGIN DOPOST ---");
}
response.setContentType("text/html; charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
PrintWriter out = response.getWriter();
//上传时间获得文件类型
String typeStr = request.getParameter("Type");
//文件上传路径
String currentPath = getUploadFileDir(this.getServletContext());
//真实路径
String currentDirPath = getServletContext().getRealPath(currentPath);
currentPath = request.getContextPath() + currentPath;
if (debug)
{
//System.out.println("baseDir:" + baseDir);
//System.out.println("currentPath:" + currentPath);
//System.out.println("currentDirPath:" + currentDirPath);
}
//上传后需要传递的参数
String retVal = "0";
String newName = "";
String fileUrl = "";
String errorMessage = "";
if (enabled)
{
try {
//用Struts2组件上传
MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) request;
// Bind allowed Files
Enumeration fileParameterNames = multiWrapper.getFileParameterNames();
while (fileParameterNames != null && fileParameterNames.hasMoreElements())
{
// get the value of this input tag name
String inputName = (String) fileParameterNames.nextElement();
// get the file type
String[] contentType = multiWrapper.getContentTypes(inputName);
if (isNonEmpty(contentType))
{
// get the name of the file from the input tag
//真实文件名
String[] fileName = multiWrapper.getFileNames(inputName);
if (isNonEmpty(fileName))
{
// Get a File object for the uploaded File
// 获得struts2上传组件存放/tmp文件
File[] files = multiWrapper.getFiles(inputName);
if (files != null) {
for (int index = 0; index < files.length; index++)
{
//文件后缀名
String ext = getExtension(fileName[index]);
//判断文件是否允许上伟
if (extIsAllowed(typeStr, ext))
{
if(isOutMaxSize(typeStr, request.getContentLength()))
{
//上传文件
String fileRename = this.getFileRename(fileName[index]);
fileUrl = currentPath + "/" + fileRename;
newName = fileName[index];
String uploadPath = currentDirPath + "\\" + fileRename;
System.out.println(fileUrl);
System.out.println(uploadPath);
File dstFile = new File(uploadPath);
this.copy(files[index], dstFile);
} else {
retVal = "1";
errorMessage = typeStr + "类型文件超过系统最大限制" + (Integer.parseInt(maxSizes.get(typeStr))/1024) + "KB,请检查上传文件大小。(如需上传请在WEB-INF/web.xml里进行设置)" ;
if (debug)
System.out.println("Invalid file type: " + errorMessage);
}
} else {
//不允许上传些文件
retVal = "1";
errorMessage = "系统只允许上传" + Arrays.asList(exts.get(typeStr)) + "类型文件,请检查上传文件格式。(如需上传请在WEB-INF/web.xml里进行设置)" ;
if (debug)
System.out.println("Invalid file type: " + errorMessage);
}
}
}
}
}
}
}
catch (Exception ex)
{
if (debug)
ex.printStackTrace();
retVal = "1";
errorMessage = "文件上传错误:" + ex.getMessage();
}
} else {
retVal = "1";
errorMessage = "(文件上传功能被禁用,请在 WEB-INF/web.xml 里进行设置) This file uploader is disabled. Please check the WEB-INF/web.xml file";
}
out.println("<script type=\"text/javascript\">");
out.println("window.parent.OnUploadCompleted(" + retVal + ",'" + fileUrl + "','" + newName + "','" + errorMessage + "');");
out.println("</script>");
out.flush();
out.close();
if (debug)
System.out.println("--- END DOPOST ---");
}
/**
* Manage the Upload requests.<br>
*
* The servlet accepts commands sent in the following format:<br>
* simpleUploader?Type=ResourceType<br>
*
* It store the file (renaming it in case a file with the same name exists)
* and then return an HTML file with a javascript command in it.
*/
public void simpleUploader(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (debug)
{
System.out.println("--- BEGIN DOPOST ---");
}
response.setContentType("text/html; charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
PrintWriter out = response.getWriter();
//上传时间获得文件类型
String typeStr = request.getParameter("Type");
//文件上传路径
String currentPath = getUploadFileDir(this.getServletContext());
//真实路径
String currentDirPath = getServletContext().getRealPath(currentPath);
currentPath = request.getContextPath() + currentPath;
if (debug)
{
System.out.println("baseDir:" + baseDir);
System.out.println("currentPath:" + currentPath);
System.out.println("currentDirPath:" + currentDirPath);
}
//上传后需要传递的参数
String retVal = "0";
String newName = "";
String fileUrl = "";
String errorMessage = "";
if (enabled)
{
try {
//创建文件项(FileItem)实例化工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置内存缓冲区大小,这里是10kb。当上传过程中文件的大小超过缓冲区大小,先写入磁盘的临时文件目录
// 目的是防止上传的文件过大时,占用大量的内存资源。默认10KB
factory.setSizeThreshold(10 * 1024 * 1024);
// 设置临时文件目录,使用系统级的临时目录,部分老的JDK版本可能不支持。
factory.setRepository(new File(java.lang.System.getProperty("java.io.tmpdir")));
// 将设置好的文件项工厂传递给文件上传执行类
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置最大文件尺寸,这里是10MB
int maxSize = 1*1024*1024;
//根据Web.xml定义读取大小
Object typeMaxSize = maxSizes.get(typeStr);
if(null != typeMaxSize && !("").equals(typeMaxSize.toString().trim()))
{
maxSize = Integer.parseInt(typeMaxSize.toString());
}
upload.setSizeMax(maxSize);
//文件上传
List items = upload.parseRequest(new ServletRequestContext(request));
Map<String, Object> fields = new HashMap<String, Object>();
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField())
fields.put(item.getFieldName(), item.getString());
else
fields.put(item.getFieldName(), item);
}
//获得新上传文件
FileItem uplFile = (FileItem) fields.get("NewFile");
//文件名
String fileNameLong = uplFile.getName();
System.out.println("fileNameLong:" + fileNameLong);
fileNameLong = fileNameLong.replace('\\', '/');
String[] pathParts = fileNameLong.split("/");
String fileName = pathParts[pathParts.length - 1];
fileName = this.getFileRename(fileName);
//文件后缀名
String ext = getExtension(fileName);
//创建新文件
File pathToSave = new File(currentDirPath, fileName);
fileUrl = currentPath + "/" + fileName;
//判断文件是否允许上伟
if (extIsAllowed(typeStr, ext))
{
//上传文件
uplFile.write(pathToSave);
} else {
//不允许上传些文件
retVal = "202";
errorMessage = "系统不允许上传此[ " + ext + "]类型文件" ;
if (debug)
System.out.println("Invalid file type: " + ext + errorMessage);
}
}
catch (Exception ex)
{
if (debug)
ex.printStackTrace();
retVal = "203";
errorMessage = "文件上传错误...";
}
} else {
retVal = "1";
errorMessage = "(文件上传功能被禁用,请在 WEB-INF/web.xml 里进行设置) This file uploader is disabled. Please check the WEB-INF/web.xml file";
}
out.println("<script type=\"text/javascript\">");
out.println("window.parent.OnUploadCompleted(" + retVal + ",'" + fileUrl + "','" + newName + "','" + errorMessage + "');");
out.println("</script>");
out.flush();
out.close();
if (debug)
System.out.println("--- END DOPOST ---");
}
/**
* Helper function to convert the configuration string to an ArrayList.
*/
private ArrayList<String> stringToArrayList(String str) {
//上传文件后缀
if (debug)
System.out.println(str);
String[] strArr = str.split("\\|");
ArrayList<String> tmp = new ArrayList<String>();
if (str.length() > 0) {
for (int i = 0; i < strArr.length; ++i) {
if (debug)
System.out.println(i + " - " + strArr[i]);
tmp.add(strArr[i].toLowerCase());
}
}
return tmp;
}
/**
* Helper function to verify if a file extension is allowed or not allowed.
*/
private boolean extIsAllowed(String fileType, String ext) {
//判断是否允许上传的文件后缀
ext = ext.toLowerCase();
ArrayList extList = (ArrayList) exts.get(fileType);
//如果为空则不允许上传
if(null == extList || extList.isEmpty())
{
return false ;
}
//如果后缀存在则同意上传
if(extList.contains(ext))
{
return true;
}
return false;
}
/**
* Method:判断文件大小是否超出允许范围<br>
* Author:HF-JWinder(2009-6-2 下午01:59:43)
* @param fileType 上传文件类型
* @param fileSize 上传文件大小
* @return boolean
*/
private boolean isOutMaxSize(String fileType, long fileSize)
{
//设置最大文件尺寸默认最大上似1MB
long defaultMaxSize = 1*1024*1024;
//根据Web.xml定义读取大小
Object typeMaxSize = maxSizes.get(fileType);
if(null != typeMaxSize && !("").equals(typeMaxSize.toString().trim()))
{
defaultMaxSize = Integer.parseInt(typeMaxSize.toString());
}
if(fileSize > defaultMaxSize)
{
return false ;
} else {
return true;
}
}
/**
* 上传文件目录更改了按照上传日期自动生成文件夹的路径
*/
private String getUploadFileDir(ServletContext context)
{
String fileSpr = System.getProperty("file.separator");
Date currentDate = new Date();
// 判断当月的目录是否存在
DateFormat dateFormat = new SimpleDateFormat("yyyy");
String yyyy = dateFormat.format(currentDate);
dateFormat = new SimpleDateFormat("MM");
String MM = dateFormat.format(currentDate);
dateFormat = new SimpleDateFormat("dd");
String dd = dateFormat.format(currentDate);
String uploadDir = baseDir + yyyy + fileSpr + MM + fileSpr + dd;
File dir = new File(context.getRealPath("/") + uploadDir);
if (!dir.exists())
{
dir.mkdirs();
}
uploadDir = uploadDir.replace("\\", "/") ;
//System.out.println("uploadDir:" + uploadDir);
return uploadDir ;
}
/**
* 重新命名上传文件,格式:yyyyMMddHHmmssS + (原名称)
*/
private String getFileRename(String fileName)
{
String YYYYMMDDHHMMSSS = "yyyyMMddHHmmssS";
SimpleDateFormat sdf = new SimpleDateFormat(YYYYMMDDHHMMSSS);
String uuidName = sdf.format(new Date());
uuidName += "(" + getNameWithoutExtension(fileName) + ")" + "." + getExtension(fileName);
return uuidName;
}
/**
* This method was fixed after Kris Barnhoorn (kurioskronic) submitted SF
* bug #991489
*/
private String getNameWithoutExtension(String fileName) {
return fileName.substring(0, fileName.lastIndexOf("."));
}
/**
* This method was fixed after Kris Barnhoorn (kurioskronic) submitted SF
* bug #991489
*/
private String getExtension(String fileName) {
return fileName.substring(fileName.lastIndexOf(".") + 1);
}
private final int BUFFER_SIZE = 16 * 1024;
//自己封装的一个把源文件对象复制成目标文件对象
private void copy(File src, File dst)
{
InputStream in = null;
OutputStream out = null;
try {
in = new BufferedInputStream(new FileInputStream(src), BUFFER_SIZE);
out = new BufferedOutputStream(new FileOutputStream(dst), BUFFER_SIZE);
byte[] buffer = new byte[BUFFER_SIZE];
int len = 0;
while ((len = in.read(buffer)) > 0)
{
out.write(buffer, 0, len);
}
}
catch (IOException e)
{
e.printStackTrace();
} finally {
if (null != in) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != out) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static boolean isNonEmpty(Object[] objArray) {
boolean result = false;
for (int index = 0; index < objArray.length && !result; index++) {
if (objArray[index] != null) {
result = true;
}
}
return result;
}
}
最后进行测试通过,我这里只是改了其中一个上传类,我把FCKeditor简化了!只有用到了图片上传。
如果你想转变一下上传方式,不用S2的话,只要在doPost改一下上传类。
希望对在用FCKeditor,Struts2的朋友有所帮助。
还好整个工程不大,不到1M。
附件提供了,Demo并且相应的包。