fmp*_*dmb 6 java struts2 file-upload multipartform-data request
使用Struts 2.3.15.1
在struts2中实现文件上传.这是我已经多次做过的事情,但是,我试图包括一些健全性检查(主要是最大文件大小).我将fileUpload拦截器作为我的堆栈中的最后一个拦截器(即struts.xml).我的堆栈包括一些内部拦截器以及validationWorkflowStack.我在struts.properties文件中设置了以下属性:
struts.multipart.maxSize = 2000000
Run Code Online (Sandbox Code Playgroud)
除了文件上传之外,我还在表单中传递了一些其他参数.表格定义为:
<s:form action="addResource" method="post" enctype="multipart/form-data">
<s:hidden name="rfqId" value='%{rfq.id}' />
<s:file name="uploadFile" id="uploadFile" label="File" size="40" value=""/>
....
</s:form>
Run Code Online (Sandbox Code Playgroud)
我相信大家都知道,validationWorkflowStack包含了params拦截器,它将请求参数设置为动作.这是问题,当上传的文件超过maxSize时,params拦截器没有设置的参数.我已经介入了,而actionContext中没有任何内容.这不好,因为我需要那些参数来处理将导致的INPUT错误.
我错过了什么吗?
从更新的文档中,现在可以使用新的JakartaStreamMultiPartRequest解决问题:
从Struts版本2.3.18开始,添加了一个新的MultiPartRequest实现 - JakartaStreamMultiPartRequest.它可用于处理大文件,有关详细信息,请参阅WW-3025,但您可以进行简单设置
Run Code Online (Sandbox Code Playgroud)<constant name="struts.multipart.parser" value="jakarta-stream" />在struts.xml中开始使用它.
来自链接的JIRA机构:
当任何大小限制超过时,将立即抛出FileUploadBase.SizeLimitExceededException或FileUploadBase.FileSizeLimitExceededException,并且终止对多部分请求的解析,而不提供用于进一步处理的请求参数.
这基本上使得任何Web应用程序都无法优雅地处理超出大小限制的情况.
我的建议是,请求解析应始终完成以传递请求参数.超出大小限制的情况/异常可能被收集以供以后检索,FileSizeLimitExeededException应映射到FileItem以允许在应用程序级别上对FileItem进行一些验证.如果上传的文件太大,这将允许将上传输入字段标记为错误.
实际上我做了一个补丁(参见附件).使用此补丁,commons-fileupload总是在大小限制超出的情况下完成请求解析,并且只有在完成解析后才会在检测到异常时抛出异常.
和Chris Cranford的评论:
我正在为Struts2开发一个新的多部分解析器我正在调用JakartaStreamMultiPartRequest.
这个多部分解析器的行为与现有的Jakarta多部分解析器相同,只是它使用Commons FileUpload Streaming API而不是将最大请求大小检查委托给文件上载API,它是在内部完成的,以避免上传API的现有问题打破循环迭代和参数丢失.
太棒了,谢谢你们:)
老答案
我想这是由于不同的行为
首先解析文件(它应该取决于它们在页面中的顺序),如果文件突破了多部分请求大小的限制,其他字段(表单字段)将不会被读取,因此不会返回INPUT结果.
Struts2使用 MultiPartRequestWrapper 的Jakarta实现:
struts.multipart.parser- 此属性应设置为扩展MultiPartRequest的类.目前,该框架附带了Jakarta FileUpload实现.
您可以在Struts2官方网站或此处找到源代码(更快到google); 这是发布多部分表单时调用的内容:
public void parse(HttpServletRequest request, String saveDir) throws IOException {
try {
setLocale(request);
processUpload(request, saveDir);
} catch (FileUploadBase.SizeLimitExceededException e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Request exceeded size limit!", e);
}
String errorMessage = buildErrorMessage(e, new Object[]{e.getPermittedSize(), e.getActualSize()});
if (!errors.contains(errorMessage)) {
errors.add(errorMessage);
}
} catch (Exception e) {
if (LOG.isWarnEnabled()) {
LOG.warn("Unable to parse request", e);
}
String errorMessage = buildErrorMessage(e, new Object[]{});
if (!errors.contains(errorMessage)) {
errors.add(errorMessage);
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后,这是循环多部分项目,文件和表单字段的位置:
private void processUpload(HttpServletRequest request, String saveDir) throws FileUploadException, UnsupportedEncodingException {
for (FileItem item : parseRequest(request, saveDir)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Found item " + item.getFieldName());
}
if (item.isFormField()) {
processNormalFormField(item, request.getCharacterEncoding());
} else {
processFileField(item);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这将在FileUploadBase中针对每个项目在此实现中结束:
FileItemStreamImpl(String pName, String pFieldName,
String pContentType, boolean pFormField,
long pContentLength) throws IOException {
name = pName;
fieldName = pFieldName;
contentType = pContentType;
formField = pFormField;
final ItemInputStream itemStream = multi.newInputStream();
InputStream istream = itemStream;
if (fileSizeMax != -1) {
if (pContentLength != -1
&& pContentLength > fileSizeMax) {
FileSizeLimitExceededException e =
new FileSizeLimitExceededException(
format("The field %s exceeds its maximum permitted size of %s bytes.",
fieldName, fileSizeMax),
pContentLength, fileSizeMax);
e.setFileName(pName);
e.setFieldName(pFieldName);
throw new FileUploadIOException(e);
}
istream = new LimitedInputStream(istream, fileSizeMax) {
@Override
protected void raiseError(long pSizeMax, long pCount)
throws IOException {
itemStream.close(true);
FileSizeLimitExceededException e =
new FileSizeLimitExceededException(
format("The field %s exceeds its maximum permitted size of %s bytes.",
fieldName, pSizeMax),
pCount, pSizeMax);
e.setFieldName(fieldName);
e.setFileName(name);
throw new FileUploadIOException(e);
}
};
}
stream = istream;
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它处理的文件大小上限和请求大小上限差别很大;
我看了很有趣的源代码,但你可以确认(或纠正)这些假设,尝试调试MultiPartRequestWrapper,看看里面发生的是我认为发生了什么......祝你好运,玩得开心.