struts.multipart 和 commons-fileupload下传插件解析
struts.multipart 和 commons-fileupload上传插件解析
使用的是struts2和commons-fileupload2.1.1
昨天遇到一个上传功能的错误,很是奇怪,原因是有的时候能够上传成功,有的不能上传成功,最为奇特的是需要报个错误,才能上传成功,不报错的就不能上传成功。今天算是弄清楚了,特地做个记录,首先报错的代码如下。
但是奇怪的是,报错了我竟然能够把正确上传附件,反而是不报错的反而上传不了附件。上传附件代码如下
根据调试发现,
这段代码在报错时,itr是有值的,而不报错的时候是没有值的。我很纳闷这究竟是怎么回事,在网上搜索了半天发现原来是我在struts.properties文件中把struts.multipart值设置的太小。我设置的值为
原来是我上次的文件大于这个值是就报错,小于这个值时就不报错。将这个值修改为1000000后,发现这回文件就压根上次不了。只好设置值为10,继续报错,可是就可以上传了。找了好多资料也没有发现有价值的。只好找到struts2的源码和commons-fileupload-1.2.1源码。调试后终于发现我的错误是在org.apache.commons.fileupload.FileUploadBase类中
在这段代码里面,如果设置的sizeMax小于requestSize时就会报错。这回报错原因找到了,继续调试,发现在上传没有报错的附件调试中,有一个类JakartaMultiPartRequest中的parse方法,如下:
里面files就是我要上传的附加信息,好终于找到了位置了。继续在附件很大时,上传要报错,就不会执行这个语句,此时在执行到List<FileItem> items = upload.parseRequest(request);就会获取到数据,这回终于弄清楚是怎么回事了。原来struts在请求时有一个参数struts.multipart.saveDir,其中值的就是在上传附件时,struts2已经和fileupload使用了默认的JakartaMultiPartRequest类上传了附件,那么我们再次使用fileupload组建获取附件时已经没有了,而报错时JakartaMultiPartRequest没有执行,所以可以使用fileupload获取附件,按这么说就只需要对上传附件做下修改就可以满足要求,再次debug发现,servlet的request对象原来是MultiPartRequestWrapper,在细看这个对象里面有一个值multi,multi有一个值为files。这会找到解决方法了,就是这个files把上传参数获取后,导致fileupload没有获取到。现在做如下修改:
今天太晚了,已经凌晨1点多了,明天继续补上
使用的是struts2和commons-fileupload2.1.1
昨天遇到一个上传功能的错误,很是奇怪,原因是有的时候能够上传成功,有的不能上传成功,最为奇特的是需要报个错误,才能上传成功,不报错的就不能上传成功。今天算是弄清楚了,特地做个记录,首先报错的代码如下。
org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (5727) exceeds the configured maximum (4028)
但是奇怪的是,报错了我竟然能够把正确上传附件,反而是不报错的反而上传不了附件。上传附件代码如下
request.setCharacterEncoding("UTF-8"); LoadPath loadPath = new LoadPath(); String path = loadPath.getUploadPath(); String fileName = ""; boolean isFlg = false; Util u = new Util(); // 判断有没有这个日期目录 String currData = u.getSysDate("yyyyMMdd"); // 判断目录在不,如果不在那么就添加一个目录 path = path + "/" + currData; File dir = new File(path); if (!dir.exists()) { // 不存在,需要创建目录 try { dir.mkdir(); this.log("创建目录:" + dir); } catch (Exception ex) { log.error("创建目录:" + path + "失败,原因:" + ex.toString()); } } // 文件上传部分 boolean isMultipart = ServletFileUpload.isMultipartContent(request); if (isMultipart == true) { DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); try { List<FileItem> items = upload.parseRequest(request);// 上传文件解析 Iterator<FileItem> itr = items.iterator();// 枚举方法 while (itr.hasNext()) { FileItem item = (FileItem) itr.next(); if (item.isFormField()) {// 判断是文件还是文本信息 } else { if (item.getName() != null && !item.getName().equals("")) {// 判断是否选择了文件 long time = System.currentTimeMillis(); String temPath = item.getName();// 返回上传文件在客户端的完整路径名称 fileName = temPath.substring(temPath .lastIndexOf("\\") + 1, temPath.length());// 原来文件名 String oldName = fileName.substring(0, fileName .lastIndexOf("."));// 文件名 String fileNameAtt = fileName.substring(fileName .lastIndexOf(".") + 1, fileName.length());// 文件后缀名 String newName = time + "." + fileNameAtt; // 此时文件暂存在服务器的内存当中 log.info("保存地址:" + path); File file = new File(path, newName); // 获取根目录对应的真实物理路径 item.write(file);// 保存文件在服务器的物理磁盘中 // 上传文件成功! isFlg = true; String loadPathStr = "upload/"+currData+"/"+newName; AppContext.getWySysFileManagerLogic().save(oldName, time+"", loadPathStr, Integer.parseInt(item.getSize()+"")); } } } } catch (Exception e) { e.printStackTrace(); log.info("文件上传失败!"); } } else { log.info("上传数据格式不是 multipart/form-data"); }
根据调试发现,
List<FileItem> items = upload.parseRequest(request);// 上传文件解析 Iterator<FileItem> itr = items.iterator();// 枚举方法
这段代码在报错时,itr是有值的,而不报错的时候是没有值的。我很纳闷这究竟是怎么回事,在网上搜索了半天发现原来是我在struts.properties文件中把struts.multipart值设置的太小。我设置的值为
struts.multipart.maxSize=4028
原来是我上次的文件大于这个值是就报错,小于这个值时就不报错。将这个值修改为1000000后,发现这回文件就压根上次不了。只好设置值为10,继续报错,可是就可以上传了。找了好多资料也没有发现有价值的。只好找到struts2的源码和commons-fileupload-1.2.1源码。调试后终于发现我的错误是在org.apache.commons.fileupload.FileUploadBase类中
if (sizeMax >= 0) { int requestSize = ctx.getContentLength(); if (requestSize == -1) { input = new LimitedInputStream(input, sizeMax) { protected void raiseError(long pSizeMax, long pCount) throws IOException { FileUploadException ex = new SizeLimitExceededException( "the request was rejected because" + " its size (" + pCount + ") exceeds the configured maximum" + " (" + pSizeMax + ")", pCount, pSizeMax); throw new FileUploadIOException(ex); } }; } else { if (sizeMax >= 0 && requestSize > sizeMax) { throw new SizeLimitExceededException( "the request was rejected because its size (" + requestSize + ") exceeds the configured maximum (" + sizeMax + ")", requestSize, sizeMax); } } }
在这段代码里面,如果设置的sizeMax小于requestSize时就会报错。这回报错原因找到了,继续调试,发现在上传没有报错的附件调试中,有一个类JakartaMultiPartRequest中的parse方法,如下:
public void parse(HttpServletRequest servletRequest, String saveDir) throws IOException { DiskFileItemFactory fac = new DiskFileItemFactory(); // Make sure that the data is written to file fac.setSizeThreshold(0); if (saveDir != null) { fac.setRepository(new File(saveDir)); } // Parse the request try { ServletFileUpload upload = new ServletFileUpload(fac); upload.setSizeMax(maxSize); List items = upload.parseRequest(createRequestContext(servletRequest)); for (Object item1 : items) { FileItem item = (FileItem) item1; if (LOG.isDebugEnabled()) LOG.debug("Found item " + item.getFieldName()); if (item.isFormField()) { LOG.debug("Item is a normal form field"); List<String> values; if (params.get(item.getFieldName()) != null) { values = params.get(item.getFieldName()); } else { values = new ArrayList<String>(); } // note: see http://jira.opensymphony.com/browse/WW-633 // basically, in some cases the charset may be null, so // we're just going to try to "other" method (no idea if this // will work) String charset = servletRequest.getCharacterEncoding(); if (charset != null) { values.add(item.getString(charset)); } else { values.add(item.getString()); } params.put(item.getFieldName(), values); } else { LOG.debug("Item is a file upload"); // Skip file uploads that don't have a file name - meaning that no file was selected. if (item.getName() == null || item.getName().trim().length() < 1) { LOG.debug("No file has been uploaded for the field: " + item.getFieldName()); continue; } List<FileItem> values; if (files.get(item.getFieldName()) != null) { values = files.get(item.getFieldName()); } else { values = new ArrayList<FileItem>(); } values.add(item); files.put(item.getFieldName(), values); } } } catch (FileUploadException e) { LOG.error("Unable to parse request", e); errors.add(e.getMessage()); } }
里面files就是我要上传的附加信息,好终于找到了位置了。继续在附件很大时,上传要报错,就不会执行这个语句,此时在执行到List<FileItem> items = upload.parseRequest(request);就会获取到数据,这回终于弄清楚是怎么回事了。原来struts在请求时有一个参数struts.multipart.saveDir,其中值的就是在上传附件时,struts2已经和fileupload使用了默认的JakartaMultiPartRequest类上传了附件,那么我们再次使用fileupload组建获取附件时已经没有了,而报错时JakartaMultiPartRequest没有执行,所以可以使用fileupload获取附件,按这么说就只需要对上传附件做下修改就可以满足要求,再次debug发现,servlet的request对象原来是MultiPartRequestWrapper,在细看这个对象里面有一个值multi,multi有一个值为files。这会找到解决方法了,就是这个files把上传参数获取后,导致fileupload没有获取到。现在做如下修改:
今天太晚了,已经凌晨1点多了,明天继续补上
1 楼
lpwdhx123
2012-03-05
收获颇多,谢谢你的文章,解决了我的燃眉之急