使用Struts 2.3.15.1
在struts2中实现文件上传。这是我已经多次做过的事情,但是,我试图包括一些健全性检查(主要是最大文件大小)。我将 fileUpload 拦截器作为我的堆栈中的最后一个拦截器(即 struts.xml )。我的堆栈包括一些内部拦截器以及 validationWorkflowStack 。我在 struts.properties 文件中设置了以下属性:
struts.multipart.maxSize = 2000000
除了上传文件外,我还在表单中传递了一些其他参数。表格定义为:
<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>
我相信大家都知道, validationWorkflowStack 包含 params 拦截器,它将请求参数设置为动作。这是问题,当上传的文件超过 maxSize 时, params 拦截器没有设置的参数。我已经介入了,而actionContext中没有任何内容。这不好,因为我需要那些参数来处理将导致的INPUT错误。
我错过了什么吗?
答案 0 :(得分:6)
从updated documentation开始,现在可以通过使用新的 JakartaStreamMultiPartRequest 来解决问题:
从Struts版本 2.3.18 开始,新的MultiPartRequest实现 添加了 - JakartaStreamMultiPartRequest。它可以用来处理 大文件,请参阅WW-3025了解更多详情,但您可以轻松设置
在struts.xml中<constant name="struts.multipart.parser" value="jakarta-stream" />
开始使用它。
来自链接的JIRA机构:
当任何尺寸限制超过时,立即a FileUploadBase.SizeLimitExceededException或 FileUploadBase.FileSizeLimitExceededException被抛出并解析 多部分请求终止而不提供请求参数 进一步处理。
这基本上使得任何Web应用程序都无法处理 大小限制优雅地超过了案例。
我的建议是请求解析应始终完成以进行传递 请求参数。超出大小限制/例外可能是 为了以后的检索而收集,应该是FileSizeLimitExeededException 映射到FileItem以允许对FileItem进行一些验证 应用水平。这将允许将上传输入字段标记为 如果上传的文件太大,那就是错误的。
其实我为此做了补丁(见附件)。有了这个补丁, commons-fileupload总是在大小的情况下完成请求解析 限制超出,只有在完成解析后才会抛出 如果检测到一个则例外。
和Chris Cranford的评论:
我正在为我正在调用的Struts2开发一个新的多部分解析器 JakartaStreamMultiPartRequest。
这个多部分解析器的行为与现有的雅加达相同 多部分解析器,除了它使用Commons FileUpload Streaming API,而不是将最大请求大小检查委托给文件 上传API,它是在内部完成的,以避免现有的问题 上传API打破循环迭代和参数丢失。
太棒了,谢谢你们:)
旧答案
我想这是由于
的不同行为首先解析文件(it should depend on their order in the page)时,如果文件超出了多部分请求大小的限制,则不会读取其他字段(表单字段),因此不会使用INPUT返回结果
对于MultiPartRequestWrapperStruts2 uses the Jakarta implementation:
struts.multipart.parser
- 此属性应设置为扩展MultiPartRequest的类。目前,该框架附带了Jakarta FileUpload实现。
您可以在Struts2官方网站or here上找到源代码(谷歌更快);这是发布多部分表单时调用的内容:
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);
}
}
}
然后,这是循环多部分项目,文件和表单字段的地方:
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);
}
}
}
将在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;
}
正如您所看到的,它处理的文件大小上限和请求大小上限差不多;
我看了很有趣的源代码,但你可以确认(或更正)这些假设,尝试调试MultiPartRequestWrapper,看看里面发生的是我认为发生的事情......祝你好运,玩得开心
答案 1 :(得分:1)
以下是我如何解决这个问题。我不会称之为解决方案。
答案 2 :(得分:0)
尝试在早期阶段进行javascript检查:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function checkSize(max_img_size)
{
var input = document.getElementById("upload");
// check for browser support (may need to be modified)
if(input.files && input.files.length == 1)
{
if (input.files[0].size > max_img_size)
{
alert("The file must be less than " + (max_img_size/1024/1024) + "MB");
return false;
}
}
return true;
}
</script>
</head>
<body>
<form action="demo_post_enctype.asp" method="post" enctype="multipart/form-data"
onsubmit="return checkSize(2097152)">
<input type="file" id="upload" />
<input type="submit" />
</body>
</html>