发现一个问题,使用struts进行文件上传,如果有些参数没有完全定义在ActionForm中,需要从request.getParameter获取,在表单提交并且validate失败返回input页面时,这部分需要从request.getPrameter获取的参数数据都丢失了,即使再对request进行multipart解析也不能得到。
经过分析,发现struts的ActionServlet在接收到multipart请求之后,在RequestProcessor中会对request进行封装:MultiRequestWrapper,然后在Action执行完之后,又将已经封装的request重新还原。以下是部分代码,截直RequestProcessor:
封装:
protected HttpServletRequest processMultipart(HttpServletRequest request) {
if (!"POST".equalsIgnoreCase(request.getMethod())) {
return (request);
}
String contentType = request.getContentType();
if ((contentType != null) &&
contentType.startsWith("multipart/form-data")) {
return (new MultipartRequestWrapper(request));
} else {
return (request);
}
}
还原:
在doForward和doInclude中在forward和include之前都执行了下面的代码:
if (request instanceof MultipartRequestWrapper) {
request = ((MultipartRequestWrapper) request).getRequest();
}
问题就出现在这儿。在经过测试之后,发现request只能进行一次multipart解析,这或许和解析request的时候调用了request.inputStream有关,第一次调用之后再调用就不能获取其中的有效内容了。因此发现request在调用CommonsMultipartRequestHandler.handleRequest进行解析后并还原后,调用common-upload对request进行解析已经得不到任何得提交内容了,因此当Form验证失败,返回input页面时,即使再进行multpart解析,也不能通过request.getPrameter取到你想要的数据。而此时,表单中的数据却不会丢失(定义在ActionForm中的表单域),这是因为struts的html系列tag在redisplay时值都是从ActionForm获取的。
在将RequestProcessor.doForward和doInclude中还原request的语句注释后,问题得到了解决。到目前还不清楚为什么struts要还原request,难道是因为chain的原因?
webwork中应该不会出现这个问题,因为webwork中无论ServletDispatcher还是FilterDispatcher在对request wrap之后都没有再还原。
XP
SCRUM
需要并且应该持续关注、思考。
一些共同点:
快速迭代
持续改进
注重测试
团队协作
很久没有来这儿了。其实我很喜欢BLOG,可以记下每天工作中的所思所想。我是一个喜欢思考的人,经常有一些想法,有这么一块地方,能够把自己的经验、想法、创造记录下来,沉积起来,对自己无疑是一种财富。
不知道是不是有人会写项目经理日志,我觉得这是一个很好的事情。以前做项目管理的时候只是弄了一个“项目事件”,记录项目开发过程中发生的、自己觉得是重要的事情,比如某某人进入项目组、离开项目组了,某某模块版本发布了,发生了什么大的费用等等。写项目经理日志,或者开发日志、工作日志也行,把自己在工作中、项目开发过程中、项目管理过程中的零零碎碎的想法记录下来,会是一件很棒的事情。人不应该懒,再累心情再遭也应该坚持写这种日志。
或许小笔记本、那种可以随身携带的那种是一件更好的日志记录工具,可惜容量不够,而且不能检索。掌上电脑?写起来似乎麻烦了,table-pc,好像又太大了,携带不方便,可惜,要是手写识别技术更智能一点、掌上电脑更薄一点,而且可以展开屏幕就棒了。可惜。
JDK1.5出来很久了,一直没有研究。这倒不是没有时间,而是觉得J2EE服务器要支持JDK1.5还需要一段时间,而多数客户还在使用JDK1.4,因此要基于JDK1.5开发Web应用程序还不现实,因此一直没有去弄这玩意。
今天由于研究Desktop的开发,装了1.5,发现1.5中Java程序已经可以获得本地系统的外观,我试着不断的变换了xp的theme,Java程序始终能够保持和系统的外观一致;而且以前使用SkinLF后,在web start程序中JOptionPane的窗体经常出不来的问题也解决了。这可是一个非常好的消息。
另一个好消息是JDK的下一个版本将对Swing/AWT组件进行增强。
为Java感到高兴!
这里列出一部分Java Desktop的开发资源。
1。A java.net community for JavaDeskTop
这是sun主持的资源很全的社区,有很多关于JavaDeskTop开发的资源。
2。JDIC(Java Desktop Integration Components)
Sun主持的致力于java和本地应用程序集成、交互的组件集,非常棒。目前有5大组件。
Desktop
FileTypes
Brower
System Tray Icon
Packager
3。JDNC(Java Desktop Network Component)
4。JExePack
一个将Java程序转化为Exe程序的组件。
5。JSmooth
作用同JExePack。
6。JavaService
一个将Java程序转化为NT Service的组件。
7。SKinLF
非常棒的Java LookAndFeel实现,采用配置包的形式定义Java的LookAndFeel,可以很方便的定义自己的LookAndFeel。它的网站上提供了大量Skin下载,其中不乏精品。
8。JGoodies
JGoodies最出名的是它的FormLayout,它使swing和AWT应用程序的布局变得非常简单。由于它的影响,已经有专门针对它的DESIGNER出现,Eclipse也有相应的插件支持。FormLayout使Java的几个默认Layout相形见绌。
JGoodies还有一组Swing/Awt组件,可以很方便的创建Wizard、对话框、Splash窗体、About窗体等GUI部件。
9。Rachel(Open Source Resource Loading Toolkit for Java Web Start )
和WebStart打过交道的人可能知道,要在webstart中读取解析zip或者jar资源是一件非常困难的事,然而有些资源又必须以zip或者jar的形式存在,比如SKinLF就是这样。Rachel使你不再为这种事情烦恼。它提供两种解决方案:采用class://的协议装载URL资源,内嵌一个小型的多线程http server。
10。JavaHelper(JavaHelp System)
Sun提供的制作Java Help制作系统。允许你在GUI应用程序、Applet中提供Online Help功能。
11。Exe4j
Java 安装程序制作工具。
12。JGraph
非常出名的Java 图形编辑框架。
13。GEF(Graphic Edit Framework)
非常好的图形编辑框架,虽然没有JGraph出名,但是我始终觉得它的结构和API都比JGraph好,扩展性非常好。
14。yworks
它的YGuard是一个非常棒的混淆器,免费的,功能很强。除了YGuard它还有几个非常好的组件。
15。Create GUI with JFC/Swing
Sun的JFC/Swing编程初学者指南。
16。Drag and Drop
Sun的关于在GUI中实现拖放操作的教学文章。
17。Joshua Marinacci的Blog
有很多介绍GUI编程的好文章。
18。CloseAndMaxTabbedPane An enhanced JTabbedPane
JavaWorld上一篇关于如何在JTabbedPane的Tab上添加Close按钮、Maximize 按钮和PopupMenu的文章,有源代码下载。还可以。
19。Creating Wizard Dialogs with Java Swing
Sun上的介绍用Swing创建类似Elipse Wizard对话框的文章。
SkinLF(http://www.l2fprod.com/)是一个非常漂亮的Java LookAndFee组件,它的外观可以配置,由一组小图片和一个skinlf-themepack.xml构成。SkinLF的网站上提供了很多Skin下载,这里http://www.l2fprod.com/software/skinlf/jnlp/demo.jnlp可以看到SkinLF和这些外观的演示。可惜的是除了默认的themepack.zip之外,其他外观(好像有很少几个除外)都有中文乱码的问题。其实这是这些外观使用的字体导致的。
打开外观zip文件中的skinlf-themepack.xml,你会发现其他外观的配置文件比themepack.zip中的配置文件多了一些地方:
<font name="Global" value="SansSerif,0,11" />
<font name="InternalFrame.titleFont" value="Trebuchet MS,1,11" />
<font name="TabbedPane.font" value="Tahoma,0,11" />
<font name="MenuBar.font" value="Tahoma,0,11" />
<font name="MenuItem.font" value="Tahoma,0,11" />
<font name="PopupMenu.font" value="Tahoma,0,11" />
<font name="Menu.font" value="Tahoma,0,11" />
把这些注释掉,然后把配置文件放回到zip文件中就可以了。当然你还可以尝试采用其他的字体。
采用JGoodies的LookAndFeel出现乱码,我曾经以为是UTF-8的问题,现在看来可能也是字体导致的。可惜的是,JGoodies的LookAndFeel不能配置。
下午,试用了SkinLF(http://www.l2fprod.com),感觉非常好,程序的外观得到了很大的改善,还可以根据自己的需要随意调整得到自己想要的外观,但是要将SkinLF应用到Web Start中还有点问题。这是因为,web start使用到的资源必须包装成jar文件,以的形式定义到jnlp资源文件中,而SkinLF的外观配置文件是zip形式的。也许有人会说,把zip转化成jar文件就可以了。是的,想象中这应当是可以的,可是实际情况不是如此,你会发现使用ClassLoader.getResourceStream("themepack.jar")的时候返回了Null,SkinLookAndFeel.loadLookAndFeel()会异常Stream closed.
调试之后发现,即使是在客户端,在Eclipse中运行的时候,如果不把themepack.jar定义到ClassPath中,也是无法加载的。
我想这是一个普遍的问题,根据我的理解,如果其他资源,比如图片、xml文件、属性文件等等能够被加载,themepack.jar也应该被加载。事实上应该是这样,但是关键在于SkinLF需要采用ZipInputStream解析zip(jar)文件,这时情况就不一样了。具体的原因目前没有搞清楚。
在网上找了半天,终于发现一个Open Source的组件:Rachel,使用它很轻易就可以解决上面提到的问题。
Rachel(http://rachel.sourceforge.net)是一个为解决Web start装载资源困难而开发的组件。它提供了两种方法解决资源装载问题。
方法一,使用class://URL Handler。
这个方法采用新的URL协议:class://从jar文件中获取资源。
Step 1,注册新的URL Handler,以支持class://协议(protocal)。
例子:java.net.URL.setURLStreamHandlerFactory( new RachelUrlFactory() );
Step 2,采用class://协议构造URL,从jar文件中读取资源。
语法:class:///
例子:
class://test.LookAndFeelTest/themepack.zip
class://com.l2fprod.gui.plaf.skin.SkinLookAndFeel/themepack.zip
注意:这里,是Rachel用来定义资源文件所在的jar的,后面的相对于jar中的根目录而言。上述例子中的jar的结构如下:
test.jar:
test/LookAndFeelTest.class
com/l2fprod/gui/plaf/skin/SkinLookAndFeel.class
themepack.zip
images/example.png
html/index.htm
Step 3,采用java.net.URL获取资源。
例子:
URL url = new URL("class://test.LookAndFeelTest/themepack.zip");
URL url = new URL("class://test.LookAndFeelTest/html/index.html");
URL url = new URL("class://test.LookAndFeelTest/images/example.png");
URL url = new URL("class://com.l2fprod.gui.plaf.skin.SkinLookAndFeel/themepack.zip");
SkinLookAndFeel.setSkin( SkinLookAndFeel.loadThemePack(url) );
方法二,在程序中嵌入多线程的,小型的http server。
Step 1,把你的资源放到jar中。
Step 2,在每一个jar中增加一个anchor class,帮组server定位资源所在的jar文件,这点类似于方法一class:///的的。
例子:
public class CrossRefAnchor
{
public CrossRefAnchor() {}
}
CrossRefAnchor没有任何的实际意义,只是为了帮组定义资源所在的jar。
Step 3,为每一个包含资源的jar用ClassResourceLoader注册到WebResourceManager。
例子:
WebResourceManager roots = WebResourceManager.getInstance();
roots.addResourceLoader( new ClassResourceLoader( CrossRefAnchor.class ) );
roots.addResourceLoader( new ClassResourceLoader( JavaDocAnchor.class ) );
Step 4,启动Server。
例子:
try
{
WebServer http = new WebServer( 7272, roots );
http.start();
}
catch( IOException e )
{
e.printStackTrace();
}
Step 5,采用URL从server获取资源。
例子:
URL crossRefUrl = new URL( "http://localhost:7272/crossref/index.html" );
URL url = new URL( "http://localhost:7272/test.LookAndFeelTest/themepack.zip" );
URL url = new URL( "http://localhost:7272/test.LookAndFeelTest/html/index.html" );
URL url = new URL( "http://localhost:7272/test.LookAndFeelTest/images/example.png" );