悲剧的一个BUG!STRUTS2 上传 问题。

悲剧的一个BUG····STRUTS2 上传 问题。
-------------------------
搞了大半天,总是奇怪问题的现象,最后附录自己的思考过程。
---------------------------------------
现象:

由于当用户在上传文件的时候,由于文件在上传过程中流还没传送完毕结果客户端就断开了链接(可能耗时比较久,造成浏览器假死的状态,然后用户强制关闭了浏览器的进程),导致上传组件抛出异常,而且这个异常在关闭上传页面之后再打开的时候还是存在,引起上传的功能点崩溃。


----------------------分析-------------------
原因分析:

原先使用 struts2 自带的common-fileupload 组件上传文件。

当文件上传出错时(包括强行关闭浏览器导致的流关闭错误),会产生actionerror对象 。

在进入Action之前 会 经过 validate 方法,

validate 方法 检测到 actionerror 后,会直接转向input页面,导致错误信息一直出现,从而导致上传组件不可用。只能通过服务器重启来解决。
(PS:spring 配置的action是单列)



---------STRUTS2源码--------

源码大家自己去看吧。
大概流程就是


FilterDispatcher--->Dispatcher--->MultiPartRequestWrapper

然后交由Apache的commons-fileupload组件来解析了。
在MultiPartRequestWrapper的构造方法中,会调用MultiPartRequest(默认为JakartaMultiPartRequest类)的parse方法来解析请求。

--------------------------------------------------------------
解决方案如下:

1. 覆盖组件中的JakartaMultiPartRequest方法,丢弃error对象。
(据说还诡异的出现问题。)

2. 修改action类,重写validate ()方法,清除ErrorsAndMessages 。


3. 更换组件。采用smartupload组件(但是这个组件对大文件上传存在着内存溢出的问题,只支持到100M 左右)


所以妥妥的 方案2.。。。。。。。。。。。


---------------方案一-----------------



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);
List items = upload.parseRequest(createRequestContext(servletRequest));

for (Object item1 : items) {
FileItem item = (FileItem) item1;
if (log.isDebugEnabled()) log.debug("Found item " + item.getFieldName());
if (item.isFormField()) {
log.debug("Item is a normal form field");
List<String> values;
if (params.get(item.getFieldName()) != null) {
values = params.get(item.getFieldName());
} else {
values = new ArrayList<String>();
}

// note: see http://jira.opensymphony.com/browse/WW-633
// basically, in some cases the charset may be null, so
// we're just going to try to "other" method (no idea if this
// will work)
String charset = servletRequest.getCharacterEncoding();
if (charset != null) {
values.add(item.getString(charset));
} else {
values.add(item.getString());
}
params.put(item.getFieldName(), values);
} else {
log.debug("Item is a file upload");

// Skip file uploads that don't have a file name - meaning that no file was selected.
if (item.getName() == null || item.getName().trim().length() < 1) {
log.debug("No file has been uploaded for the field: " + item.getFieldName());
continue;
}

List<FileItem> values;
if (files.get(item.getFieldName()) != null) {
values = files.get(item.getFieldName());
} else {
values = new ArrayList<FileItem>();
}

values.add(item);
files.put(item.getFieldName(), values);
}
}
} catch (FileUploadException e) {
log.error(e);
e.printStackTrace();
//注意此处的修改~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//errors.add(e.getMessage());
}
}



方案1的方法:别忘记了配置struts.xml的bean ,和struts.properties.


--------------思考过程---------------
1. 为什么关闭浏览器后,问题依旧存在。。
自然会想到单列~~~~~~~~~~~~

2. 为什么后续问题不进ACTION
自然会想到拦截·····是什么拦截呢?(结合源码分析中的error对象,
这个对象校验使用到,那么 自然而然 变成是 校验拦截)


3.结合起来,问题就不奇怪了·········
,要发现问题现象和JAVA领域知识相结合。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值