﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-风行天下-文章分类-struts</title><link>http://www.blogjava.net/fengtaishao/category/7212.html</link><description>JAVA太极</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 02:51:37 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 02:51:37 GMT</pubDate><ttl>60</ttl><item><title>Validator 四步曲</title><link>http://www.blogjava.net/fengtaishao/articles/10138.html</link><dc:creator>风太少</dc:creator><author>风太少</author><pubDate>Mon, 15 Aug 2005 05:23:00 GMT</pubDate><guid>http://www.blogjava.net/fengtaishao/articles/10138.html</guid><wfw:comment>http://www.blogjava.net/fengtaishao/comments/10138.html</wfw:comment><comments>http://www.blogjava.net/fengtaishao/articles/10138.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/fengtaishao/comments/commentRss/10138.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/fengtaishao/services/trackbacks/10138.html</trackback:ping><description><![CDATA[<DIV id=divarticlecontent>
<H3 class=title>Validator 四步曲</H3><BR>
<P>from:http://www.matrix.org.cn/blog/magicgod/</P><BR>
<P>1.<FONT color=red>NewTaskGroupForm</FONT> extends <FONT color=red>ValidatorForm</FONT><BR>并且去掉<FONT color=red>validate</FONT>函数</P><BR>
<P>2.validation.xml:<BR>&lt;form name="<FONT color=red>newTaskGroupForm</FONT>"&gt;<BR>&lt;field property="<FONT color=red>tg_name</FONT>" depends="<FONT color=red>required</FONT>"&gt;<BR>&lt;arg key="<FONT color=red>label.taskgroup.tg_name</FONT>" position="0"/&gt;<BR>&lt;/field&gt;<BR>&lt;field property="starttime" depends="long"&gt;<BR>&lt;arg key="label.taskgroup.starttime" position="0"/&gt;<BR>&lt;/field&gt;<BR>&lt;field property="interval" depends="long"&gt;<BR>&lt;arg key="label.taskgroup.interval" position="0"/&gt;<BR>&lt;/field&gt;<BR>&lt;/form&gt;<BR>其中：newTaskGroupForm是抄<FONT color=red>struts-config.xml</FONT><BR>tg_name是字段名，抄<FONT color=red>NewTaskGroupForm.java</FONT><BR>depends="required"里required是抄<FONT color=red>validation-rules.xml</FONT><BR>label.taskgroup.tg_name，抄<FONT color=red>ApplicationResources_zh_CN.properties</FONT><BR>position="0"是指参数位置，用于 errors.long=<FONT color=red>{0}</FONT> 必须输入长整数</P><BR>
<P>3.<FONT color=red>ApplicationResources_zh_CN.properties</FONT><BR>这些是字段名：跟validation.xml对应<BR>label.taskgroup.tg_name=任务组名称<BR>label.taskgroup.starttime=开始时间<BR>label.taskgroup.interval=每行运行间隔时间</P><BR>
<P>以下这些是公共信息，跟validation-rules.xml对应<BR>errors.required=<FONT color=red>{0}</FONT> 不能为空，必须输入<BR>errors.long={0} 必须输入长整数</P><BR>
<P>4.以上是提交校验，如果需要加入js<BR>&lt;html:javascript formName="<FONT color=red>newTaskGroupForm</FONT>"/&gt;<BR>注意formName="newTaskGroupForm"要写正确</P><BR>
<P>在form上加入onsubmit="return validate<FONT color=red>NewTaskGroupForm</FONT>(this)"<BR>函数名后半部分是formName，很有规律的</P></DIV><BR><IFRAME name=articleforum marginWidth=0 marginHeight=0 src="http://www.matrix.org.cn/articleforum.shtml" frameBorder=0 width=700 scrolling=no height=270></IFRAME><img src ="http://www.blogjava.net/fengtaishao/aggbug/10138.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/fengtaishao/" target="_blank">风太少</a> 2005-08-15 13:23 <a href="http://www.blogjava.net/fengtaishao/articles/10138.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>struts源代码阅读（struts 初始化）</title><link>http://www.blogjava.net/fengtaishao/articles/10127.html</link><dc:creator>风太少</dc:creator><author>风太少</author><pubDate>Mon, 15 Aug 2005 04:31:00 GMT</pubDate><guid>http://www.blogjava.net/fengtaishao/articles/10127.html</guid><wfw:comment>http://www.blogjava.net/fengtaishao/comments/10127.html</wfw:comment><comments>http://www.blogjava.net/fengtaishao/articles/10127.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/fengtaishao/comments/commentRss/10127.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/fengtaishao/services/trackbacks/10127.html</trackback:ping><description><![CDATA[本文Matrix永久镜像：<A href="http://www.matrix.org.cn/resource/article/1/1071.html">http://www.matrix.org.cn/resource/article/1/1071.html</A> <BR>说明：本文可能由Matrix原创，也可能由Matrix的会员整理，或者由<BR>Matrix的Crawler在全球知名Java或者其他技术相关站点抓取并永久<BR>保留镜像，Matrix会保留所有原来的出处URL，并在显著地方作出说明，<BR>如果你发觉出处URL有误，请联系Matrix改正.<BR>
<DIV id=divarticlecontent>我在几个月前曾经发表过一个帖子，就是和大家一起学习struts源代码。成为一名合格的程序员，阅读大量的优秀程序是必不可少的。只看书是不会让你水平有很大提高的，要多看多写。<BR>本来是打算等下面几篇文章写好后一起发布的，这样大家可能才能看得明白些，但是根据我现在的状况，估计还要一、两个月。所以，为了防止在struts源代码发生过大变化后我的文章就没有太大价值了，所以就提前发表了，霍霍~~~<BR>我的email为：mariah_fan@hotmail.com，有什么不对的地方请大家指正：）<BR>struts作为J2EE的MVC框架已经取得了很大的成功，下面将分几篇文章说明struts源程序的结构。<BR>第一篇 struts的初始化<BR><BR>struts 的核心类是org.apache.struts.action.ActionServlet，这个类将会在struts第一次使用时，<BR>作为servlet初始化并存入tomcat容器。很显然的，初始化将会调用init方法初始化相应的数据。<BR><BR>一、initInternal()方法：<BR>通过调用MessageResources.getMessageResources(internalName)方法生成一个<BR>MessageResources类，getMessageResources是通过调用MessageResourcesFactory.<BR>createResources(config)来实现的。至于MessageResourcesFactory是一个abstract类，任何<BR>继承自它的类都要实现createResources方法，生成MessageResources对象。整个程序生成<BR>MessageResourcesFactory使用了如下技巧：<BR>MessageResourcesFactory.factoryClass = factoryClass;<BR>MessageResourcesFactory.clazz = null;<BR>首先会通过factoryClass来定义一个类全名，然后通过ClassLoader.loadClass<BR>(factoryClass)方法来生成这个类，并赋给clazz，然后通过newInstance来生成一个对象。<BR>在本程序中，生成MessageResources对象实际就是对如下属性进行了初始化：<BR>this.factory = factory;("org.apache.struts.util.PropertyMessageResourcesFactory")<BR>this.config = config;("org.apache.struts.action.ActionResources")<BR>this.returnNull = returnNull;(true/false)<BR><BR>对于MessageResources类的作用是根据不同的Locate来格式化相应的string。或者把你需要改变<BR>的string存放到数组中，然后通过getMessage(Locale locale, String key, Object args[])<BR>方法来格式化。然后把格式好的string存放到HashMap里，这样就可以为以后重用。这里的key是<BR>使用的locale.toString() + "." + key<BR><BR>在PropertyMessageResources中的loadLocale方法用来读取resource的初始化信息。首先它会<BR>通过一个HashMap检测这个localKey相关的message是否已经被初始化了，如果被初始化过就跳<BR>出，检测的方法是locales.get(localeKey) != null。<BR>然后会读取如下一个文件：<BR>org/apache/struts/action/ActionResources_(localKey).properties，然后进行如下操作：<BR>Properties props = new Properties();<BR>ClassLoader classLoader = Thread.currentThread().getContextClassLoader();<BR>is = classLoader.getResourceAsStream(name);<BR>props.load(is);<BR>Iterator names = props.keySet().iterator();<BR>while (names.hasNext()) {<BR>String key = (String) names.next();<BR>if (log.isTraceEnabled()) {<BR>log.trace(" Saving message key '" + messageKey(localeKey, key));<BR>}<BR>messages.put(messageKey(localeKey, key), props.getProperty(key));<BR>}<BR><BR>PropertyMessageResources 就是通过上面的loadLocale方法查找与Locale locale, String key<BR>相对对应的Message.查找的次序如下locale.toString()，然后是<BR>localeKey = localeKey.substring(0, underscore)，然后是defaultLocale，然后是key。<BR><BR>最后，resource类的结构如下：<BR>PropertyMessageResources extends MessageResources<BR>PropertyMessageResourcesFactory extends MessageResourcesFactory<BR><BR>二、initOther()方法：<BR>从servlet中获取config和debug两个参数，然后初始化ConvertUtils对象。由于<BR>ConvertUtils.deregister()的初始化，所有的Converter都是有初始值的，所以这里Struts自己<BR>把这些初始值设置为null，即转换出错的时候返回null，而不是初始值。使用ConvertUtils类的<BR>原因是由于从form传输过来的都是String类型的值，所以我们要把它们转换成相应的类型。<BR><BR>提到几个技巧：<BR>*public boolean isIndexed() {<BR>if (type == null) {<BR>return (false);<BR>//技巧一：判断是否是一个Array类的方法<BR>} else if (type.isArray()) {<BR>return (true);<BR>//技巧二：判断type是否是List的一个父类或者父接口，或者与List为同一个类<BR>//要注意如果List是另一个primitive的TYPE类，那么type必须也是这个类才会<BR>//返回true，否则都是false。注意long.TYPE与Long.class是不同的<BR>} else if (List.class.isAssignableFrom(type)) {<BR>return (true);<BR>} else {<BR>return (false);<BR>}<BR>}<BR><BR>*//componentType为Array类所存储的元素的类别 <BR>Class componentType = indexedProperty.getClass().getComponentType();<BR>//生成一个新的Array<BR>Object newArray = Array.newInstance(componentType, (index + 1));<BR>System.arraycopy(indexedProperty, 0, newArray, 0, length);<BR>indexedProperty = newArray;<BR>set(name, indexedProperty);<BR>int newLength = Array.getLength(indexedProperty);<BR>for (int i = length; i &lt; newLength; i++) {<BR>Array.set(indexedProperty, i, createProperty(name+"["+i+"]", componentType));<BR>}<BR><BR>三、initServlet()方法：<BR>这个方法主要是通过digester类解析web.xml，对String servletMapping属性进行初始化。对于<BR>digester说明如下：这是一个基于DOM的SAX实现的类，它是事件触发的，根据xml文件的结构，<BR>每次读到一个节点元素就会触发一个事件。<BR><BR>InputStream input = getServletContext().getResourceAsStream("/WEB-INF/web.xml");<BR>这是一个比较少见的方法。首先通过this.servletName = getServletConfig().<BR>getServletName()获取servlet的名称，然后根据<BR>if (servletName.equals(this.servletName)) {<BR>this.servletMapping = urlPattern;<BR>}<BR>来判断当前读到的servlet名称是否是我们运行的servlet的名称，如果是，就把url-pattern作为<BR>我们的servletMapping。<BR><BR>四、getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this)<BR>把自己存储到servletContext中，属性名为Globals.ACTION_SERVLET_KEY。<BR><BR>五、ModuleConfig moduleConfig = initModuleConfig("", config)<BR>这个方法使用由initOther()方法获取的config值为要解析的xml路径，用来初始化ModuleConfig。<BR>它首先采用与生成MessageResourcesFactory同样的方法产生一个MessageResourcesFactory对象：<BR>MessageResourcesFactory为一个抽象类，每一个继承它的类都要实现<BR>createModuleConfig(String prefix)方法。本程序使用的缺省的MessageResourcesFactory类为<BR>org.apache.struts.config.impl.DefaultModuleConfigFactory，它<BR>的createModuleConfig(String prefix)方法会生成一个ModuleConfigImpl类。<BR><BR>ModuleConfigImpl类相当于一个JavaBean，用来存放一个web模块运行时所需要的配置信息。当<BR>然，一个web模块可以拥有多个ModuleConfig，但是缺省的是prefix长度为0的ModuleConifg。它<BR>的每个属性几乎都是由HashMap组成的，它通过一个configured布尔值来描述当前的ModuleConfig<BR>是否已经被初始化完毕，在每存放一个属性的时候都会监测这个值。如果初始化完毕而还要改变<BR>里面的属性值，则会报出IllegalStateException("Configuration is frozen")异常，现在对它<BR>的属性简单说明如下：<BR>* protected HashMap actionConfigs：<BR>这个HashMap用来存储ActionConfig对象。<BR>* protected HashMap dataSources<BR>这个HashMap用来存储DataSourceConfig对象。<BR>* protected HashMap exceptions<BR>这个HashMap用来存储ExceptionConfig对象。<BR>* protected HashMap formBeans<BR>这个HashMap用来存储FormBeanConfig对象。<BR>* protected HashMap forwards<BR>这个HashMap用来存储ForwardConfig对象。<BR>* protected HashMap messageResources<BR>这个HashMap用来存储MessageResourcesConfig对象。<BR>* protected ArrayList plugIns<BR>这个HashMap用来存储PlugInConfig对象。<BR>* protected ControllerConfig controllerConfig<BR>ControllerConfig类<BR>* protected boolean configured<BR>标志这个ModuleConfig是(true)否(false)配置完成。<BR>* protected String prefix<BR>用来标志和区分ModuleConfig类，同时在使用上面的config类初始化相应的资源以后，也是通<BR>过这个prefix来区分所属的不同的web模块。<BR>* protected String actionMappingClass = "org.apache.struts.action.ActionMapping"<BR>ActionMapping类名，缺省为org.apache.struts.action.ActionMapping。<BR><BR>初始化ModuleConfig的方法如下：<BR>首先是使用getServletConfig().getInitParameter("mapping")来获取设定的ActionMapping类<BR>名，然后通过initConfigDigester()方法来生成一个digester。最后用","分隔config，对每一<BR>块调用parseModuleConfigFile(prefix, paths, config, digester, path)方法解析。注意，这<BR>个方法实际上只有两个参数是有意义的：path为我们要解析的xml文件，config用来初始化完成<BR>后保存到servletContext中。<BR><BR>如果ModuleConfig中存放的FormBeanConfig为Dydamic类型，那么就调用<BR>DynaActionFormClass.createDynaActionFormClass(FormBeanConfig)初始化<BR>DynaActionFormClass，并存放到DynaActionFormClass.dynaClasses 的 static HashMap中。这<BR>里的key为FormBeanConfig.getName() + moduleConfig.getPrefix()。<BR><BR>如果当前的ModuleConfig为缺省的ModuleConfig，那么将会调用如下几个方法：<BR>defaultControllerConfig(config)<BR>defaultMessageResourcesConfig(config)<BR>defaultFormBeansConfig(config)<BR>defaultForwardsConfig(config)<BR>defaultMappingsConfig(config)<BR>在struts1.1以后，这个特例将会被废弃：<BR><BR>defaultControllerConfig(config)为ControllerConfig通过getInitParameter(s)方法初始化如<BR>下几个属性：bufferSize，content，locale(true/false)，maxFileSize，nocache(true/false)<BR>，multipartClass，tempDir。<BR><BR>defaultMessageResourcesConfig(config)为MessageResourcesConfig通过getInitParameter(s)<BR>方法初始化如下几个属性：application，factory，null(true/false)。<BR><BR>其它的几个方法就是获取不同的对象，然后把它们相应的存储到servlet中。关心如下：<BR>ActionFormBeans=&gt;FormBeanConfig，ActionForwards=&gt;ForwardConfig，<BR>ActionMappings=&gt;ActionConfig。<BR><BR>六、initModuleMessageResources(ModuleConfig config)<BR>通过存储在ModuleConfig中的MessageResourcesConfig对象，逐个初始化MessageResource，<BR>然后再把初始化好的MessageResources存放到ServletContext中，attributeName为<BR>MessageResourcesConfig.getKey() + ModuleConfig.getPrefix()。<BR><BR>七、initModuleDataSources(ModuleConfig config)<BR>通过存储在ModuleConfig中的DataSourceConfig对象，逐个初始化DataSource。然后对于每一个<BR>DateSource通过BeanUtils.populate(ds, dscs[i].getProperties())方法初始化其属性。再把初<BR>始化好的DateSource存放到ServletContext中，attributeName为<BR>DataSourceConfig.getKey() + ModuleConfig.getPrefix()。同时也存放到名位dataSources的<BR>FastHashMap中，key为DataSourceConfig.getKey()。<BR><BR>这里还会根据生成的DateSource对象是否是GenericDataSource类型，如果是则调用<BR>GenericDataSource.open()方法。GenericDataSource是一个非常简单的数据库连接池，它的<BR>open()方法用来初始化连接池，生成最小数目的GenericConnection，这里的open()方法根据<BR>String driver变量是否为null来判断是否已经被初始化过。需要仔细说明的是getConnection()<BR>方法，它首先从连接池中取出GenericConnection对象，然后检查其是否是可链接的，如果是就<BR>返回，否则继续取出，同时activeCount-1。如果没有取到，则会检查当前可使用的<BR>GenericConnection是否达到最大值(activeCount &lt; maxCount)，如果没有，调用<BR>createConnection()方法声成一个新的GenericConnection，然后检查其是否是可链接，如果可以<BR>则返回。returnConnection(GenericConnection conn)方法则是通过把GenericConnection放回到<BR>连接池，然后activeCount-1。<BR><BR>这个方法中使用到了ServletContextWriter类，DateSource的log信息就通过这个类写入。对这个<BR>类说明如下：<BR>它继承自PrintWriter，而PrintWriter又继承自Writer。Writer类所作的事情就是在同步的情况下<BR>调用abstract方法：abstract public void write(char cbuf[], int off, int len)，这个方法<BR>将会根据调用者的需要由调用者实现。<BR>PrintWriter则首先通过ensureOpen()方法检验这个类中是否有写入的对象(Writer类或其子类)，<BR>如果有则根据不同的情况调用这个写入对象的write方法(out.write(....))。这个类的print(...)<BR>方法就是据不同的情况调用相应的write(...)方法。而println(...)与之的区别就是每次多写入一<BR>个换行字符串。还有一个区别是println(...)会根据是否需要autoflush进行flush，而write(...)<BR>方法不会。<BR>ServletContextWriter类的作用是把字符写入ServletContext中。ServletContextWriter类方法中<BR>真正实现了write方法：<BR>public void write(char c) {<BR>if (c == '\n')<BR>flush();<BR>else if (c != '\r')<BR>buffer.append(c);<BR>}<BR>public void flush() {<BR>if (buffer.length() &gt; 0) {<BR>context.log(buffer.toString());<BR>buffer.setLength(0);<BR>}<BR>}<BR><BR>八、initModulePlugIns(moduleConfig)<BR>通过存储在ModuleConfig中的PlugInConfig对象，逐个初始化PlugIn对象，存放到一个数组中，<BR>然后再把这个数组存放到ServletContext中，attributeName为<BR>Globals.PLUG_INS_KEY + ModuleConfig.getPrefix()。<BR><BR>对每一个生成的PlugIn对象通过<BR>BeanUtils.populate(plugIns[i], plugInConfigs[i].getProperties())方法初始化其属性。然后<BR>再把PlugInConfig对象存放到由其生成的PlugIn对象中。<BR><BR>最后，通过plugIns[i].init(this, (ModuleConfig) config)初始化这个plugIn对象。<BR><BR>九、初始化结束<BR>完成了这个初始化以后，会调用ModuleConfig.freeze()令这个ModuleConfig变得不可改变。然后<BR>会遍历ServletConfig中的initParameterNames，如果有以"config/"开头的，则通过这个parameter<BR>的值继续初始化其它的ModuleConfig，且这个ModuleConfig的prefix为"config/"后的字符串。<BR><BR>同样调用如下方法：<BR>initModuleMessageResources(moduleConfig);<BR>initModuleDataSources(moduleConfig);<BR>initModulePlugIns(moduleConfig);<BR>moduleConfig.freeze();<BR><BR>最后调用destroyConfigDigester()释放内存。 </DIV><img src ="http://www.blogjava.net/fengtaishao/aggbug/10127.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/fengtaishao/" target="_blank">风太少</a> 2005-08-15 12:31 <a href="http://www.blogjava.net/fengtaishao/articles/10127.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>struts源代码阅读（Commons-Beanutils包）</title><link>http://www.blogjava.net/fengtaishao/articles/10126.html</link><dc:creator>风太少</dc:creator><author>风太少</author><pubDate>Mon, 15 Aug 2005 04:28:00 GMT</pubDate><guid>http://www.blogjava.net/fengtaishao/articles/10126.html</guid><wfw:comment>http://www.blogjava.net/fengtaishao/comments/10126.html</wfw:comment><comments>http://www.blogjava.net/fengtaishao/articles/10126.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/fengtaishao/comments/commentRss/10126.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/fengtaishao/services/trackbacks/10126.html</trackback:ping><description><![CDATA[<DIV id=articleview_summary>摘要：<BR>既然是说Struts源代码，为什么要讲Commons-Beanutils包呢？原因很简单，Struts的DynaFormBean就是通过这个包里的相关类实现的。本文对Commons-Beanutils 源代码进行了分析..<BR><BR><BR>本文Matrix永久镜像：<A href="http://www.matrix.org.cn/resource/article/1/1708_struts.html">http://www.matrix.org.cn/resource/article/1/1708_struts.html</A> <BR>说明：本文可能由Matrix原创，也可能由Matrix的会员整理，或者由<BR>Matrix的Crawler在全球知名Java或者其他技术相关站点抓取并永久<BR>保留镜像，Matrix会保留所有原来的出处URL，并在显著地方作出说明，<BR>如果你发觉出处URL有误，请联系Matrix改正.<BR></DIV>
<DIV id=divarticlecontent>既然是说Struts源代码，为什么要讲Commons-Beanutils包呢？原因很简单，Struts的DynaFormBean就是通过这个包里的相关类实现的。同样，留下我的邮箱，方便和大家共同交流。我的邮箱是：mariah_fan@hotmail.com。<BR><BR><B>Commons-Beanutils（一） </B><BR><BR>Commons-Beanutils 这个是jakarta commons项目中的一个子项目。这个项目开发的目的是帮助开发者动态的获取/设值Java Bean的属性，同时解决每次都要写getXXX和setXXX的麻烦。<BR><BR><B>一、XXXConvert</B><BR>这些类都实现Converter接口，提供把value值转化成为相应XXX类的实现。现在只针对四种类型：数字，时间，Boolean和String。在Converter 接口中只有一个方法convert(Class type, Object value)，把value对象转换为type所要求的类。XXXConvert类中这个方法的思路是：<BR>1、如果value==null，并且自己内部有缺省的值那么就返回这个缺省的值。如果没有缺省值，就抛出ConversionException异常。<BR>2、如果value instanceOf XXX类，那么就直接返回value。<BR>3、如果上面的都不行，那么调用new XXX(value.toString())或者XXX.valueOf(value.toString())方法来返回。转化失败时，抛出ConversionException异常。<BR><BR><B>二、特殊的实现</B><BR>1、对于ClassConverter类，当进入第三种情形的时候，实际执行的是<BR><PRE class=overflow title="pre code">ClassLoader classLoader =Thread.currentThread().getContextClassLoader();<BR>&nbsp; &nbsp;if (classLoader == null) {<BR>&nbsp; &nbsp; &nbsp; &nbsp;classLoader = ClassConverter.class.getClassLoader();<BR>&nbsp; &nbsp;}<BR>&nbsp; &nbsp;return (classLoader.loadClass(value.toString()));</PRE><BR><BR>2、对于BooleanConverter类，当进入第三种情形的时候，实际执行的是，根据value.toString()的值：yes，y，true, on, 1 返回true；no，n，false，off，0 返回false。如果这些情形都不符合，并且有缺省值的时候则返回缺省值。否则抛出ConversionException；<BR><BR><B>三、XXXArrayConverter</B><BR>这些类继承自AbstractArrayConverter类。 AbstractArrayConverter 实际只实现了一个List parseElements(String svalue)方法。这个方法接受的是{value1, value2,...}格式的字符串，逐个解析出来后，放入一个ArrayList中。它通过StreamTokenizer解析字符串：StreamTokenizer是用来分离input stream中读取的字符串，并且可以根据标记区分不同的内容，比如数字，字符或者注释。XXXArrayConverter由于要转换的是一个数组，所以convert(....)方法的实现过程有所不同。<BR>1、如果value==null，并且自己内部有缺省的值那么就返回这个缺省的值。如果没有缺省值，就抛出ConversionException异常。<BR>2、如果model.getClass() == value.getClass()，那么就直接返回value。<BR>3、如果上面的都不行，那么就通过parseElements(value.toString())生成一个数组，再对数组的元素逐个调用new XXX(list.get(i))或者XXX.valueOf(list.get(i))方法，转换成为数组对元素要求的类型。转化失败时，抛出ConversionException异常。<BR><BR><B>Commons-Beanutils（二） </B><BR><BR><B>一、LocaleConverter 与 BaseLocaleConverter</B><BR>LocaleConverter继承自 Converter接口，定义了一个新方法convert(Class type, Object value, String pattern)。<BR>抽象类BaseLocaleConverter实现了LocaleConverter接口。它的locPattern属性用来表示这个对象的pattern是否是本地化的格式。patttern 是指把何种格式的时间或者数字值转换成标准值。convert(...)的执行过程是：<BR>1、如果value==null，并且自己内部有缺省的值那么就返回这个缺省的值。如果没有缺省值，就抛出ConversionException异常。<BR>2、根据参数pattern值是否为null，调用parse(Object value, String pattern)方法：如果这个参数不为null那么就使用这个参数的值，否则使用对象预存的pattern值。如果这<BR>样做引起了异常，会首先判断是否能够返回缺省的值，不能则抛出ConversionException异常。<BR>3、parse(Object value, String <BR>pattern)方法的实现被抛至继承了它的类具体实现。这个方法虽然把value值表述为Object类型，但是最后都是通过强制转换，转换成为String类型。也就是说它实际上需要的<BR>是String类型的value。<BR><BR><B>二、 XXXLocaleConverter</B><BR>把pattern格式的value转换成标准格式的相应的XXX类。这些类可以分为两大类：一类为时间，一类为数值。<BR>1、时间类最后都会通过SimpleDateFormat类对值进行转换，程序如下：<BR><PRE class=overflow title="pre code"> if(pattern == null) {&nbsp; &nbsp; &nbsp; <BR>&nbsp; &nbsp; &nbsp; &nbsp;pattern = locPattern ? new SimpleDateFormat().toLocalizedPattern() : <BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;new SimpleDateFormat().toPattern();<BR>&nbsp; &nbsp;}<BR>&nbsp; &nbsp;SimpleDateFormat format = new SimpleDateFormat(pattern, locale);<BR>&nbsp; &nbsp;if (locPattern) {<BR>&nbsp; &nbsp; &nbsp; &nbsp;formatter.applyLocalizedPattern(pattern);<BR>&nbsp; &nbsp;}else {<BR>&nbsp; &nbsp; &nbsp; &nbsp;formatter.applyPattern(pattern);<BR>&nbsp; &nbsp;}<BR>&nbsp; &nbsp;return formatter.parse((String) value);</PRE><BR><BR>2、数值类最后都会通过DecimalFormat类对值进行转换，程序如下：<BR><PRE class=overflow title="pre code">DecimalFormat formatter = (DecimalFormat) DecimalFormat.getInstance(locale);<BR>&nbsp; &nbsp;if (pattern != null) {<BR>&nbsp; &nbsp; &nbsp; &nbsp;if (locPattern) {<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;formatter.applyLocalizedPattern(pattern);<BR>&nbsp; &nbsp; &nbsp; &nbsp;} else {<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;formatter.applyPattern(pattern);<BR>&nbsp; &nbsp; &nbsp; &nbsp;}<BR>&nbsp; &nbsp;} <BR>&nbsp; &nbsp;return formatter.parse((String) value);</PRE><BR>这个转化过程要注意精度的问题。由于Number类是所有的数值类的父类，所以转换完成后要检查最后的结果是否是当前要求的精度：如果大于所要求的精度，则抛出ConversionException异常。<BR><BR><B>Commons-Beanutils（三）</B><BR><BR>Dyna开头的类，是专门为DynaFormBean而设计的。<BR><BR><B>一、DynaBean，DynaClass 与 DynaProperty</B><BR>DynaBean并不是Java中所定义的Bean，而是一种“假”的Bean。因为它并不是通过getXXX和setXXX方法，对XXX属性进行取值和设值的。它通过一个实现了DynaClass接口的类，帮助管理其所有的属性的类别，而自己则管理对XXX属性值的设定和获取。在设值的时候会通过与name对应的DynaProperty对象，检查赋值的类别是否正确。<BR>DynaProperty类描述的是DynaBean中所包含的属性的类型。DynaProperty类有三个属性：属性的名称：name，属性的名称；type，属性的类别；contentType，如果DynaProperty描述的是个容器对象(List或者Map)，那么这个contentType就代表这个容器内元素的类别。这个类值得关注的地方是writeObject和readObject方法的实现。它会首先判断自己的type是否是一个primitive的类，如果是，则先写入true标志，再写入对应的primitive类的编号；否则写入false标志，再写入type。因为在调用readObject方法时，如果得出的是primitive类型，则type的值为XXX.TYPE而不是XXX.class。<BR>DynaClass 是一个接口，用来管理DynaBean中所有的DynaProperty属性。<BR><BR><B>二、BasiceDyanBean 与 BasicDynaClass</B><BR>BasiceDyanBean 实现自DynaBean接口。它包含一个实现了DynaClass接口的类的对象，和一个用来存放值的HashMap。这个HashMap的key与DynaClass中HashMap的key是一一对应的。<BR>BasicDynaClass 实现了DynaClass接口，以DynaProperty的name为key保存所有这些DynaProperty对象。它通过newInstance方法动态生成实现了DynaBean接口的类的对象；注意这个类是可以动态指定的，如果没有，那么就是默认的BasicDynaBean类。动态指定类是通过反射实现的，程序如下：<BR>//dynaBeanClass为任意的实现了DynaBean接口的类，constructorTypes为这个<BR>//类的构造方法所需要的参数的类型<BR>constructor = dynaBeanClass.getConstructor(constructorTypes);<BR>//constructorValues为构造方法的参数值，实际上它的值为当前的BasicDynaClass<BR>return ((DynaBean) constructor.newInstance(constructorValues)); <BR><BR><B>Commons-Beanutils（四）</B><BR><BR><B>一、ConvertUtils 和 ConvertUtilsBean</B><BR>ConvertUtils 是ConvertUtilsBean类的一个简单封装，即ConvertUtils中的所有方法都是通过直接调用ConvertUtilsBean中的同名方法实现的。如果你需要更复杂的功能，就使用ConvertUtilsBean，否则使用ConvertUtils。<BR>ConvertUtilsBean 通过一个HashMap管理所有的XXXConverter。这个HashMap的key为XXX的类全名，值为相应的XXXConverter对象。通过deregister()方法，初始化这个HashMap。这个初始化方法会为每一个XXXConverter类提供一个缺省的值。用户可以动过setDefaultXXX(...)方法来自行设置XXXConverter对象的缺省值。这个类还提供了convert(...)方法，对String value进行相应的转化。<BR><BR><B>二、PropertyUtils 和 PropertyUtilsBean</B><BR>PropertyUtils 是PropertyUtilsBean类的一个简单封装，同样它的所有方法都是通过直接调用PropertyUtilsBean 中同名方法实现的。<BR>PropertyUtilsBean 对DynaBean或者一个java标准Bean中的属性动态的赋值和取值(非通过getXXX和setXXX方法)。<BR>1、这个类支持多层嵌套，比如：XXX[i].YYY(key).ZZZ，那么它会为你得到或者设置ZZZ的属性。<BR>2、所有的set/get方法介绍：<BR>//对XXX(key)格式的name设值<BR>setMappedProperty(Object bean, String name,String key, Object value)<BR>//对XXX[i]格式的name设值<BR>setIndexedProperty(Object bean, String name, int index, Object value)<BR>//对XXX格式的name设值<BR>setSimpleProperty(Object bean, String name, Object value)<BR>//对XXX(key).YYY[i].ZZZ格式的名称设值。注意，name必须要遵照这种格式。<BR>//这个方法实际做的就是以“.”为分隔符，逐层的根据情况分别调用上面的几个方法，<BR>//获取相应的bean。<BR>setNestedProperty(Object bean, String name, Object value)<BR>//它直接调用setNestedProperty方法<BR>setProperty(Object bean, String name, Object value)<BR>3、getPropertyType(Object bean, String name)方法中用来获取Bean的某一个property的类型的代码：<BR>PropertyDescriptor descriptor = getPropertyDescriptor(bean, name);<BR>if (descriptor == null) {<BR>return (null);<BR>}else if (descriptor instanceof IndexedPropertyDescriptor) {<BR>return (((IndexedPropertyDescriptor) descriptor).getIndexedPropertyType());<BR>} else if (descriptor instanceof MappedPropertyDescriptor) {<BR>return (((MappedPropertyDescriptor) descriptor).getMappedPropertyType());<BR>} else {<BR>return (descriptor.getPropertyType());<BR>}<BR>4、getIndexedProperty(Object bean, String name, int index)<BR>这个方法用来获取一个数组或者一个List中的属性。它会首先看这个bean是否是DynaBean类型的，如果是，再其检查是否有name这个属性，如果有那么就直接调用get(String name, int index)方法返回值；如果不是DynaBean类型，那么就会执行如下方法：<BR>//有没有为数组的某个特定元素取值的方法<BR>if (descriptor instanceof IndexedPropertyDescriptor) {<BR>Method readMethod = ((IndexedPropertyDescriptor) descriptor).<BR>getIndexedReadMethod(); <BR>if (readMethod != null) {<BR>Object subscript[] = new Object[1];<BR>subscript[0] = new Integer(index);<BR>return (invokeMethod(readMethod,bean, subscript));<BR>}<BR>}<BR>// 如果没有，就先取出整个对象<BR>Method readMethod = getReadMethod(descriptor);<BR>if (readMethod == null) { <BR>throw new NoSuchMethodException("Property '" + name +<BR>"' has no getter method");<BR>}<BR>Object value = invokeMethod(readMethod, bean, new Object[0]);<BR>//如果这个对象实际上是一个List，那么调用get()方法<BR>if (!value.getClass().isArray()) {<BR>if (!(value instanceof java.util.List)) {<BR>throw new IllegalArgumentException("Property '" + name<BR>+ "' is not indexed");<BR>} else {<BR>//get the List's value<BR>return ((java.util.List) value).get(index);<BR>}<BR>//否则通过Array类提供的相应方法取值<BR>} else {<BR>//get the array's value<BR>return (Array.get(value, index));<BR>}<BR><BR><B>三、BeanUtil 和 BeanUtilBean</B><BR>BeanUtils 是BeanUtilsBean类的一个简单封装，同样它的所有方法都是通过直接调用BeanUtilsBean 中同名方法实现的。<BR>BeanUtilBean中大多数核心方法都是通过调用PropertyUtilsBean中的方法实现的。而populate(Object bean, Map properties)是自己实现的，因为这个赋值过程要首先对value进行格式的转化；这个方法把properties中的key为属性名，value为属性的值，分别对应的设值给bean对象。它通过setProperty(Object bean, String name, Object value)方法实现逐个设值的。由于此时的value不一定符合bean中name属性的类型，所以首先要把value转换成合适的值，然后再设值。具体的类型转换方法如下：<BR><BR><PRE class=overflow title="pre code">//这种类型转换的原则是：如果value是String或者String[]，那么这个值可能为任意的类型， <BR>&nbsp; &nbsp; //需要进行转换。如果为其它的类型，则不进行任何转换。<BR>&nbsp; &nbsp; if (type.isArray() &amp;&amp; (index &lt; 0)) { <BR>&nbsp; &nbsp; &nbsp; &nbsp; // 如果是直接对一个数组赋值，则使用convert(String values[], Class clazz)方法转换<BR>&nbsp; &nbsp; &nbsp; &nbsp; if (value == null) {<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String values[] = new String[1];<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; values[0] = (String) value;<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newValue = getConvertUtils().convert((String[]) values, type);<BR>&nbsp; &nbsp; &nbsp; &nbsp; } else if (value instanceof String) {<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String values[] = new String[1];<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; values[0] = (String) value;<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newValue = getConvertUtils().convert((String[]) values, type);<BR>&nbsp; &nbsp; &nbsp; &nbsp; } else if (value instanceof String[]) {<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newValue = getConvertUtils().convert((String[]) value, type);<BR>&nbsp; &nbsp; &nbsp; &nbsp; } else {<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newValue = value;<BR>&nbsp; &nbsp; &nbsp; &nbsp; }<BR>&nbsp; &nbsp; } else if (type.isArray()) {<BR>&nbsp; &nbsp; &nbsp; &nbsp; // 如果是对数组的某一个元素赋值，则使用convert(String value, Class clazz)方法转换<BR>&nbsp; &nbsp; &nbsp; &nbsp; if (value instanceof String) {<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newValue = getConvertUtils().convert((String) value, type.getComponentType());<BR>&nbsp; &nbsp; &nbsp; &nbsp; } else if (value instanceof String[]) {&nbsp; &nbsp;<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newValue = getConvertUtils().convert(((String[]) value)[0],type.getComponentType());<BR>&nbsp; &nbsp; &nbsp; &nbsp; } else {<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newValue = value;&nbsp; &nbsp; &nbsp;<BR>&nbsp; &nbsp; &nbsp; &nbsp; }<BR>&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<BR>&nbsp; &nbsp; &nbsp; &nbsp; // 否则就是一对一的简单赋值，则使用convert(String value, Class clazz)方法转换<BR>&nbsp; &nbsp; &nbsp; &nbsp; if ((value instanceof String) || (value == null)) {<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newValue = getConvertUtils().convert((String) value, type);<BR>&nbsp; &nbsp; &nbsp; &nbsp; } else if (value instanceof String[]) {<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newValue = getConvertUtils().convert(((String[]) value)[0], type);&nbsp; &nbsp; &nbsp; &nbsp;<BR>&nbsp; &nbsp; &nbsp; &nbsp; } else if (getConvertUtils().lookup(value.getClass()) != null) {<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newValue = getConvertUtils().convert(value.toString(), type);<BR>&nbsp; &nbsp; &nbsp; &nbsp; } else {<BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newValue = value;&nbsp; &nbsp; &nbsp; &nbsp; }<BR>&nbsp; &nbsp; } </PRE></DIV><img src ="http://www.blogjava.net/fengtaishao/aggbug/10126.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/fengtaishao/" target="_blank">风太少</a> 2005-08-15 12:28 <a href="http://www.blogjava.net/fengtaishao/articles/10126.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>