`
lyy3323
  • 浏览: 85937 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

悲剧的一个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领域知识相结合。




分享到:
评论
59 楼 lyy3323 2012-07-16  
黑暗浪子 写道
lyy3323 写道
呵呵~~~~~
统计一下 大家公司项目的里action在SPRING 中的配置情况好吗?
呵呵,和struts2有什么关系?
是SPRING的错误配置造成的OK?

你好好学习一下如何让struts2和spring集成在一块。我看这帖子很久了就是没发言。忍不住了我,发现你就是死不承认自己对struts2还没了解透彻。很多人都已经告诉你原委了。甚至有人一针见血的指出了struts和struts2有本质不同。


1年前的文章了,现在回过头来,多谢大家批评~s2不配置成多列是无法想象的,愿各位不要被我误导~
58 楼 Josun 2011-04-08  
学习了。。。
57 楼 无根V稻草 2011-04-08  
学习了 我配的时候都没用过单例
56 楼 Speak-shuai 2011-04-08  
学习了 自己的水平又有了提高
55 楼 ilrxx 2011-02-11  
单例的本意是为了减少过多创建对象而造成的内存开销大,也要看场合。
54 楼 beyondqinghua 2011-02-10  
LZ真杯具!
53 楼 yanbingwei 2011-02-04  
struts2的Action使用命令模式 , 每次请求都会生成一个新的action来处理用户的请求 ,因此action不要配置成单例的,否则会出现许多意想不到的错误
52 楼 yjl6691088 2011-02-03  
lz struts1 与struts2 最基本区别是神马?

1 貌似是单例
2 发一次请求new一个action 
51 楼 coolbamboo2008 2011-02-02  
还是很佩服楼主的钻研精神的
50 楼 little_shieh 2011-02-02  
悲剧都是自己弄出来的,
struts1和struts2的最大区别就是action是否单例,你把struts2搞成个单例不出问题才怪呢。
49 楼 tiyi 2011-02-02  
s2用单例?牛逼!
48 楼 dwangel 2011-02-02  
xrqsjj 写道
这样的帖子蛮好的,大家讨论的这么激烈,干嘛要隐藏呢,难道大家都是神马

因为这种大标题的帖子会给不明真相群众很大误解,本来是楼主一知半解,当结论发表了。
47 楼 buyajun 2011-02-01  
现在内存那么便宜,CPU的速度也快,还在为区区几个性能指标纠结么?
46 楼 黑暗浪子 2011-01-31  
lyy3323 写道
呵呵~~~~~
统计一下 大家公司项目的里action在SPRING 中的配置情况好吗?
呵呵,和struts2有什么关系?
是SPRING的错误配置造成的OK?

你好好学习一下如何让struts2和spring集成在一块。我看这帖子很久了就是没发言。忍不住了我,发现你就是死不承认自己对struts2还没了解透彻。很多人都已经告诉你原委了。甚至有人一针见血的指出了struts和struts2有本质不同。
45 楼 黑暗浪子 2011-01-31  
SeanHe 写道
lyy3323 写道
lanxia39 写道
lyy3323 写道
Agrael 写道
是你自己弄的悲剧,struts2的action需要是prototype的。你配置成singleton的当然会保留之前的状态。验证的时候有那个Error的状态自然会错。

spring 里的action 配置 相信大家基本都是配的单列。

项目配置的问题。

我也不明白为什么把action配置成singleton有什么好处。

struts1.x中的action通常情况下,我们只会定义成员函数,不会定义成员变量,是一个无状态的类对象,也就是只有成员函数,没有成员变量,不会引起并发和线程访问问题,设置为单例,可以节省内存空间,提高执行效率,而struct2,action定义为一个普通的javaben,具有状态,如果定义成单例会引起并发和线程访问问题。当然你也可以按照struct1.x的方式来用struct2

的确struts1.x 的action是默认的单列模式,参数是由request来传递,
所以在使用成语变量的时候要额外注意。

struts2.x 作为一个状态BEAN  单列确实会引发同步问题。

可惜啊 ,现在的项目大家都使用spring , 都没配置bean的状态,默认是单例~~~~


struts2的spring插件负责将struts2的Action动态的加入到Spring的beanfactory里,你可以去看一下代码被动态加入到beanfactory里的action的scope默认是prototype

44 楼 yxhzj 2011-01-30  
beer2008cn 写道
struts2 比struts1优秀的其中一点就是,它不需要singleton


不需要singleton就是优秀?这样做的代价也是很大的,有的时候就变成泛滥的使用成员变量,成了悲剧。
43 楼 beer2008cn 2011-01-30  
struts2 比struts1优秀的其中一点就是,它不需要singleton
42 楼 yin_bp 2011-01-29  
有空看看bbossgroups3.0中的mvc框架和aop框架以及持久层框架,一整套体系,不过mvc框架还在孵化中。。。。绝对不比struts 2和spring mvc逊色哦
mvc中也自带了个上传的功能,有空写篇文章给大家指教,呵呵
最近发布了个bbossgroups专题论坛,没空写文章。。。。。。
http://www.xtzy.com:800/forums/list.page
41 楼 jxdwinter 2011-01-29  
我一般都是把 action配置成prototype,单例模式会出现很多问题。
40 楼 yagesi 2011-01-29  
fatesymphony 写道
struts2整合spring,action不能为单例,不是不建议,是根本不能为单例。

在说了上传文件出错时?不应该产生actionerror吗????


强烈赞同....

相关推荐

Global site tag (gtag.js) - Google Analytics