问题背景:
使用ssh框架开发一个站点,需要使用在线编辑器,以往没用框架直接jsp时使用的是fckeditor编辑器。
这次结合struts框架开发,开始时选择了tinyMCE(扩展性不错,博客园用的也是这个),但项目进行到一半时候发现需要编辑器能够实现上传文件功能,以便
于方便传含图片的新闻及加附件。但是tinymce不支持,需要自己扩展。时间原因,只好重新选择其他编辑器。
什么kindeditor、ueditor看了看,最后选择了kindeditor-v4.1.6。问题来了
问题描述:
1、tinyMCE不支持直接上传文件,需扩展。有时间再整http://www.cnblogs.com/ryanding/archive/2010/11/02/1866694.html
2、kindeditor支持上传文件。但由于struts的过滤器将HttpServletRequest对象包装成MultiPartRequestWrapper,如果直接用示例文件upload_json.jsp。
关键代码:
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8");
List items = upload.parseRequest(request);
Iterator itr = items.iterator();
while (itr.hasNext()) {
FileItem item = (FileItem) itr.next();
String fileName = item.getName();
long fileSize = item.getSize();
if (!item.isFormField()) {
//检查文件大小
if(item.getSize() > maxSize){
out.println(getError("上传文件大小超过限制。"));
return;
}
//检查扩展名
String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
if(!Arrays.<String>asList(extMap.get(dirName).split(",")).contains(fileExt)){
out.println(getError("上传文件扩展名是不允许的扩展名。\n只允许" + extMap.get(dirName) + "格式。"));
return;
}
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
String newFileName = df.format(new Date()) + "_" + new Random().nextInt(1000) + "." + fileExt;
try{
File uploadedFile = new File(savePath, newFileName);
item.write(uploadedFile);
}catch(Exception e){
out.println(getError("上传文件失败。"));
return;
}
JSONObject obj = new JSONObject();
obj.put("error", 0);
System.out.println(" url: "+saveUrl + newFileName);
obj.put("url", saveUrl + newFileName);
out.println(obj.toJSONString());
}
}
会发现 upload.parseRequest(request);取不到值。
问题分析:
kindeditor 在java环境中用到了 commons-fileupload-1.2.1.jar 组件。 在Common- FileUpload中,它把从客户端提交过来的表单封装成一个个FileItem对象,这也是它实现文件上传功能 的核心类。另一个很重要的类就是FileUploadBase,他的功能就是解析请求(request),如进行上传文 件大小验证,请求类型验证(文件上传的enctype要设置成multipart/form-data)等。我们经常用到它 的子类ServletFileUpload。在FileUploadBase解析 request的过程中会将文件保存到内存,如果文件大 小大于我们设置的缓存的大小,它将把文件的其他内容保存到一个临时目录,当我们对FileItem 对象实 现正真上传时会从内存区或临时目录将文件保存到正真的上传目录。
解决方法:
1、指定struts的filter过滤的url类型,防止其对访问jsp页面的请求request进行封装。(已验证)
<url-pattern>*.action</url-pattern>或者<url-pattern>*.do</url-pattern>
2、写个Servlet来代替upload_json.jsp的功能。upload_json.jsp里面的代码大部分都可以复制到Servlet中, upload_json.jsp中的out.prinln返回值用 resp.getWriter().println()代替就行。(未验证)
3、修改upload_json.jsp.修改获得request对象的方法。详见http://www.kaifajie.cn/struts/9086.html
//Struts2 请求 包装过滤器
MultiPartRequestWrapper wrapper = (MultiPartRequestWrapper) request;
//获得上传的文件名
String fileName = wrapper.getFileNames("imgFile")[0];//imgFile,imgFile,imgFile
//获得文件过滤器
File file = wrapper.getFiles("imgFile")[0];(未验证、理论可行)
4、重写action使其可以获得File对象。(已验证)
看完上面几种方法,不知道大家发现没有,其实kindeditor上传文件的方法和以前没什么不一样。唯一不一样的是我们在不了解起上传页面情况下不知道其表单的file域的name属性。通过调试,我们可以发现file对象的实际名称。一般如果file域的name属性为“file”,则对应处理的action类这么写:
public class CommonAction extends ActionSupport{
private static final long serialVersionUID = 1L;
//所属类型,按模块划分
private String type;
//上传文件
private File file;
//上传文件名字
private String fileFileName;
//返回地址列表(存入数据库)
private String fileURL;
kindeditor的name属性为imgFile,因此将名字改过来,就可以了。