做如下几点说明: 1. 本文所指的FckEditor是2.6.4,所指的Struts2是2.1.6 2. 有关FckEditor的源代码分析,见:http://nileader.blog.51cto.com/1381108/301614 3. 网上很多关于FckEditor在Jsp中的配置的文章,本文也是在笔者看了传智播客的fck视频后,有所改进的完成的。但是,笔者的观点的是现在纯Jsp的网站不是很多,因此Fck和Struts2的结合更为多见。如果纯jsp的小网站,建议163的编辑器大可搞定。 http://nileader.blog.51cto.com/1381108/302744 4. 本文是作者一步一步配置的过程,并记录了作者在和Struts2过程中碰到的一些问题和解决方 法,供参考。 5. 建议和这篇文章一起看,效果更佳 http://nileader.blog.51cto.com/1381108/303234
5. 项目源代码: http://down.51cto.com/download.php?do=attachment&aid=120763&k=6b8f9716a1f697186a152ee7e03a68b3&t=1271986205 Struts2环境构建 网上关于如何构建Struts2环境的文章铺天盖地,这里不再赘述,只是提供给读者Struts2.1.6的一些jar包。
下载地址是:http://down.51cto.com/download.php?do=attachment&aid=120757&k=2adb78a2c041f917b548ff1e6a58e53c&t=1271983135 加入FckEditor Step1、下载Fckeditor2.6.4,下载地址是:http://down.51cto.com/download.php?do=attachment&aid=120751&k=f5b36d01d190c945186ec94b138e380b&t=1271981326 Step2、解压后,把里面的fckeditor目录导入到项目的WebRoot目录下,结构如图:
Step3、这步相当关键。 导入fckeditor-java-core的jar包到项 目的WEB-INF/lib目录下,下载地址是:http://down.51cto.com/download.php?do=attachment&aid=120752&k=74632b54f5df3e3415f74b2a20c871e3&t=1271982128
导入以下4个文件:
这里先别急,说明几点:
1. 这里的commons-fileupload-1.2.1.jar已经在上面Struts2中有所导入,所以不用导入。 2. 这里的slf4j-api-1.5.8.jar和slf4j-simple-1.5.8必须保持版本一致。 这里的三个包的下载地址是 : http://img1.51cto.com/attachment/201004/1381108_1271985600.rar Step4、在jsp页面中,添加如下标签声明: <%@ taglib uri="http://java.fckeditor.net" prefix="FCK"%> Body标签中加入你要放 置的fckeditor的位置: <FCK:editor instanceName="articleAddEditor" basePath="/fckeditor" value=" " ></FCK:editor>
好的,现在可以看到Fckeditor的真面目了。
Step1. 要上传文件,首先要配置 Web.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <filter> <filter-name>struts2</filter-name> <!-- 控制器 --> <filter-class> org.apache.struts2.dispatcher.FilterDispatcher </filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <!-- 任何请求均有过滤器 --> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>Connector</servlet-name> <servlet-class> net.fckeditor.connector.ConnectorServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Connector</servlet-name> <url-pattern> /fckeditor/editor/filemanager/connectors/* </url-pattern> </servlet-mapping> </web-app>
Step2. 在src目录下新建一个fckeditor.properties文件,内容如下:
connector.userActionImpl =net.fckeditor.requestcycle.impl.UserActionImpl好了,现在可以去页面上看看了,不过出错了:
或者是:
出现这个问题的原因是Fckeditor的拦截Servlet和Struts2的Servlet的冲突了。解决方法是修改web.xml如下
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <filter> <filter-name>struts2</filter-name> <!-- 控制器 --> <filter-class> org.apache.struts2.dispatcher.FilterDispatcher </filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/struts/*</url-pattern> </filter-mapping> <welcome-file-list> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>Connector</servlet-name> <servlet-class> net.fckeditor.connector.ConnectorServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Connector</servlet-name> <url-pattern> /fckeditor/editor/filemanager/connectors/* </url-pattern> </servlet-mapping> </web-app>
使得Struts2的拦截器只拦截.jsp和.action的请求。现在再到页面上去看看,可以上传了。
Step3. 改成随机数命名文件。
由于fckeditor的文件上传功能主要是由web.xml中配置的 net.fckeditor.connector.ConnectorServlet这个类拦截的,所以我们要自己来重命名文件的话,就要修改这个类。 办法是在net.fckeditor.connector.ConnectorServlet的基础上,建立自己的Servlet。
在项目src目录下建立以下包cn.nileader.tool里面建立两个类:GetCode.java
package com.rctraffic110.tool; import java.text.SimpleDateFormat; public class GetCode { /* * 获取一个记录编号 * 格式:12 位时间+业务编号+随即数 * 例如:100330101028+04+893 (2010-03-30-10:20:28, 业务号是04, 随机数893 ) *@param btype 业务类型编号 员工业务01 招聘业务02…… *@return code 构造的一个记录编号 */ public static String getNo(String btype){ //返回的code String code; //系统当前时间 12位 SimpleDateFormat sdf=new SimpleDateFormat("yyMMddhhmmss"); String nowDate=sdf.format(new java.util.Date()); //随机数 String iRandom = Math.round(Math.random()*900 )+100 +""; //整合一个code return nowDate + btype + iRandom ; } }
上面这个类是个随机获取编号的方法。再建立这个类ConcectorServlet.java
package com.rctraffic110.tool; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.fckeditor.connector.Messages; import net.fckeditor.handlers.CommandHandler; import net.fckeditor.handlers.ConnectorHandler; import net.fckeditor.handlers.ExtensionsHandler; import net.fckeditor.handlers.RequestCycleHandler; import net.fckeditor.handlers.ResourceTypeHandler; import net.fckeditor.response.UploadResponse; import net.fckeditor.response.XmlResponse; import net.fckeditor.tool.Utils; import net.fckeditor.tool.UtilsFile; import net.fckeditor.tool.UtilsResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ConnectorServlet extends HttpServlet { private static final long serialVersionUID = -5742008970929377161L; private static final Logger logger = LoggerFactory.getLogger(ConnectorServlet.class); public void init() throws ServletException, IllegalArgumentException { String realDefaultUserFilesPath = getServletContext().getRealPath( ConnectorHandler.getDefaultUserFilesPath()); File defaultUserFilesDir = new File(realDefaultUserFilesPath); UtilsFile.checkDirAndCreate(defaultUserFilesDir); logger.info("ConnectorServlet successfully initialized!"); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { logger.debug("Entering ConnectorServlet#doGet"); response.setCharacterEncoding("UTF-8"); response.setContentType("application/xml; charset=UTF-8"); response.setHeader("Cache-Control", "no-cache"); PrintWriter out = response.getWriter(); String commandStr = request.getParameter("Command"); String typeStr = request.getParameter("Type"); String currentFolderStr = request.getParameter("CurrentFolder"); logger.debug("Parameter Command: {}", commandStr); logger.debug("Parameter Type: {}", typeStr); logger.debug("Parameter CurrentFolder: {}", currentFolderStr); XmlResponse xr; if (!RequestCycleHandler.isEnabledForFileBrowsing(request)) xr = new XmlResponse(XmlResponse.EN_ERROR, Messages.NOT_AUTHORIZED_FOR_BROWSING); else if (!CommandHandler.isValidForGet(commandStr)) xr = new XmlResponse(XmlResponse.EN_ERROR, Messages.INVALID_COMMAND); else if (typeStr != null && !ResourceTypeHandler.isValid(typeStr)) xr = new XmlResponse(XmlResponse.EN_ERROR, Messages.INVALID_TYPE); else if (!UtilsFile.isValidPath(currentFolderStr)) xr = new XmlResponse(XmlResponse.EN_ERROR, Messages.INVALID_CURRENT_FOLDER); else { CommandHandler command = CommandHandler.getCommand(commandStr); ResourceTypeHandler resourceType = ResourceTypeHandler.getDefaultResourceType(typeStr); String typePath = UtilsFile.constructServerSidePath(request, resourceType); String typeDirPath = getServletContext().getRealPath(typePath); File typeDir = new File(typeDirPath); UtilsFile.checkDirAndCreate(typeDir); File currentDir = new File(typeDir, currentFolderStr); if (!currentDir.exists()) xr = new XmlResponse(XmlResponse.EN_INVALID_FOLDER_NAME); else { xr = new XmlResponse(command, resourceType, currentFolderStr, UtilsResponse .constructResponseUrl(request, resourceType, currentFolderStr, true, ConnectorHandler.isFullUrl())); if (command.equals(CommandHandler.GET_FOLDERS)) xr.setFolders(currentDir); else if (command.equals(CommandHandler.GET_FOLDERS_AND_FILES)) xr.setFoldersAndFiles(currentDir); else if (command.equals(CommandHandler.CREATE_FOLDER)) { String newFolderStr = UtilsFile.sanitizeFolderName(request .getParameter("NewFolderName")); logger.debug("Parameter NewFolderName: {}", newFolderStr); File newFolder = new File(currentDir, newFolderStr); int errorNumber = XmlResponse.EN_UKNOWN; if (newFolder.exists()) errorNumber = XmlResponse.EN_ALREADY_EXISTS; else { try { errorNumber = (newFolder.mkdir()) ? XmlResponse.EN_OK : XmlResponse.EN_INVALID_FOLDER_NAME; } catch (SecurityException e) { errorNumber = XmlResponse.EN_SECURITY_ERROR; } } xr.setError(errorNumber); } } } out.print(xr); out.flush(); out.close(); logger.debug("Exiting ConnectorServlet#doGet"); } @SuppressWarnings("unchecked") public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { logger.debug("Entering Connector#doPost"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=UTF-8"); response.setHeader("Cache-Control", "no-cache"); PrintWriter out = response.getWriter(); String commandStr = request.getParameter("Command"); String typeStr = request.getParameter("Type"); String currentFolderStr = request.getParameter("CurrentFolder"); logger.debug("Parameter Command: {}", commandStr); logger.debug("Parameter Type: {}", typeStr); logger.debug("Parameter CurrentFolder: {}", currentFolderStr); UploadResponse ur; // if this is a QuickUpload request, 'commandStr' and 'currentFolderStr' // are empty if (Utils.isEmpty(commandStr) && Utils.isEmpty(currentFolderStr)) { commandStr = "QuickUpload"; currentFolderStr = "/"; } if (!RequestCycleHandler.isEnabledForFileUpload(request)) ur = new UploadResponse(UploadResponse.SC_SECURITY_ERROR, null, null, Messages.NOT_AUTHORIZED_FOR_UPLOAD); else if (!CommandHandler.isValidForPost(commandStr)) ur = new UploadResponse(UploadResponse.SC_ERROR, null, null, Messages.INVALID_COMMAND); else if (typeStr != null && !ResourceTypeHandler.isValid(typeStr)) ur = new UploadResponse(UploadResponse.SC_ERROR, null, null, Messages.INVALID_TYPE); else if (!UtilsFile.isValidPath(currentFolderStr)) ur = UploadResponse.UR_INVALID_CURRENT_FOLDER; else { ResourceTypeHandler resourceType = ResourceTypeHandler.getDefaultResourceType(typeStr); String typePath = UtilsFile.constructServerSidePath(request, resourceType); String typeDirPath = getServletContext().getRealPath(typePath); File typeDir = new File(typeDirPath); UtilsFile.checkDirAndCreate(typeDir); File currentDir = new File(typeDir, currentFolderStr); if (!currentDir.exists()) ur = UploadResponse.UR_INVALID_CURRENT_FOLDER; else { String newFilename = null; FileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); upload.setHeaderEncoding("UTF-8"); try { List<FileItem> items = upload.parseRequest(request); // We upload only one file at the same time FileItem uplFile = items.get(0); String rawName = UtilsFile.sanitizeFileName(uplFile.getName()); String filename = FilenameUtils.getName(rawName); String baseName = FilenameUtils.removeExtension(filename); String extension = FilenameUtils.getExtension(filename); filename = GetCode.getNo("1104" )+"."+extension; if (!ExtensionsHandler.isAllowed(resourceType, extension)) ur = new UploadResponse(UploadResponse.SC_INVALID_EXTENSION); else { // construct an unique file name File pathToSave = new File(currentDir, filename); int counter = 1; while (pathToSave.exists()) { newFilename = baseName.concat("(").concat(String.valueOf(counter)) .concat(")").concat(".").concat(extension); pathToSave = new File(currentDir, newFilename); counter++; } if (Utils.isEmpty(newFilename)) ur = new UploadResponse(UploadResponse.SC_OK, UtilsResponse .constructResponseUrl(request, resourceType, currentFolderStr, true, ConnectorHandler.isFullUrl()).concat(filename)); else ur = new UploadResponse(UploadResponse.SC_RENAMED, UtilsResponse.constructResponseUrl(request, resourceType, currentFolderStr, true, ConnectorHandler.isFullUrl()) .concat(newFilename), newFilename); // secure image check if (resourceType.equals(ResourceTypeHandler.IMAGE) && ConnectorHandler.isSecureImageUploads()) { if (UtilsFile.isImage(uplFile.getInputStream())) uplFile.write(pathToSave); else { uplFile.delete(); ur = new UploadResponse(UploadResponse.SC_INVALID_EXTENSION); } } else uplFile.write(pathToSave); } } catch (Exception e) { ur = new UploadResponse(UploadResponse.SC_SECURITY_ERROR); } } } out.print(ur); out.flush(); out.close(); logger.debug("Exiting Connector#doPost"); } }目录结构为:
再修改web.xml中的Servlet如下:
<servlet> <servlet-name>Connector</servlet-name> <servlet-class> cn.nileader.tool.ConnectorServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet>效果如下:
下载地址 :http://download.csdn.net/user/advance1989