- 浏览: 92262 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
xtpgyaps:
楼主,问下,,怎么我重构了JakartaMultiPartRe ...
struts2 使用 jakarta 上传文件时commons fileupload的异常捕捉 -
netfork:
时间变化真快,楼主08年5月份发的贴,现在再看涉及到的源代码, ...
struts2 使用 jakarta 上传文件时commons fileupload的异常捕捉 -
harry:
不错很不错
Linda Rising:“你相信谁?”
问题:
struts2 使用jakarta 上传文件时,如果上传文件的大小超出commons fileupload(jakarta上传文件还是依赖commons-fileupload)设置的大小就会在进入action以前抛出异常.
如果想返回用户的输入界面(input),那么页面原来的参数会丢失。
首先看一下struts2 执行一个action的过程
1. 将用户请求发给org.apache.struts2.dispatcher.Dispatcher,
wrapRequest(HttpServletRequest request, ServletContext servletContext) 方法会判断是否"multipart/form-data",如果是建立一个multiPartRequest 的实例,并且建立MultiPartRequestWrapper
MultiPartRequest multi = getContainer().getInstance(MultiPartRequest.class);
request = new MultiPartRequestWrapper(multi, request, getSaveDir(servletContext));
} else {
request = new StrutsRequestWrapper(request);
}
2. 建立 MultiPartRequestWrapper 时解析(parse) request,
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); //upload 解析request并取得页面参数 List items = upload.parseRequest(createRequestContext(servletRequest)); ......
3.我们看一下ServletFileUpload(commons-fileupload v1.1.1) 的parseRequest做了什么
public List /* FileItem */ parseRequest(RequestContext ctx) throws FileUploadException { if (ctx == null) { throw new NullPointerException("ctx parameter"); } ArrayList items = new ArrayList(); String contentType = ctx.getContentType(); if ((null == contentType) || (!contentType.toLowerCase().startsWith(MULTIPART))) { throw new InvalidContentTypeException( "the request doesn't contain a " + MULTIPART_FORM_DATA + " or " + MULTIPART_MIXED + " stream, content type header is " + contentType); } int requestSize = ctx.getContentLength(); if (requestSize == -1) { throw new UnknownSizeException( "the request was rejected because its size is unknown"); } //关键就这里了,大小超出的异常,这里是所有上传文件合计的大小,如果超出就抛出异常 //这时上层是拿不到保存参数的items的 if (sizeMax >= 0 && requestSize > sizeMax) { throw new SizeLimitExceededException( "the request was rejected because its size (" + requestSize + ") exceeds the configured maximum (" + sizeMax + ")", requestSize, sizeMax); } String charEncoding = headerEncoding; if (charEncoding == null) { charEncoding = ctx.getCharacterEncoding(); } try { byte[] boundary = getBoundary(contentType); if (boundary == null) { throw new FileUploadException( "the request was rejected because " + "no multipart boundary was found"); } InputStream input = ctx.getInputStream(); MultipartStream multi = new MultipartStream(input, boundary); multi.setHeaderEncoding(charEncoding); boolean nextPart = multi.skipPreamble(); while (nextPart) { Map headers = parseHeaders(multi.readHeaders()); String fieldName = getFieldName(headers); if (fieldName != null) { String subContentType = getHeader(headers, CONTENT_TYPE); if (subContentType != null && subContentType .toLowerCase().startsWith(MULTIPART_MIXED)) { // Multiple files. byte[] subBoundary = getBoundary(subContentType); multi.setBoundary(subBoundary); boolean nextSubPart = multi.skipPreamble(); while (nextSubPart) { headers = parseHeaders(multi.readHeaders()); if (getFileName(headers) != null) { FileItem item = createItem(headers, false); OutputStream os = item.getOutputStream(); try { multi.readBodyData(os); } finally { os.close(); } items.add(item); } else { // Ignore anything but files inside // multipart/mixed. multi.discardBodyData(); } nextSubPart = multi.readBoundary(); } multi.setBoundary(boundary); } else { FileItem item = createItem(headers, getFileName(headers) == null); OutputStream os = item.getOutputStream(); try { multi.readBodyData(os); } finally { os.close(); } items.add(item); } } else { // Skip this part. multi.discardBodyData(); } nextPart = multi.readBoundary(); } } catch (IOException e) { throw new FileUploadException( "Processing of " + MULTIPART_FORM_DATA + " request failed. " + e.getMessage()); } return items; }
4.这之后才开始逐个进入interceptor,见DefaultActionInvocation.invoke()
.... //递归interceptor if (interceptors.hasNext()) { final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next(); UtilTimerStack.profile("interceptor: "+interceptor.getName(), new UtilTimerStack.ProfilingBlock<String>() { public String doProfiling() throws Exception { resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); return null; } }); } else { //如果有errors,resultCode会得到‘input’ resultCode = invokeActionOnly(); } ...
5.我们的目标就是返回input并且保留页面原来的参数,那么就要不要让ServletFileUpload抛出异常,并且要让strusts使用我们自己的jakart.
6.写自己的ServletFileUpload
/* * Copyright 2001-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.infowarelab.newcentury.web.util; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.FileUpload; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.MultipartStream; import org.apache.commons.fileupload.RequestContext; import org.apache.commons.fileupload.servlet.ServletRequestContext; import org.apache.log4j.Logger; /** * come from commons-fileupload * @author alfred */ public class ServletFileUpload extends FileUpload { // ---------------------------------------------------------- Class methods /** * Logger for this class */ private static final Logger logger = Logger.getLogger(ServletFileUpload.class); private List<String> errors = new ArrayList<String>(); /** * Constructs an uninitialised instance of this class. A factory must be * configured, using <code>setFileItemFactory()</code>, before attempting * to parse requests. * * @see FileUpload#FileUpload(FileItemFactory) */ public ServletFileUpload() { super(); } /** * Constructs an instance of this class which uses the supplied factory to * create <code>FileItem</code> instances. * * @see FileUpload#FileUpload() */ public ServletFileUpload(FileItemFactory fileItemFactory) { super(fileItemFactory); } /** * overide parseRequest */ public List /* FileItem */parseRequest(RequestContext ctx) throws FileUploadException { if (ctx == null) { throw new NullPointerException("ctx parameter"); } ArrayList items = new ArrayList(); String contentType = ctx.getContentType(); if ((null == contentType) || (!contentType.toLowerCase().startsWith(MULTIPART))) { throw new InvalidContentTypeException("the request doesn't contain a " + MULTIPART_FORM_DATA + " or " + MULTIPART_MIXED + " stream, content type header is " + contentType); } int requestSize = ctx.getContentLength(); if (requestSize == -1) { // throw new UnknownSizeException( // "the request was rejected because its size is unknown"); logger.error("the request was rejected because its size is unknown"); errors.add("the request was rejected because its size is unknown"); } String charEncoding = getHeaderEncoding(); if (charEncoding == null) { charEncoding = ctx.getCharacterEncoding(); } try { byte[] boundary = getBoundary(contentType); if (boundary == null) { // throw new FileUploadException( // "the request was rejected because " // + "no multipart boundary was found"); logger.error("the request was rejected because no multipart boundary was found"); errors.add("the request was rejected because no multipart boundary was found"); } InputStream input = ctx.getInputStream(); MultipartStream multi = new MultipartStream(input, boundary); multi.setHeaderEncoding(charEncoding); boolean nextPart = multi.skipPreamble(); while (nextPart) { Map headers = parseHeaders(multi.readHeaders()); String fieldName = getFieldName(headers); if (fieldName != null) { String subContentType = getHeader(headers, CONTENT_TYPE); if (subContentType != null && subContentType.toLowerCase().startsWith(MULTIPART_MIXED)) { // Multiple files. byte[] subBoundary = getBoundary(subContentType); multi.setBoundary(subBoundary); boolean nextSubPart = multi.skipPreamble(); while (nextSubPart) { headers = parseHeaders(multi.readHeaders()); if (getFileName(headers) != null) { FileItem item = createItem(headers, false); OutputStream os = item.getOutputStream(); try { multi.readBodyData(os); } finally { os.close(); } items.add(item); } else { // Ignore anything but files inside // multipart/mixed. multi.discardBodyData(); } nextSubPart = multi.readBoundary(); } multi.setBoundary(boundary); } else { FileItem item = createItem(headers, getFileName(headers) == null); OutputStream os = item.getOutputStream(); try { multi.readBodyData(os); } finally { os.close(); } items.add(item); } } else { // Skip this part. multi.discardBodyData(); } nextPart = multi.readBoundary(); } // remove SizeLimitExceededException if (getSizeMax() >= 0 && requestSize > getSizeMax()) { // throw new SizeLimitExceededException( // "the request was rejected because its size (" + requestSize // + ") exceeds the configured maximum (" + getSizeMax() + ")", // requestSize, getSizeMax()); logger.error("the request was rejected because its size (" + requestSize + ") exceeds the configured maximum (" + getSizeMax() + ")"); } } catch (IOException e) { logger.error("Processing of " + MULTIPART_FORM_DATA + " request failed. " + e.getMessage()); errors.add("Processing of " + MULTIPART_FORM_DATA + " request failed. " + e.getMessage()); // throw new FileUploadException( // "Processing of " + MULTIPART_FORM_DATA // + " request failed. " + e.getMessage()); } return items; } /** * @return the errors */ public List<String> getErrors() { return errors; } /** * @param errors the errors to set */ public void setErrors(List<String> errors) { this.errors = errors; } }
7.copy org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest,只是import上面自己的ServletFileUpload.这样就可以保存页面的所有参数了。
8.更改struts配置文件加入你自己的JakartaMultiReques
<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="jakarta_yourself" class="com.xxxxx.util.JakartaMultiPartRequest" scope="default" optional="true" />
9.更改struts.properties
struts.multipart.parser=jakarta_yourself
10.就OK啦
评论
不过说实在的,FileUploadBase这个类写的真得不怎么样,把错误信息直接throw了,struts2的JakartaMultiPartRequest类也不怎么样,把异常的错误信息直接加到errors中就算完事了,太不负责任了吧,国际化在哪里啊?
commons-fileupload组件抛异常有他的道理,楼主的作法会引发一个大的漏洞,我作了个上传文件的完整分析,大家可以看下面的文章。
http://www.iteye.com/topic/287800
发表评论
-
[转载]maven&jetty&eclipse
2008-10-28 20:09 1957个人觉得最好还是不要再pom.xml中写入关于maven-je ... -
Maven权威指南
2008-10-24 13:39 936这个网站对maven很全面的介绍 写道 虽然网络上有许多Ma ... -
spring IOC 在Web容器中的初始化
2008-07-16 15:50 01.web容器读取web.xml配置 <listener ... -
ransactionAttributeSourceAdvisor
2008-06-05 16:57 0在使用 Spring 自动代理配置事务时,要配置 Transa ...
相关推荐
在Struts2中处理文件上传功能时,通常需要依赖两个关键的第三方库:`commons-fileupload`和`commons-io`。这两个jar包在Java文件上传处理中扮演着至关重要的角色。 `commons-fileupload-1.2.1.jar`是Apache Commons...
以上就是关于Struts2中利用Apache Commons FileUpload和Apache Commons IO进行文件上传和下载的基本原理和实现流程。这两个库大大简化了处理文件操作的复杂性,提高了代码的可读性和可维护性。在实际开发中,应根据...
Struts2的Action类会接收这个文件,并使用`Commons FileUpload`库来处理文件内容。这个库处理文件分割、内存限制和临时存储等问题,确保上传过程的安全性和效率。 描述中的链接指向了CSDN博主johnjobs的一篇文章,...
在Struts2中,文件上传功能是一个常用特性,尤其在处理用户提交的多个文件时。本文将详细讲解如何使用Struts2进行多个文件的上传,重点是使用List集合进行上传。 首先,要实现Struts2的文件上传,必须引入必要的...
- Struts 2: 对于基于Struts 2的应用,可以通过配置`struts.multipart.parser`属性为`jakarta`来启用Apache Commons FileUpload。 总之,Apache Commons FileUpload是Java Web开发中处理文件上传不可或缺的工具,...
1. **文件上传组件**:在Struts2中,我们通常使用`Commons FileUpload`库来处理文件上传。这个库提供了处理多部分HTTP请求的能力,是Java中处理文件上传的标准库。我们需要在Struts2配置文件中引入对应的拦截器`...
在Struts2中,文件上传是通过`Commons FileUpload`库来处理的,这是一个Apache提供的开源组件,专门用于处理multipart/form-data类型的表单数据,也就是通常用于文件上传的表单类型。在Struts2的Action类中,我们...
Struts2提供了内置的支持来处理文件上传,主要利用了Apache Commons FileUpload库。在Struts2的Action类中,可以定义一个字段,类型为`java.io.File`或`org.apache.struts2.dispatcher.multipart.FileItem`,Struts2...
这通常涉及到添加`<constant>`标签来设置`struts.multipart.parser`属性为`jakarta`,因为Jakarta Commons FileUpload库是Struts2处理文件上传的基础: ```xml <constant name="struts.multipart.parser" value=...
文件上传功能在Struts2中通过`Struts2`提供的插件来实现,主要依赖于`Apache Commons FileUpload`库。首先,要在`struts.xml`配置文件中启用文件上传支持,设置`struts.multipart.parser`为`jakarta`或`native2...
在这个"struts2上传和下载文件详细源码"中,我们可以深入理解Struts2如何处理文件上传和下载操作。 1. 文件上传: 在Struts2中,文件上传主要依赖于Apache的Commons FileUpload库。首先,需要在struts.xml配置文件...
5. **错误处理**:当文件上传过程中出现错误时,可以使用Struts2的异常处理机制来返回错误信息。 关于SSH(Spring、Struts2、Hibernate)标签,它们代表了三个流行Java开发框架的首字母缩写。Spring提供了依赖注入...
总的来说,Struts2的文件上传和下载功能通过集成Apache Commons FileUpload库,大大简化了开发者的工作,提供了友好的API和配置选项,使得处理文件上传和下载变得轻而易举。开发者只需要关注业务逻辑,无需过多关注...
`jakarta`是基于Apache Commons FileUpload库,而`common`则是Struts1时代的上传方式,现在已较少使用。 3. **Action类的改造** 要处理文件上传,Action类需要继承`org.apache.struts2.interceptor....
- 在`struts.xml`配置文件中,需要启用`struts.multipart.parser`参数,通常设置为`jakarta`以使用Jakarta Commons FileUpload库。 - 配置Action类,声明一个或多个字段类型为`java.io.File`或`UploadedFile`,...
- Struts2使用Apache的Commons FileUpload库来处理文件上传。这个库将文件内容分解成多个部分,以便在内存有限的情况下处理大文件。 - HTTP协议中,文件上传通过`multipart/form-data`编码类型实现。 3. **配置...
Struts2通过Apache的Commons FileUpload库来处理文件上传。这个库提供了处理单个或多个文件上传的功能,并允许开发者设置最大文件大小、内存阈值等参数。在Struts2配置文件(struts.xml)中,我们需要开启文件上传...