我们使用的JSValidation升级为1.0b4以后就不工作了,我本想放弃。后来下午灵机一动,把新的1.0b4用UTF-8转存一下就OK了,靠!而且同时发现我们使用的已经是1.0b4了,我去年就……靠靠!
发现比较有趣的地方:
1、Webwork封装的sessionMap其实就是Map,使用起来完全相同。使用map.put map.get即可,自己放什么类型就是什么类型。
2、Webwork的OGNL里面自动set回来的parameter是String[]类型,遍历时使用((String[])session.get("somekey"))[0]即可访问到,注意先检测是否contains那个key。原理是由于html的form的name允许重复,所以返回的可能是parameter或者parameters,后者就是一个数组,所以OGNL的setter会自动把你的结果全部以数组方式保存。直接使用就有点麻烦了,不过无所谓了。所以webwrok里面ModelDriven风格才是推荐。
所以我们的需要使用Session的UserAuthenticationManagerjiu只需map.get即可。
而后就是漫长的实现,发现了global-results,这个需要配置在package里面。发现它可以覆盖,即在子package的global-results会覆盖父package的global-results,方便。
不过要注意,在package里面,global-results要在action前面声明。
然后还发现一个非常重大的Bug,或者说问题,是关于Spring的:
在配置的时候使用模版方式定义,即:
<bean id="basicActionWithAuthtication" abstract="true">
此时该bean里面的所有注入属性都可以工作,也就是parent指向basicActionWithAuthtication的bean都会继承它的ref bean。
但是在该bean里面声明的singleton="false"却不会被继承。
这个需要参考以下参考书了,比较重要,不能误解!
在Spring reference的第26-27页(1.2.6)第3.5节Abstract and child bean definitions:
A child bean definition will inherit constructor argument values, property values and method overrides from the
parent, with the option to add new values. If init method, destroy method and/or static factory method are
specified, they will override the corresponding parent settings.
The remaining settings will always be taken from the child definition: depends on, autowire mode, dependency
check, singleton, lazy init.
意思就是一般构造参数和参数值及方法都会从parent继承和覆盖,而如果指定了init方法destroy方法和static factory方法,也会覆盖parent的相应配置。
但是depends on、autowire mode、dependency check、singleton、lazy这些属性则不会被继承,都直接从child中获取。
这也就解释了我们使用的parent里面设置singleton="false"为什么不起作用(Spring默认true,其实就是我们的parent设置不会被继承)。
里面还有个说明有意思:
对于没有制定abstract="true"的action,如果它的class没有指定,则它默认情况下也是一个abstract。但是对于那些指定了class的bean,如果不指定abstract="false",则默认它会初始化。但是对于无abstract声明,但由没有class制定的bean,被引用或者初始化,则会报错!所以要注意,考虑好你的class是否是abstract,声明好。个人人为还是纯抽象并作为模版比较好,表示配置相同的那种方式(都指定class,且有parent关系)则不太合适。
这个的严重性会造成Webwork的action变成singleton,如此的话,两台机器同时调用/administrator/load.action就会调出同一个admin,太可怕了!
java中的String的encoding和下载文件的jsp例子
晚上跟zh等同志一起看了下文件下载的中文问题,问题解决,并且收获不小:
1、java的char类型是16bit,而不是c/c++中的8bit,所以char和byte之间的转换会造成严重的精度损失。而Java的char是Unicode的。
2、java中String是基于char[]的,也就是说这个String天生就可以表示Unicode。所以如果从byte[]创建一个String就会涉及到一个严重的策略问题,是一个byte转一个String字还是两个byte转一个String字。
3、所以我们常用的java转码中的语句somestr = new String(somestr.getBytes(),"ISO-8859-1")与somestr = new String(somestr.getBytes(),"GB2312")之间是有很大区别的,它们关系到从一个byte变两个byte或反过来。
4、所以,对于单精度的"ISO-8859-1"与双精度的GB2312、GBK、utf-8处理的时候一定要分清,而且它也可以解决很多的问题。而如果你好好了解GB2312与GBK的效果其实很类似,他们只有部分的编码覆盖度上的区别,大部分字符是通用的,可是"ISO-8859-1"却与他们完全不同。
5、还有一个有意思的地方:java.io.Writer与java.io.InputStream下面的东西有个明显的区别,前者接受char[],而后者接受byte[]。其实理解一下,他们之间的转换其实正好需要String的单字节编码与双字节编码的区别,我们可以用它们完成有意思的转换。在它们的沟通过程中我们如果使用buffer,则需要String作为中间者进行转换,算个小trick吧。
6、从这里,我们引出今天解决的中文文件下载的问题中的有意思的地方:
<%@ page language="java" import="java.io.PrintWriter"
%><%
String filename = (String)request.getAttribute("downloadFileName");
String filepath = (String)request.getAttribute("downloadFileUrl");
filename = new String(filename.getBytes(),"ISO-8859-1");
if(filename != null && filepath != null) {
response.setContentType("APPLICATION/OCTET-STREAM");
response.setHeader("Content-Disposition",
"attachment; filename=\"" + filename + "\"");
java.io.FileInputStream fileInputStream =
new java.io.FileInputStream(filepath);
java.io.File file = new java.io.File(filepath);
response.setContentLength((new Long(file.length()).intValue()));
PrintWriter pw = response.getWriter();
byte[] charArray = new byte[4096];
int len;
while ((len=fileInputStream.read(charArray)) != -1) {
String s = new String(charArray,"ISO-8859-1");
pw.write(s);
}
pw.flush();
pw.close();
fileInputStream.close();
}
%>
webork2与spring的autowire配合的trick
今天,又看了下上面这个例子里面的starter那个例子,发现:
它使用了Spring的自动装配,以下两段代码效果相同:
java代码:
<beans default-autowire="autodetect">
<bean id="personManager" class="com.acme.PersonManager"/>
</beans>
java代码:
<beans>
<bean id="personManager" class="com.acme.PersonManager"/>
<bean id="listPeople" class="com.acme.ListPeople">
<property name="personManager" >
<ref local="personManager" />
</property>
</bean>
<bean id="createPserson" class="com.acme.CreatePerson">
<property name="personManager">
<ref local="personManager" />
</property>
</bean>
</beans>
如果这样使用的话,如果在xwork里面配制好action的class,然后连这个class的bean都不用在spring里面声明了,其依赖也通过名字匹配自动装配了。
真简单啊,想知道spring的autowire有没有性能损耗,如果每次装配都反射会不会性能很差?
webwork 2.2 中如何给Collection赋值
原本javaeye有这么一篇帖子“在WebWork2 Action中如何自动设置Array、List、Map”,是moxie大哥写的。
http://forum.javaeye.com/viewtopic.php?t=8770
但是已经是2004年11月的文章了,在webwork 2.2 b4中,XWorkList和XWorkMap已经是deprecated状态了,当时我就一头雾水,也没找到什么好的线索。
去java.net下载了XWork的最新代码,看到了其中的注释,说这个工作已经可以自动完成了。
又几经周折,才算搞明白先在如何让List、Map等工作起来:
下面简单介绍一下:
1、如果要将值映射到pojo的collection,则需要使用conversion功能。
如我又一个Action,叫testAction:
public class testAction extends ActionSupport {
private Collection smoeAttrs = null;(使用webwork自动负值,应有对应getter和setter)
private IDeptJgzTjkEcoAttDAO ecoAttDAO = null;(改DAO使用Spring注入,应有相应setter)
public String execute() throws Exception {
if (log.isDebugEnabled()) {
log.debug("performing execute() method!");
}
//持久化collection里面的pojo
for (Iterator iterator = smoeAttrs.iterator(); iterator.hasNext();) {
SomeAttr someAttr = (SomeAttr) iterator.next();
ecoAttDAO.saveOrUpdate(someAttr, someAttr.getId());
}
return Action.SUCCESS;
}
}
对应一个pojo:
package org.tin.test;
public class SomeAttr implements Serializable {
/** The composite primary key value. */
private java.lang.Long id;
private java.lang.Float fild1;
private java.lang.String fild2;
private java.util.Date fild3;
/*
….
对应的getter和setter
*/
}
可以看到,上面的Action声明的时候没有任何涉及到XWorkList的地方(moxie介绍的那种风格),也就是说现在webwork并不知道Collection里面放的pojo的类型。这就是Webwork目前的高明之处,这样的代码非常干净。但是如果要自动设定Collection的值,访问到这些Pojo,则一定要知道Pojo的类型,Webwork如何做呢?
通过-conversion配置。
需要在对应该才那个testAction.java的相同目录写一个testAction-conversion.properties文件(格式就是Action名字+“-conversion.properties”)。
文件里面注明:
Element_someAttrs = org.tin.test.SomeAttr (以前版本曾经用过Collection、Map分开,但是现在不管什么类型,都用Element)
格式就是“Element_”+Action中Collection的名字+“=”+你的pojo的完整类名
如此配置后,自动设置值的时候就可以知道你的pojo的类型了,很干净。
下面一小段由于我接触Webwork不久,所以是个很初级的经验,如果需要则自取:
回忆moxie帖子中的重要的部分,在post到相应action的页面的form中,input要遵循这样的命名:
对应刚才所说的那个pojo:
<form>
<input name="someAttrs[0].fild1" value="45555.6" id="xxx11" />
<input name="someAttrs[0].fild2" value="test" id="xxx12" />
<input name="someAttrs[0].fild3" value="2006-01-05" id="xxx13" />
<input name="someAttrs[1].fild1" value="45555.6" id="xxx21" />
<input name="someAttrs[1].fild2" value="test" id="xxx22" />
<input name="someAttrs[1].fild3" value="2006-01-05" id="xxx23" />
<input name="someAttrs[2].fild1" value="45555.6" id="xxx31" />
<input name="someAttrs[2].fild2" value="test" id="xxx32" />
<input name="someAttrs[2].fild3" value="2006-01-05" id="xxx33" />
</form>
如何输出?很简单,在列表页中:
<ww:iterator value="someAttrs" status="someAttrsIter">
<tr>
<td>
<ww:hidden name="someAttrs[%{#someAttrsIter.index}].id" value="%{id}"/>
<ww:textfield name="someAttrs[%{#someAttrsIter.index}].fild1" value="%{fild1}"/></td>
<td><ww:textfield name="someAttrs[%{#someAttrsIter.index}].fild2 value="%{fild2}"/></td>
<td><ww:textfield name="someAttrs[%{#someAttrsIter.index}].fild3" value="%{fild3}"/></td>
</tr>
</ww:iterator>
即可以,因为iteratror这个tag支持iteratroStatus这个东西,用它可以获取index、isOdd等信息,很方便。
配合
<action name="saveAction" class="testAction">
<result name="success" type="redirect">/loadByInf.action?id=${someAttrOwner.id}</result>
</action>
则很容易的实现对Collection的CRUD。正好用到了ONGL的集中基本访问方式:#、%{}、${}
以上内容,错漏难免。因为今天终于可以偷闲,赶紧结绳记之。欢迎大家讨论更简便的方法。
Webwork 2.2 b5中datapicker的本地化使用方法
1、我使用Weblogic 8.1 SP5+Webwork 2.2 beta 5。2.2b5的Webwork已经完全转向使用jscalendar作为datapicker的js,而不是以前的tigracalendar,因为tigracalendar不支持国际化。Web项目使用FilterDispatcher,本应改可以将/webwork/*的请求拦截下来,但是它工做不正常。所以我把webwork.jar里面的\com\opensymphony\webwork\static目录拷贝到Web根目录,并将static目录重名名为webwork。
此时,你的Web根目录下面应有一个名为webwork的目录,里面有jscalendar、dojo、niftycorners这几个文件加,如果不需要其它的,可以只保留jscalendar一个目录。
2、在需要显示datapicker的地方使用如下标记<ww:datepicker name="ecoInf.turninDate" id="ecoInf.turninDate" template="datepicker.ftl" language="cn_utf8" format="%Y-%m-%d %H:%M:%S" showstime="true" />。
其中template完全可以不写。而name标明你的数据的来源。id是方便javascript访问所保留的,可以和name相同(如果有重复name,如经过iterator,则需要区别其id,保持id在html dom中唯一)。
showstime标明是否可以选择时间,可以是"true","false","24","12"。
language决定jscalendar使用的语言,参照下面说明。
3、language指定的语言其实就对应jscalendar/lang下面的语言文件,格式就是calendar-语言名.js,默认的中文使用的是zh。但是其实j2ee项目经常面对中文乱码问题,最佳解决方案就是统一使用UTF-8。但是calendar-zh.js正好不是UTF-8的,所以如果直接使用zh语言则datapicker没法正常工作。
我的解决方法是将webwork附带的jscalendar 1.0的lang里面的cn_utf8.js改名为calendar-cn_utf8.js,然后将language="cn_utf8"就工作正常了。
4、关于时间的显示格式。其实cn_utf8.js里面已经制定了时间的标准显示格式是%Y-%m-%d,符合我们的习惯。但是有时我们需要显示具体时间,参照他们网站的说明,使用format="%Y-%m-%d %H:%M:%S",这个也符合我们的习惯。
本来奇简单。但是很奇怪/webwork/*居然不能在Weblogic下自动映射,我一会而去试验下Tomcat,还有就是js解析utf-8出错造成整个js没法工作,浪费了半天时间,唉。
2.2 beta 5的datapicker的doc:
http://wiki.opensymphony.com/display/WW/datepicker
jscalendar的官方网站:
http://www.dynarch.com/projects/calendar/
jscalendar的使用方法简单demo:
http://www.dynarch.com/demos/jscalendar/
jscalendar下载:
http://prdownloads.sourceforge.net/jscalendar/jscalendar-1.0.zip?download
datapicker本地化的相关讨论:
http://forums.opensymphony.com/thread.jspa?messageID=21466
http://forums.opensymphony.com/thread.jspa?messageID=21526
eXtremeComponent在中文环境下的使用
不知道大家是否使用过eXtremeComponent,我刚才在java eye没有搜索到。
最早知道eXtremeComponent是从www.open-open.com,去年就在用了,感觉明显比display-tag要好用多了。
它使用jstl,所以与webwork集成也很方便,不象display-tag那样需要把hibernate返回的collection复制一遍再访问。
具体的使用方法参考官方网站好了:
官方网站在这里:
http://www.extremecomponents.org/extremesite/welcome.jsp
最新的版本是1.0.1-M4-A14,可以到这里下载:
http://www.extremecomponents.org/extremesite/public/download/
或者直接下载:
http://www.extremecomponents.org/extremesite/public/download/extremecomponents-1.0.1-M4-A14.zip
但是这个snapshot版本没有依赖lib和资源文件等,推荐去这里下一个完整版本备用,目前最新的Production Release包是eXtremeComponents-1.0.1-M3-with-dependencies.zip:
https://sourceforge.net/project/showfiles.php?group_id=108168
最新版本的说明书在这里,说明书用的doc book格式,写的也很清楚:
http://www.extremecomponents.org/extremesite/public/download/eXtremeComponents.pdf
很多人都对他使用的doc book声称doc感兴趣,spring和hibernate都用doc book,可是一般看不到源文件。作者很慷慨将doc book的源文件也分享了,是学习是学习使用doc book的好东西:
http://www.extremecomponents.org/extremesite/public/download/generate-docs.zip
资源就贴到这里,这里要提及作者Jeff Johnston人非常热情,论坛上四处可见他的身影,给他发信他也是每信必会、有求必应,承蒙他多次帮助。而且论坛中大家多次提及中文问题,他也很重视。
转入正题:
我贴一下一个例子:
<ec:table
items="ecoAttrs"
action="/jgz/tjk/eco/listTjkAttByInfId.action"
imagePath="${pageContext.request.contextPath}/css/table/zh_CN/*.gif"
cellpadding="1"
title="农村经济运行情况列表"
locale="zh_CN"
rowsDisplayed="30">
<ec:export view="xls" fileName="jgz_zyjjzbwcqk.xls" tooltip="输出Excel文件"/>
<ec:exportPdf fileName="jgz_zyjjzbwcqk.pdf" tooltip="输出PDF文件" headerColor="blue" headerBackgroundColor="red" headerTitle="密云县农村经济月份经济主要指标完成情况表"/>
<ec:exportCsv fileName="jgz_zyjjzbwcqk.txt" tooltip="输出CSV文件" delimiter="|"/>
<ec:row>
<ec:column property="ofTown.name" title="乡镇名称"/>
<ec:column property="ncJihua" title="农村计划"/>
<ec:column property="ncWancheng" title="农村完成"/>
<ec:column property="ncQunian" title="农村去年"/>
<ec:column property="zongShouRuWCJH" title="完成计划%"/>
<ec:column property="zongShouRuTB" title="同比+/-%"/>
</ec:row>
</ec:table>
其中ecoAttrs是一个collection,放入pojo。action里面写你这个页面的访问方法(如我的页面是一个action,其他的如.do或者.jsp什么的都可以)。rowsDisplayed是默认显示条数,它可以自动实现分页。
下面的三个<ec:export>是导出三种格式用的,不用的话可以不写(写了需要在web.xml配置相应的filter)。
<ec:column>里面放属性,property指向pojo的相应属性,而title是表头显示的信息,这个标签需要用<ec:row>包起来(1.0.1 m4以后)(抱歉pojo比较丑,出自同事之手)。
这里放一套我做的中文图标:
http://tiny.51.net/extremecomponent/zh_CN.rar
还有我该写了一下css,更适合使用中文,将字体该为%大小,可以定义.eXtremeTable里面的font-size,即影响所有eXtremeTable里面的字体大小,也方便写js来动态修改大小:
http://tiny.51.net/extremecomponent/extremecomponents.css
贴一下我在web.xml里面的配置:
<filter>
<filter-name>eXtremeExport</filter-name>
<filter-class>
org.extremecomponents.table.filter.ExportFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>eXtremeExport</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<taglib>
<taglib-uri>/extremecomponents</taglib-uri>
<taglib-location>/WEB-INF/tld/extremecomponents.tld</taglib-location><!– 别忘了把那个tld拷贝到相应目录去 –>
</taglib>
其实,那个filter只是在使用<ec:export>的时候才需要,不过这个功能还是很有用的。
export里面的excel和pdf默认不支持中文,需要手工修改源码,excel的比较简单:
修改org.extremecomponents.table.view.XlsView.java(我指的是1.0.1-M4-A14的相应代码)
102行:
HSSFCell hssfCell = hssfRow.createCell(cellnum);
hssfCell.setEncoding(HSSFCell.ENCODING_UTF_16);(就是添加这一行)
122行:
HSSFCell cell = row.createCell(cellnum);
cell.setEncoding(HSSFCell.ENCODING_UTF_16);(就是添加这一行)
这个在使用UTF-8时工作正常。如果其他Unicode环境可以尝试HSSFCell.ENCODING_COMPRESSED_UNICODE。
编译后将对应.class放到WEB-INF/classes相应目录就可以了。
pdf view的比较麻烦,还没尝试,解决方法参照这个帖子:
http://extremecomponents.org/forum/viewtopic.php?t=139&highlight=chinese+filter
http://www-128.ibm.com/developerworks/cn/xml/x-ospdf/index.html
还有一小点:
升级到1.0.1-M4-A14以后两个图片改名了,如果用1.0.1-M3的对应gif则需要该如下两个文件名(我修改的那个ZH-CN已经重命名过了):
searchArrow.gif -> filterArrow.gif
search.gif -> filter.gif
说的比较罗嗦,主要是想让和我一样的非常初级水平的朋友能够比较容易上手。其实eXtremeComponent的文档很不错,用那个上手其实更好,我仅抛砖引玉,各位大虾多多包涵。
Rate My Life
This Is My Life, Rated | |
Life: | ![]() |
Mind: | ![]() |
Body: | ![]() |
Spirit: | ![]() |
Friends/Family: | ![]() |
Love: | ![]() |
Finance: | ![]() |
Take the Rate My Life Quiz |
新年,2005总结再见,欢迎2006来临!
2005年是我的本命年,其间很多事情发生了改变,人生收获颇多。所以,这里几个流水账,自勉。
1、年初和期末考试作斗争,并且成功全过。这门过后我的学分基本修够,减少了下个学期的专业课学习压力,是个成功。
2、第四次冲击6级。靠,我个人非常清楚英语的重要性,所以一直注意实际阅读、听的能力,但是六级的应试能力不佳。幸好zz帮助我,给我找了些真题,而且教导我要向过6级就好好做真题。结果顺利通过,真是喜出望外。今年是老版6级最后一年了,算是赶上这个末班车了。谢谢zz。
3、陪zz准备北京公务员考试,本来说陪她考的,可是由于时效问题,没有真正陪她,也没有好好帮她复习。她没过。这是个失败,明年要陪她冲击。
4、学校第二学期开始,开始一段比较自由的学习。我开始认真地读《程序员杂志》,为自己从硬件兴趣型到软件专业型的转换做准备。经验是,不管如何要专业。
5、和小梁合作的jsp的电子商城项目被我们强行终结,幸好将我们将货款收回。这个项目我们从去年9月做到今年3月,成本亏了是肯定的,但是让我从一个asp程序员转型为jsp程序员,真正了解脚本是什么。呵呵,我的asp还是2年前在玩票,现在的jsp让我慢慢往后了解server可以如何运作。这里不多说了。但是这真的是个正式的算钱的项目,体会了软件工程,学习了如何分工协调,从我的搭档身上也学到了很多,我的学习能力在这个项目上迅速提升。
6、做了几个网站,包括给小叔公司代理telecobriges,还有大学同学的《厅长小武》,还有一个Moshiwig假发。基本上是设计型的,分别对PSD切片、xhtml+w3c等进行了更多的尝试。
7、五月和zz去青岛旅游,太高兴了,充满无数美好回忆!所以明年还要继续选择一个目的地去旅游。
8、进行二级实践课程,认识了几个好朋友,与他们的共事使我真正进入Java Web开发的阵营,并且用心的体验了什么是轻量J2EE开发,真正认识了Spring、Struts、Hibernate,几乎是一夜间我就成为了一个Javaer。
9、上了软件心理学,并认真思考了一下UI设计的问题。虽然没有上升到学术高度,但是确实认真思考了这方面的问题,感觉很有收获。
10、开始研究什么是架构,什么样的需求需要什么样的架构。多次和LBBZH讨论过这些问题,感觉收获巨大,他是个好朋友,以后还要多向他学习。
11、开始用业余时间在混乱的开源项目中体验不同的思路,从而可以在简历中说熟悉了一大堆的框架、工具等等。发现开源社区的意义,并尽量做些贡献(eXtremeComponents、参与翻译Pro Spring等)。这种感觉是快乐充实的。
12、协助一个朋友忙开网吧的事,并出差山东一次。虽然时间不长,但这种只身去陌生地方的经验是第一次,男人需要成长呀。
13、今年第一次自己找了个工作。得到了一个朋友的帮助。工作了不到两个月,平生第一次正式的领到工资。虽然在单位没有发挥自己的全部实力,但是还是认真地做事,可惜单位的职位还是不太适合我,我需要一个空间让我自由发挥。但是单位的同事都是朋友拉。谢谢丸子!
14、今年也第一次尝试了辞职。仅仅工作了两个月就被朋友召唤走了,心里没有一丝依恋。因为新的环境会很自由!辞职的流程还是比较长经验的,哈哈。
15、和朋友组成Team去密云做工程,我的职位是系统架构师。非常惭愧,其实不配这个称号。但是被人家吹捧的感觉还是不错的,谢谢你们的善意欺骗,我会努力成为真正的master的。
16、终于有足够的money陪zz逛街了,很爽。尤其是可以不假思索的说“拿下”,看zz惊讶的笑脸,满足啊。男人就应该这样,明年继续。
17、我和zz终于走到一个里程碑,我们已经计划好,她已经同意嫁给我了。具体的计划还在筹划,这是我人生中的重大决定呀。
18、今年花了很大的心思给zz准备生日礼物。她非常满意。男人应该尽到他的心意。zz,我喜欢给你画画。
19、今年在硬件上。我花eShop工程和小武等工程的钱买了个Dell 1704FPT LCD,并且通过我的努力将有坏点的显示器换成了一个完美的8ms板的。当然1704颜色一般,准备以后换个好的。后来入手了Logitech G5和MX510两个鼠标,键盘变成了Dell 8135。其余的新鲜东西没啥了。
20、年底送给zz一个iPod nano黑色。原先跟她说她并没有感兴趣,但是送她以后她却被它迷住了。她超级喜欢这个礼物,个人认为这礼物是我的杰作。同时送了iDog小狗一直,完全满足我家zz的爱好!
21、由LBBZH推荐加入了BJUG,参与了几次活动,受益匪浅。对各位大牛真地是佩服得五体投地,并且也迅速找到了自己的不足。更加认真地扎入到java这个阵营中了!学习了更多的框架,理解也比以前深刻了,明年还要继续跟进。
22、今年丢了一次钱包,卡没有使用强密码,损失了800元。还好先前花980买了个Meizu E5 512MB Mp3,它给我带来了很多的音乐享受,也让我少丢了另外800元钱。明年要涨记性,多注意防贼!
23、我的三星X108丢失在青岛的崂山风景区,具体丢失过程不明,但是以后还是要多家小心。 好了,23是我的幸运数字,不继续写了。
可以说2005年是我到现在的人生经历中收获最大的一年。学习平稳到了一个收获期,成功转型,成功潜入Java开发阵营并站稳脚,感情稳定并得到认可,经济状况明显好转,性格也成熟了很多,我真的从一个男孩成为一个准男人了。明年的目标就是更男人!要更男人就是为了要扛起我的父母和爱人。期待2006,一定要比2005更加充实。
Spring 2.0和给贫血模型充血
Spring 2.0 vs. the Anemic Domain Model
原来是因为老马骂了贫血模型为反模式,说冲血模型才是最好的,能够真正的OO。
不过Spring 2.0的概念被骂了个体无完肤。
本身,我的立场从来就没有站在OO这一边,我是真的无所谓的人,什么过程、OO、FP我都很认同,当然能优雅些是最好的。
看了以后就想到WQH前两天就已经推荐给我的ajoo写的充血模型的问题,我才意识到QH大师又走在我们前头了!
看了下javaeye上贫血/充血的讨论,才豁然开朗。
知道为什么冲突就对了。关键点还是在争吵OO,而OO在领域模型方面有时适合充血有时适合贫血,当然贫血居多,所以举起例子总是两边倒,没有定论。
还好,抽出重要部分,对于基本CRUD,那么绝对是贫血模型就好了。而对于有复杂计算的领域模型,我们要建立一个完备的OO的领域模型则需要充血。
这提醒了我们,充血的确是需要的。不过给Hibernate下的POJO(明显贫血到死)充血并不容易,所以才有了更多的文章讨论这个问题。
记录下来,大家有兴趣一起研究:
TSS:Spring 2.0 vs. the Anemic Domain Model
http://www.theserverside.com/news/thread.tss?thread_id=38047
Javaeye论坛:贫血就贫血,咂地?
http://www.hibernate.org.cn/viewtopic.php?p=100045&sid=df2163b2c94afbb6b214da6b3be42d73
ajoo在javaeye的conflunce上写的:怎样给马丁的充血域对象注射依赖
ajoo一文的后篇:http://www.javaeye.com/display/ajoo/Dependency+Injection+For+Rich+Domain+Model
对程序员透明的非aop方法解决rich domain object的依赖注射
http://www.javaeye.com/display/ajoo/Transparent+Dependency+Injection+For+Rich+Domain+Model
Codehaus上的一个解决方案:Dependency Injection For Rich Domain Objects
http://docs.codehaus.org/display/YAN/Dependency+Injection+For+Rich+Domain+Objects
老马写的批评贫血模型的檄文:AnemicDomainModel
http://www.martinfowler.com/bliki/AnemicDomainModel.html
Spring Blog上的原文:Spring 2.0 vs. the Anemic Domain Model
http://jroller.com/page/habuma?entry=spring_2_0_vs_the
我个人认为POJO还有DTO都是简单的VO,而VO就是VO,要区别于Real Object。我们的domain里面大都是VO而不是RO。Hibernate也是基于VO的,EJB3同样。所以RO应该说是理想OO下的东西,我们真正要用的时候,还是可以自己选择是否要实现这种复杂的东西的。但是不用RO则我们的程序就变得过程化。所以老马也认为这是头疼的事,但又不要解决,只能放到他的TODO list里面了,哈哈。
哈哈,但是看完Spring的那个Blog,感觉Spring 2.0做好了解决多向以来的模型的方法是很不错的,当然是由解决给贫血模型充血引发的,但是我认为它还能解决其它问题,所以感觉不错。但是Spring 2.0再次强调Aop的好处,也的确能看到,所以有时间还要学习一下AspectJ。
而这个问题ajoo说了IoC和Aop都可以解决,感觉各有道理。IoC方式感觉代码容易读懂,也合理。而Aop则代码有点牵强,当然使用起来感觉很爽,尤其和Lazy-init结合,对生存周期的控制有它读到的地方,而且想明白了用Aop+Annotation感觉也很清楚优雅。
非常完美的一天!
和每个找她的周末的早晨一样,习惯性的期望13路正好经过,因为搭乘13是去她家的最佳车辆。作为完美一天开始的信号,我看到十三路从远方开来,并且面前是个绿灯,可以马上过马路到车站。快步冲过人行道,我与车一同停下,上车,心情很愉快!
我在锣鼓巷倒车,换乘115路。下车继续用我喜欢的节奏快步前行,到了115路总站发现刚好就要发车,小跑几步上了车,还坐在我最喜欢的皇帝位上。皇帝位就是最后一排最中间的那个坐,视野广阔,可以面对整个过道,拥有清晰的视野是让人心情轻快的事。
8:05分,我已经在ZZ家楼下。天太冷了,我走到ZZ家的楼道中,此时她已经收到了我到达的讯号,因为我听到她家的门被打开又被关上的声音,多么熟悉呀,说明我家宝贝已经就要下来了。
然后就是蹦蹦跳跳的下楼的声音,我迎上去,我家ZZ看来很高兴,她在看着我开心你的笑。我抱起她,一直到楼下。
按我们的计划上午有个健身的活动,我们搭车去了KFC,吃些早餐。要了咖啡和麦香猪柳蛋的组合。这个选择很英明,芝士ZZ很喜欢,而蛋的口感很顺华,猪柳则明显调和了清淡的口味,配合在一起就能给我们满足的感觉。然后就是期待中的一小段运动时间,现在健身已经是我们生活中的一个重要节目了,因为现在的生活节奏的确需要这种节目来缓解,边运动边聊天。
ZZ说昨晚吃的太少了,尽早就很饿,刚才的早餐其实大部分被我干掉了……ZZ说要计划一下中午吃什么,她想吃好的。
什么叫说曹操曹操就到?在完美的一天一定要有这样的巧合才对。就在我们计划吃什么的时候收到了姐姐发来的短信,问我们在哪里。嘿嘿,姐姐周末的短信就是说要有饭局了。
正好中午要去国展家乐福,就应了姐姐……中午去吃汉拿山,上次就说请姐姐吃的,正好也是ZZ的最爱之一。而我正好是无肉不欢的人,当然乐意的不得了!
饭局定在12:00。我和ZZ先去国展家乐福,这里的特点就是物种极大丰富,我们并不喜欢这里火车般的长队,但是喜欢到这里发现没见过的食物,这种感觉有点像在逛博物馆。
由于时间仓促,我们主要流连于西餐区,因为ZZ总想给我做pasta吃,前一天其实我们已经来过,不过还没有过瘾,我们继续寻找各种pasta的佐料(昨天已经买了通心粉和番茄肉酱),真的很好玩。很快接到电话,二姐的车到了。
我们两个迅速跑出去了,活像两个企鹅,哈哈,摇摇晃晃跑过过街天桥。
去吃汉拿山了。可爱的明明没来,哥哥点的菜。这里的牛扒还是那么好吃,让人感觉幸福呀。腐败的过程不赘述,吃完以后我们来到安贞华联。
ZZ想要兰寇的so magic香水,可惜这里没有兰寇。然后我们逛啊逛,终于逛到了海盗船,那天答应送她一个新耳环。其实她扎了耳朵眼没几天,现在还没好利落呢,前几天送她了一对耳钉,她还想要环。
到了店里,她在挑……我用眼扫了一下,发现一对比较闪亮的,好像在呼唤我。我推荐给ZZ,她一下就喊道:“太漂亮了!”然后她也环视了一下,马上肯定我选到的是最漂亮的,然后说我要买下它。
我非常干脆利落的让小姐开票并去付账了,这是我最近练出的本事,做男人给女朋友花钱一定要买单不眨眼不犹豫,说实话也没什么犹豫的,我喜欢她闪亮亮的。
回来的时候她已经把耳环换好了,看着她闪动着满意的眼神,我心里十分的满足,嘎嘎嘎!
然后继续逛,卖首饰的柜台真多,不过没怎么看到更好看的。所以说是完美的一天,因为想要的东西马上就可以找到!
我们继续逛,她给我指了很多毛衣,可能我很想给她买东西,并没有看到什么让我眼前一亮的毛衣。我现在也变挑剔了,因为要让她有面子我也要打扮得潇洒一些,前年这个时候我可不会逛商场买衣服,但是现在,逛商场感觉就像在自己家里一样。
下了楼,本来要回家了,看到国美电器了。她想起要买个卷发棒,其实去年她就要求过我,可是看到的都太低档了,所以还没出手。
进去以后,很快选定了德国伟嘉的3合1卷发棒,我坚持要送给她!她欣然接受,我很满足,嘻嘻。
然后过了马路,718很快到站,然后又很快有坐。到了家里,有香喷喷的牛肉面等我们爽呀!
爽呀!爽呀!爽呀!爽呀!
真的很满足,因为很完美,我们已经找到了应该收集到的所有快乐碎片,下一步就是步入婚姻殿堂了,她也欣然接受,我就要订婚了,当然日程还没有订!
所以,这是需要纪念的一天!
2005年12月11日!