这里先唠叨一下,这几天在学习spring-mvc,相对于之前的struts2还是相当痛苦的
如此看来,如果没有扎实的学过jsp相关技术,直接跳到struts2,完全可以!但是,如果再次回到spring-mvc或者jsp的话,那肯定会出不少概念性的问题,我就是!这又让我想起了struts2让高手越用越强,让菜鸟越用越笨了,呵呵
前2天,杭州下了大雨,打了打雷。悲剧的,据说学校的部分路由设施给出了问题,我昨天凡是上网(而且是我最需要的),那个慢啊,最可恶的是SourceForge上不去了,直接悲剧到,我的fckeditor2.6的bin包找不着,幸亏之前有他的src包。
开始正题!
之前在用的是fckeditor for java 2.4吧,这次用了最新的2.6.6,发现很多api都改了。看样子又要仔细看一下了。
一共有一下几个要求,特点:
<servlet> <servlet-name>Connector</servlet-name> <servlet-class> com.mxdba.common.service.fckeditor.servlet.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>
@Override
protected void doPost(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException,
IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
response.setHeader("Cache-Control", "no-cache");
PrintWriter out = response.getWriter();
UploadResponse uploadResponse = null;
try {
ThreadLocalData.beginRequest(request);//这个threadLocalData是个好东西,主要解决多线程时的问题,到时要仔细写一下
uploadResponse = uploadRuleHandle.doPost(request);//此处才是真正 的处理部分
} catch (Exception e) {
throw new ServletException(e);
} finally {
ThreadLocalData.endRequest();
}
out.print(uploadResponse);
out.flush();
out.close();
}
protected UploadResponse doPost(final HttpServletRequest request) {
log.debug("Entering Dispatcher#doPost");
Context context = ThreadLocalData.getContext();
context.logBaseParameters();
String uploadRuleId = request.getParameter("uploadRuleId");//此处代码是在control中产生的
/** * 处理上传文件 * @param request 通过request设置session中key值 */ private void addUploadFile(HttpServletRequest request) { UploadRule rule = new UploadRule(getWeb().getUploadRoot(), Article.UPLOAD_PATH, true); int uploadRuleId = rule.hashCode(); request.setAttribute("_uploadRuleId", uploadRuleId); request.getSession().setAttribute(UploadRule.KEY + uploadRuleId, rule);//在session中保存,因为session的key是动态的,所以无法使用springmvc中的@seesionAttribute
String currentFolderStr = "";
// 根据上传规则处理浏览路径
UploadRule rule = (UploadRule) request.getSession().getAttribute(
UploadRule.KEY + uploadRuleId);
UploadResponse uploadResponse = null;
if (rule == null)
uploadResponse = UploadResponse.getFileUploadDisabledError();
// check permissions for user actions
else if (!RequestCycleHandler.isFileUploadEnabled(request))
uploadResponse = UploadResponse.getFileUploadDisabledError();
// check parameters
else if (!Command.isValidForPost(context.getCommandStr()))
uploadResponse = UploadResponse.getInvalidCommandError();
else if (!ResourceType.isValidType(context.getTypeStr()))
uploadResponse = UploadResponse.getInvalidResourceTypeError();
else if (!UtilsFile.isValidPath(context.getCurrentFolderStr()))
uploadResponse = UploadResponse.getInvalidCurrentFolderError();
else {
// call the Connector#fileUpload
ResourceType type = context.getDefaultResourceType();
// 使用上传规则的浏览路径,即上传根路径
String rootPath = rule.getRootPath() + rule.getPathPrefix();
String typePath;//一般为htpp://www.mxdba.com:8080/res_base/mxdba_com_www/article
if (rule.isHasType()) {//处理类别htpp://www.mxdba.com:8080/res_base/mxdba_com_www/article + /image
typePath = rootPath + type.getPath();
} else {
typePath = rootPath;
}
上传路径,是从rule中获取的,这样就做到了动态性,而这个UploadRule是关键,相关思路是参考了jeecms中的实现,以后再分析一下
//获得绝对路径 String typeDirPath = servletContext.getRealPath(typePath); //如果不存在则在服务器端创建 File typeDir = new File(typeDirPath); UtilsFile.checkDirAndCreate(typeDir); //此处获取具体文件的目录,会根据年月日自动创建 如:\2010_1\3_6 currentFolderStr = UploadRule.genFilePath(); File currentDir = new File(typeDir, currentFolderStr); //如果不存在则创建 if (!currentDir.exists()) { currentDir.mkdirs(); } /** * 这次已经准备好文件路径: * 如:E:\==teclife==\tomcat\tomcat6.0.20\wtpwebapps\WhiteBoard\res_base\test1_com_www\\upload\article\image\2010_1\3_6 */ //开始进行上传操作 FileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); try { List<FileItem> items = upload.parseRequest(request); // We upload just 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);//扩展名 // 判断是否创建文件名,如果上传文件包含中文字,也自动创建文件名 if (rule.isGenName() || StrUtils.hasCn(filename)) { baseName = UploadRule.genFileName(); filename = baseName.concat(".").concat(extension); } // 检查扩展名是否允许 if (type.isDeniedExtension(extension)) uploadResponse = UploadResponse.getInvalidFileTypeError(); // Secure image check (can't be done if QuickUpload) else if (type.equals(ResourceType.IMAGE) && PropertiesLoader.isSecureImageUploads() && !UtilsFile.isImage(uplFile.getInputStream())) { uploadResponse = UploadResponse.getInvalidFileTypeError(); } else { //创建文件,能够处理重复文件名的情况 String newFileName = connector.fileUpload(type, currentDir.toString(), filename, uplFile .getInputStream()); String fileUrl = typePath + currentFolderStr + newFileName;//得到返回路径,即编辑框中地址 // String fileUrl = UtilsResponse.fileUrl(RequestCycleHandler // .getUserFilesPath(request), type, context // .getCurrentFolderStr(), newFileName); fileUrl = handlerUrl(fileUrl); //检查是否重命名了 if (filename.equals(newFileName)) uploadResponse = UploadResponse.getOK(fileUrl); else { uploadResponse = UploadResponse.getFileRenamedWarning(fileUrl, newFileName); log.debug("Parameter NewFile (renamed): {}", newFileName); } } uplFile.delete(); } catch (InvalidCurrentFolderException e) { uploadResponse = UploadResponse.getInvalidCurrentFolderError(); } catch (WriteException e) { uploadResponse = UploadResponse.getFileUploadWriteError(); } catch (IOException e) { uploadResponse = UploadResponse.getFileUploadWriteError(); } catch (FileUploadException e) { uploadResponse = UploadResponse.getFileUploadWriteError(); } } log.debug("Exiting Dispatcher#doPost"); return uploadResponse; }这里的代码主要参考了fckeditor自带的dispatch, 之所以不扩展dispath是因为dispath中的那些方法都是包级别可见性,无法进行扩展,幸亏fckeditor其他包对dispath没有依赖
第四步,由通过url传递uploadId
这点是最麻烦的
/**
* 处理上传文件
* @param request 通过request设置session中key值
*/
private void addUploadFile(HttpServletRequest request) {
UploadRule rule = new UploadRule(getWeb().getUploadRoot(), Article.UPLOAD_PATH, true);
int uploadRuleId = rule.hashCode();
request.setAttribute("_uploadRuleId", uploadRuleId);
//在此处设置attribute,jsp页面时可以取道,但是由于上传文件时的post地址是fckeditor的servlet地址,要通过参数传递才可以,所以必须动态构造URL
request.getSession().setAttribute(UploadRule.KEY + uploadRuleId, rule); }
我是使用jspTag的,其他方式道理一样,就是构造config
<fck:editor instanceName="content"> <jsp:attribute name="value">This is some <strong>sample text </strong>. You are using <a href="http://www.fckeditor.net"> FCKeditor</a>. </jsp:attribute> <jsp:body> <fck:config ImageUploadURL="${ctx}${fck_uploadPath}&uploadRuleId=${_uploadRuleId}"/>//ctx fck_uploadPath都是事先设置好的 //这样就完成了动态传参过程 </jsp:body> </fck:editor>
第五步,创建connector.userActionImpl connector.userPathBuilderImpl
这个在实现了传递uploadRuleId的情况下就非常容易了,因为能够从session中取得rule 而这个rule中就可以设置权限管理信息,代码就不贴出来了
最后说明一下:
这个系统是能够实现页面模板与资源(js,css,img等等)所在服务器分离的,但是在这里还没有彻底实现(会有BUG),具体以后再实现