struts2文件上传失去参数 [英] struts2 file upload loosing parameters

查看:241
本文介绍了struts2文件上传失去参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用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结果在正常进程结束时重定向到
  • 违反整个请求的最大大小,这将(可能?)打破任何其他元素解析,因为它是一个安全机制,而不是像文件大小检查的功能;



当文件首先被解析(它应该依赖于它们在页面中的顺序),如果一个文件打破了多部分请求大小的限制,其他字段字段)不会被读取,因此不会返回INPUT结果。



Struts2为MultiPartRequestWrapper使用Jakarta实现

lockquote
目前,该框架附带了Jakarta FileUpload实现。

您可以在Struts2官方网站上找到源代码或这里(更快到谷歌);这是什么时候发布多部分表单:

  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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆