struts2文件上传失去参数 [英] struts2 file upload loosing parameters
问题描述
使用Struts 2.3.15.1
在struts2中实现文件上传。这是我已经做了很多次,但是,我试图包括一些理智检查(主要是最大文件大小)。我将 fileUpload 拦截器作为堆栈中的最后一个拦截器(即 struts.xml )。我的堆栈包含一些内部拦截器以及 validationWorkflowStack 。我在 struts.properties 文件中设置了以下属性:
$ b
struts.multipart.maxSize = 2000000
除了文件上传以外,我还传递了其他一些参数。表单被定义为:
< s:form action =addResourcemethod =postenctype =multipart / form -data>
< s:hidden name =rfqIdvalue ='%{rfq.id}'/>
....
< / s:form>
由于我确定我们都知道, validationWorkflowStack 包含< params 拦截器,它将请求参数设置到动作上。这是一个问题,当上传的文件超过 maxSize 时,没有设置 params 拦截器的参数。我已经走过了,actionContext里没有任何东西。这是不好的,因为我需要这些PARAMS来处理INPUT错误,会导致。
我错过了什么吗?
$ b
从 http://struts.apache.org/release/2.3.x/docs/file-upload.html#FileUpload-AlternateLibrariesrel =nofollow noreferrer>更新的文档,现在可以通过使用新的 JakartaStreamMultiPartRequest :
从Struts版本2.3.18开始, MultiPartRequest
被添加 - JakartaStreamMultiPartRequest。它可以用来处理
大文件,请参阅 WW-3025 有关更多详细信息,但可以简单设置
$ b< constant name =struts.multipart .parservalue =jakarta-stream/>
在struts.xml中开始使用它。
从链接的JIRA主体:
当任何大小限制超过时,立即
FileUploadBase.SizeLimitExceededException或
FileUploadBase.FileSizeLimitExceededException抛出并解析
多部分请求终止,不提供请求参数
用于进一步处理。
这基本上使得任何web应用程序都不可能正常处理
大小限制的情况。
我的建议是请求解析应该始终完成, b $ b请求参数。大小限制超出的情况/例外情况可能是以后检索收集的
,FileSizeLimitExeededException应该是
映射到FileItem以允许对
应用程序级别的FileItem进行一些验证。如果上传文件太大,这将允许将上传输入字段标记为
erronous。实际上,我为它做了一个补丁(参见附件)。有了这个补丁,
commons-fileupload总是会在
限制超出的情况下完成请求解析,并且只有在完成解析后才会检测到
异常。
和Chris Cranford的评论:
我正在研究新的多部分解析器为Struts2我正在调用
JakartaStreamMultiPartRequest。
这个多部分解析器的行为与现有的Jakarta
多部分解析器相同,除了它使用Commons FileUpload Streaming
API,而不是将最大请求大小检查委托给File
Upload API,这是在内部完成的,以避免现有的
Upload API中断循环迭代和参数的问题
真棒,谢谢你们:)
$ b $ hr
老答案 我想这是由于$ b $的不同行为b 当文件首先被解析(它应该依赖于它们在页面中的顺序),如果一个文件打破了多部分请求大小的限制,其他字段字段)不会被读取,因此不会返回INPUT结果。 Struts2为MultiPartRequestWrapper使用Jakarta实现: 您可以在Struts2官方网站上找到源代码或这里(更快到谷歌);这是什么时候发布多部分表单:
lockquote
public void parse(HttpServletRequest request,String saveDir)throws IOException {
试试{
setLocale(request);
processUpload(request,saveDir);
catch(FileUploadBase.SizeLimitExceededException e){
if(LOG.isWarnEnabled()){
LOG.warn(请求超出大小限制!,e);
}
字符串errorMessage = buildErrorMessage(e,new Object [] {e.getPermittedSize(),e.getActualSize()});
if(!errors.contains(errorMessage)){
errors.add(errorMessage);如果(LOG.isWarnEnabled()){
LOG.warn(无法解析请求,e);
}
} catch(Exception e){
}
字符串errorMessage = buildErrorMessage(e,new Object [] {});
if(!errors.contains(errorMessage)){
errors.add(errorMessage);
code
$ b那么这就是它的地方循环多部分Items,包括文件和表单字段:
private void processUpload(HttpServletRequest request,String saveDir)throws FileUploadException,UnsupportedEncodingException { ($)
for(FileItem item:parseRequest (item.isFormField()){
processNormalFormField(item,request.getCharacterEncoding());
if
} else {
processFileField(item);
$ / code $ / pre
即将结束 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(
格式(字段%s超过了最大允许的大小%s字节。,
fieldName,fileSizeMax),
pContentLength,fileSizeMax);
e.setFileName(pName);
e.setFieldName(pFieldName);
抛出新的FileUploadIOException(e);
}
istream = new LimitedInputStream(istream,fileSizeMax){
@Override
protected void raiseError(long pSizeMax,long pCount)
throws IOException {
itemStream.close(真);
FileSizeLimitExceededException e =
FileSizeLimitExceededException(
格式(字段%s超过最大允许的大小%s字节。,
fieldName,pSizeMax),
pCount,pSizeMax);
e.setFieldName(fieldName);
e.setFileName(name);
抛出新的FileUploadIOException(e);
}
};
}
stream = istream;
$ b 你可以看到,它处理的文件大小上限和请求大小上限;
我已经查看了源代码的乐趣,但是您可以真正确认(或更正)这个假设,尝试调试MultiPartRequestWrapper,看看里面发生了什么是我认为正在发生的事情...祝你好运,玩得开心。
Using Struts 2.3.15.1
Implementing file upload in struts2. This is something I've done a number of times, however, I'm trying to include some sanity checks (i.e. max file size primarily). I have the fileUpload interceptor in place as the last interceptor in my stack (i.e. struts.xml). My stack includes a few in-house interceptors as well as the validationWorkflowStack. I've set the following property in my struts.properties file:
struts.multipart.maxSize = 2000000
In addition to the file upload, I'm passing a few other params in my form. Form is defined as:
<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>
As I'm sure we all know, the validationWorkflowStack includes the params interceptor, which sets the request params onto the action. Here's the issue, when the file being uploaded exceeds the maxSize, there are no params for the params interceptor to set. I've stepped through is and there's nothing in the actionContext. This is not good, because I need those params to handle the INPUT error that will result.
Am I missing something?
解决方案 Problem solved !
From the updated documentation, now the problem can be solved by using the new JakartaStreamMultiPartRequest :
As from Struts version 2.3.18 a new implementation of MultiPartRequest
was added - JakartaStreamMultiPartRequest. It can be used to handle
large files, see WW-3025 for more details, but you can simple set
<constant name="struts.multipart.parser" value="jakarta-stream" />
in struts.xml to start using it.
From the linked JIRA body :
When any size limits exceed, immediately a
FileUploadBase.SizeLimitExceededException or
FileUploadBase.FileSizeLimitExceededException is thrown and parsing of
the multipart request terminates without providing request parameters
for further processing.
This basically makes it impossible for any web application to handle
size limit exceeded cases gracefully.
My proposal is that request parsing should always complete to deliver
the request parameters. Size limit exceeded cases/exceptions might be
collected for later retrieval, FileSizeLimitExeededException should be
mapped to the FileItem to allow some validation on the FileItem on
application level. This would allow to mark upload input fields as
erronous if the uploaded file was too big.
Actually I made a patch for that (see attachment). With this patch,
commons-fileupload always completes request parsing in case of size
limit exceedings and only after complete parsing will throw an
exception if one was detected.
and Chris Cranford's comment:
I am working on a new multipart parser for Struts2 I am calling
JakartaStreamMultiPartRequest.
This multi-part parser behaves identical to the existing Jakarta
multi-part parser except that it uses the Commons FileUpload Streaming
API and rather than delegating maximum request size check to the File
Upload API, it's done internally to avoid the existing problem of the
Upload API breaking the loop iteration and parameters being lost.
Awesome, thanks guys :)
Old answer
I guess it is due to the different behavior of
- a single file (or more files) that is exceeding its maximum defined size, and then can be redirected back at the end of a normal process with the INPUT result, and
- the violation of the maximum size of the entire Request, that will (probably?) break any other element parsing, because it is a security mechanism, not a feature like the file size check;
When the files are parsed first (it should depend on their order in the page), if a file breaks the limit of the multipart request size, the other fields (the form fields) won't be read and hence not returned back with the INPUT result.
Struts2 uses the Jakarta implementation for the MultiPartRequestWrapper:
struts.multipart.parser
- This property should be set to a class that extends MultiPartRequest. Currently, the framework ships with the Jakarta FileUpload implementation.
You can find the source code on Struts2 official site or here (faster to google); this is what is called when posting a multipart form:
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);
}
}
}
then, this is where it cycles the multipart Items, both files and form fields:
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);
}
}
}
that will end, in the FileUploadBase, in this implementation for each item:
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;
}
as you can see, it handles pretty differently the file size cap and the request size cap;
I've looked at the source for fun but you could really confirm (or correct) this assumptions, trying to debug the MultiPartRequestWrapper to see if what happens inside is what I think is going on... good luck and have fun.
这篇关于struts2文件上传失去参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!