您的位置:首页 > 编程语言 > Java开发

struts2 使用 jakarta 上传文件时commons fileupload的异常捕捉

2012-08-27 12:48 555 查看
问题:

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

写道

...if (content_type != null && content_type.indexOf("multipart/form-data") != -1) {

MultiPartRequest multi = getContainer().getInstance(MultiPartRequest.class);

request = new MultiPartRequestWrapper(multi, request, getSaveDir(servletContext));

} else {

request = new StrutsRequestWrapper(request);

}

2. 建立 MultiPartRequestWrapper 时解析(parse) request,

Java代码

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做了什么

Java代码

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()

Java代码

....

//递归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

Java代码

/*

* 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

Xml代码

<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest"

ame="jakarta_yourself"

class="com.xxxxx.util.JakartaMultiPartRequest"

cope="default" optional="true" />

9.更改struts.properties

struts.multipart.parser=jakarta_yourself

10.就OK啦
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐