Cleanliness is next to impossible.

2009-07-03

A Cheerful heart 一颗欢乐的心 (翻译)

Filed under: 生活 — LiQiang @ 10:33:57

原文来自:http://happylifeandwork.com/behappy/a-cheerful-heart/

Maintaining a cheerful heart is very important to being happy in life and at work. It is often not so much about our circumstances, but how we respond in the midst of those circumstances. Another way to put it might be that what we achieve is not nearly as important as what we overcome. And, it takes the right spirit of thankfulness, attitude of gratitude, and cheerful heart to overcome many of life’s toughest circumstances. The questions then becomes where does this strong yet peaceful spirit come from. It comes from a personal relationship with Jesus!

在生活和工作中保持欢乐的心情是很重要的。很多时候重要的不是我们周围的环境怎样,而是我们在这些境遇中怎样反应。另一种阐释是我们达成的目标并不如我们克服的困难重要。克服生活中最困难的环境需要我们有感恩的精神、感激的态度和欢乐的心情。…..

“The precepts of the LORD are right, giving joy to the heart. The commands of the LORD are radiant, giving light to the eyes”…Paslm 19:8

With this joy in our hearts and light in our eyes, we can “Serve the LORD with gladness”….Psalm 100:2

When somebody is eighty-four years of age and is still able to do just a little bit of the work she loves, that is a great privilege,” said the inimitable Corrie ten Boom before adding, no doubt with a smile, “but I am able to do so much!” According to her coworker, Pam Rosewell, Corrie was continually thankful to God for every opportunity to serve Him, and she went about her task with an enthusiasm hard to equal. “How she enjoyed life,” Pam later recalled, “…and what a sense of humor she had! We spent a lot of time laughing; she was very young in spirit.”

“He who is of a merry heart has a continual feast.”…Proverbs 15:15

有愉悦心情的人每天都在过着节日。

“A cheerful heart is good medicine”…Proverbs 17:22

欢乐的心情是很好的药物。

Every day has its share of burdens, and many of us have aches and pains. But a cheerful heart is as irrepressible as a cork in water. A joyful person just cannot be held down. What a privilege to serve the Lord with gladness and to use our gifts for His glory, doing so with a merry heart. We can moan and complain about life or we can keep life in perspective and enjoy it. Paul learned the secret of contentment, and so can we. That choice is yours and mine.

生活中每天都有一些负担、困难,我们很多人都有疼痛。但是一颗欢乐的心就像在水里无法压下去的软木一样。一个欢乐的人是不会被击垮的。…..我们可以呻吟和抱怨生活,但也可以正确看待生活、享受生活。…….

The future is glorious. The best is yet to be, and you and I have the privilege to help hasten the coming of Jesus…..Corrie ten Boom

2009-06-21

IPhone程序XCS RSS v1.0开发完成

Filed under: XCSRSSReader, iphone — LiQiang @ 13:43:40

    最近完成了IPhone Developer Program的申请,我的第一个IPhone应用程序开发完成了第一个版本,今天提交给App Store进行review,不久就可以在App Store下载安装了。
    XCS RSS现在实现了下面功能:

  • feed分类
  • feed添加(当前只可以手工添加,下一版本增加导入功能)
  • feed文章下载到本地,可以离线阅读
  • feed文章在web浏览器里阅读

下面是部分界面的截图:

     
  

2009-06-08

Drupal新站

Filed under: 软件 — LiQiang @ 22:50:45

drupal@xuecs
欢迎到新的基于drupal的主题站点: drupal@xuecs

2009-03-02

Java中Cache的使用

Filed under: java, framework, develop — LiQiang @ 14:43:43

Cache简介
    在Java开源领域,常用的cache有以下几种:

  • JBossCache
    JBoss支持的Cache引擎,树形cache,在JBoss app server中使用它进行数据缓存、以及cluster之间的数据复制存储。
  • EHCache
    在Souceforge的一个开源项目,使用比较广泛,有很好的支持。
  • OSCache
    相对轻量级一些,一般用在hibernate和web页面的缓存。

   Cache的使用范围:

  • 降低数据库负载,对数据库数据进行缓存
  • 提高web页面生成速度,对于重复使用的web页面缓存部分或者全部
  • 提高计算速度,对于复杂计算结果缓存

   进行Cache的前提:

  • 被缓存的数据没有失效
  • 被缓存的数据可以提出一个替代值,用于查找缓存对象,比如一个hashcode

     Cache通过JGroup或者JMS等方式,可以扩展支持cluster复制缓存。

使用Spring的AOP机制实现method cache
     Spring提供的MethodInterceptor可以方便的实现一个简单的method cache interceptor:

public Object invoke(MethodInvocation invocation) throws Throwable {
        String targetName  = invocation.getThis().getClass().getName();
        String methodName  = invocation.getMethod().getName();
        Object[] arguments = invocation.getArguments();
        Object result;

        logger.info("looking for method result in cache:"+targetName+" "+methodName+" "+arguments);
        String key=getKey(targetName,methodName,arguments);
        if(objs.get(key)!=null){
            return objs.get(key);
        }else{
            result = invocation.proceed();
            if(result!=null)
                objs.put(key,result);
        }

        return result;
    }

  上面的代码中首先根据方法的签名构造缓存键值,方法签名包括类名称、方法名称、参数等信息,用于区分方法缓存对象。然后把方法执行结果和签名保存到缓存中。在第二次使用时,如果在缓存中可以找到相同签名的对象,那么可以把结果直接返回。这个代码只是一个机制示例,真正的实现有很多问题需要解决。在下一节中我们会看到spring-modules提供的完整实现。

Spring2.5中EHCache的使用
Spring提供了EHCache的简单封装,配置如下:

 <bean id="cacheManager"
          class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
      <property name="configLocation" value="classpath:config/ehcache.xml"/>
 </bean>

EhCacheManagerFactoryBean用于初始化CacheManager,读取外部配置文件,以及支持在bean config注入各种属性信息。
     Spring本身提供的ehcache封装比较简单,另一个开源项目spring-modules提供了更加好用的cache封装接口,可以联合使用。
     Spring-modules-cache的实现机制是通过Spring的AOP机制,根据配置截取方法调用,对方法调用的参数和返回结果进行缓存,对于缓存失效条件也通过方法调用的截获进行触发。

 <bean id="cacheProviderFacade"
          class="org.springmodules.cache.provider.ehcache.EhCacheFacade">
        <property name="cacheManager" ref="cacheManager" />
    </bean>
    <bean id="YourServiceCached"
          class="org.springmodules.cache.interceptor.proxy.CacheProxyFactoryBean">
        <property name="cacheProviderFacade" ref="cacheProviderFacade" />
        <property name="cachingModels">
            <props>
                <prop key="get*">cacheName=mainCache</prop>
                <prop key="find*">cacheName=mainCache</prop>
            </props>
        </property>
        <property name="flushingModels">
            <props>
                <prop key="update*">cacheNames=mainCache</prop>
                <prop key="add*">cacheNames=mainCache</prop>
                <prop key="delete*">cacheNames=mainCache</prop>
            </props>
        </property>
        <property name="target" ref="YourService" />
    </bean>

    使用spring-modules提供的EhCacheFacade和CacheProxyFactoryBean:

  • EhCacheFacade
    用于封装底层cache接口,对于不同的cache提供者,可以提供统一的facade接口,spring-modules直接支持的cache提供者有:ehcache、jbosscache、gigaspaces、jcs、tangosol等。
     
  • CacheProxyFactoryBean
    对需要进行cache的对象进行代理,用于截获方法调用,对cache进行保存或者失效操作。
    cachengModels 配置哪些方法需要进行缓存。
    flushingModels 配置哪些方法用于触发缓存失效。flushingModels 配置的失效缓存池可以是多个,用于细粒度的控制失效范围。
    target配置要进行代理缓存的实际对象。

 

2009-03-01

SiteMesh记要

Filed under: java, framework — LiQiang @ 21:51:55

    SiteMesh是一个使用java语言实现,采用decorator模式装饰页面的框架。SiteMesh采用filter实现,实现了下面功能:

  • 对于页面被SiteMesh包装输出的页面代码,sitemesh进行解析,然后根据配置进行代码修改。
  • 提取大量网页中重复相同的html、js、css等代码
    SiteMesh提取web页面的公共部分,把页面的公共代码提取出来,可以灵活配置,方便页面的开发、修改
  •  对于页面根据环境的不同,自动的进行定制修改,可以根据浏览器类型、用户语言、搜索引擎、操作系统等进行不同的页面装饰。

   SiteMesh的配置文件主要包含两个:

  • sitemesh.xml
    包括了parse和mapper的配置
  • <page-parsers>
            <parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
    </page-parsers>
    <decorator-mappers>
           <mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
                <param name="decorator.parameter" value="pagetype"/>
           </mapper>
           <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
                <param name="config" value="${decorators-file}"/>
            </mapper>
    </decorator-mappers>
    
  • decorators.xml
    这个文件是可选文件,从前面的sitemesh.xml配置可以看到,这个文件是被ConfigDecoratorMapper使用的。
     
  • <decorator name="ajax" page="ajax.html">
          <pattern>/yourajax.action</pattern>
    </decorator>
    <decorator name="default" page="main.html">
            <pattern>/*</pattern>
    </decorator>
    

SiteMesh的主要处理过程:

  1. Servlet Container进行正常的页面处理,各种filter执行
  2. 在执行到sitemesh的filter时,根据配置确定是否需要执行
  3. sitemesh构造PageResponseWrapper,然后执行之后的各种filter
  4. 通过PageResponseWrapper得到需要进行装饰的页面对象,PageResponseWrapper调用配置的Parser进行页面解析
  5. 调用applyDecorator进行页面装饰处理,使用freemarker或者velocity模版作为装饰外框
  6. 把处理结果写入到response

几个主要的对象:
Parser
sitemesh为了对页面进行装饰,需要解析页面代码为内存对象(类似DOM树),然后才能对这些不同的节点进行装饰处理。框架提供了 FastPageParser 和 HTMLPageParser 。FastPageParser代码更为简洁,HTMLPageParser重写了FastPageParser,并且增加了更多的功能。

Mapper 
Mapper用于选择正确的装饰配置,比如上面配置的 ConfigDecoratorMapper ,根据配置文件中的url匹配规则进行装饰,而 ParameterDecoratorMapper则是根据url参数按照名称选取decorator配置。

PageFilter
sitemesh的框架核心,作为调度中枢。在struts 2中,一般使用它的子类FreeMarkerPageFilter或者VelocityPageFilter。

 

Struts 2 记要--Result

Filed under: java, framework, develop — LiQiang @ 13:22:43

回顾Struts 1的Result处理
        Struts 1的Result页面处理是通过 RequestDispatcher.forward 方法执行,而RequestDispatcher的实例是servlet容器提供的。这样struts 1在result页面处理时,实质上是直接转交给了web容器。
         页面转交给web容器处理后,web容器就可以通过已有的各种url处理机制处理,比如和velocity集成时,实质上是配置了servlet容器映射.vm URL到VelocityViewServlet进行处理。而vm页面的数据来源则在struts 1处理完成时已经放入了request、response、VelocityContext等对象里面。

Struts2的处理方式
         前面一篇讲的xwork容器环境,可以知道Result其实是xwork提供的一种机制。Result在运行时是一个实例对象,被DefaultActionInvocation构造、调用,Result执行时可以直接把处理结果写入到应答数据流中。
         Struts2内置了多种Result类型的实现,比如VelocityResult、PlainTextResult、XSLTResult等,当然也可以自己扩展,比如下面的代码增加了图形输出Result:

<result-type name="d2chart" class="com.xuecs.ezweb.struts.result.Data2ChartResult">
   <param name="height">150</param>
   <param name="width">200</param>
</result-type>

 Data2ChartResult实现的是首先通过JFreeChart构造图形,然后写到应答数据流中。
 对于JSon数据转换,可以使用 com.googlecode.jsonplugin.JSONResult 自动转换json数据。

    Struts 2改变了Result处理方式,带来以下优点:

  • 不依赖与web环境,Result接口要求提供的方法 execute(ActionInvocation invocation) 没有和web api相关
  • 相比struts 1依赖Dispatcher进行处理,Struts2的Result功能可以不依赖web容器的功能
  • Result执行后仍然在框架中,会通过inteceptor桟返回,可以通过inteceptor再进行扩展处理

2009-02-27

Struts 2 记要--容器

Filed under: java, framework — LiQiang @ 19:00:13

    Struts 1在06年后发展方向大致有两个,一个是Component-based的Shale框架,另一个就是和WebWorks 2合并作为Struts 2。最终Struts 2设计为合并了Struts 1和WebWork 2。
    WebWork本身采用了Xwork作为它的容器环境,struts 2自然也采用xwork容器环境。xwork是OpenSymphony的一个项目,提供了以下功能:
    1. IOC容器环境
    2.表达式语言
    3.数据校验框架
    4.数据转换
    5.可扩展的配置

    Struts 2很重要的一个改变就是容器环境的引入, struts 2里IOC容器最主要用在了各种框架对象的创建,框架核心的各种依赖注入,以及inteceptor机制。同时xwork可以和spring集成,Action就可以使用spring容器的大量高级功能。

xwork的使用方式
    xwork 容器不仅可以用于struts 2的核心部分,用户也可以直接使用。比如struts 2的plugin:config-browser ,在获取struts2运行时的配置时,通过下面代码可以把struts解析的配置注入到类中:
   @Inject
    public void setConfiguration(Configuration config) {
        this.configuration = config;
    }
Action的创建
    在Struts2的Dispatcher创建Action时,会调用xwork提供的ActionProxyFactory得到Action,而ActionProxyFactory的具体实现在struts2是StrutsActionProxyFactory,StrutsActionProxyFactory则继承自xwork的DefaultActionProxyFactory。通过ActionProxyFactory得到对象时它会通过ObjectFactory构造action。xwork容器会进行注入操作,同时如果配置了spring,xwork容器会调用spring  context创建对象,然后注入xwork配置的注入信息。

ObjectFactory

  • 创建action
  • 创建inteceptor,使用ognl设置属性,并初始化
  • 创建Result
  • 创建validator
  • 调用IOC容器进行注入

DefaultActionProxy

  • 作为Action的代理,包含了action的各种配置信息
  • 负责通过DefaultActionInvocation执行action

DefaultActionInvocation

  • 调用ObjectFactory创建action,result
  • 调用inteceptor chain
  • 执行action
  • 调用action执行结果result

Inteceptor
     xwork实现的是 command-pattern 框架,核心是执行action,在action的执行前后通过inteceptor进行定制化操作,这种模式的使用不局限于web环境,带来了一下优点:

  • 可以灵活的配置对于不同的action采用不同的inteceptor
  • inteceptor封装了action需要的统一操作,框架提供了很多常用的inteceptor来简化开发
  • 可以脱离web环境运行

2009-02-23

Struts 2 记要--历史

Filed under: java, framework — LiQiang @ 22:46:30

    最近一个项目在我的推进下采用了struts 2进行开发,对我来说从03年初第一次接触struts到现在有6年了,因此struts 2对我来说就像时隔多年重见的老朋友。03年使用struts的时候还在学校,那时候参加了一个地税系统的J2EE项目,当时只是懵懂的感觉struts用起来机制蛮复杂的,不明白内部机制,只懂得通过各种配置使他和我步调一致。后来看了J2EE design patterns,渐渐明白struts采用的front controller、facade、MVC等等模式,达到提高系统灵活性、扩展性、开发速度的目的。
    06年的时候
,经过2年的.net开发,搜寻了很多web框架技术,没有找到比较成熟好用的框架,就萌生了使用C#实现struts的想法。从想法酝酿到实现这样一个框架原型,大致用了一周时间。然后这个框架使用到了一个实际的客户系统项目,进行了进一步完善,取得了很好的效果。
    Struts 1的几个优点
:
      1. MVC
   很多人在谈论的MVC,MVC这个词在前几年就已经用滥了,大多数人都在谈论MVC,但是真正能够谈的上MVC模式使用很好的系统是少之又少,很多只是把MVC作为一个招牌而已。
       Struts是一个标准的MVC框架
,当然一般会谈论Type-1,Type-2型的MVC,这点我们暂不做深究。MVC是一个模式,而Struts从一方面来说是MVC的一个模式实现,同时它也规范使用Struts的应用系统必须采用MVC模式,这个模式规范的是WEB层的一个范式。
        Model
从框架角度来说是ActionForm基类,它提供了从WEB页面到Server端映射的存储数据模型,同时框架提供了为之服务的工具类,自动的把web层传过来的参数通过reflection设置到form数据中。Model从应用端看,struts要求应用必须使用model,同时需要继承自ActionForm。
        Controller从框架角度是ActionServlet,采用了Front Controller模式,作为所有url的前端预处理,它把Model和View联系起来,处于中枢位置。从应用角度Controller是应用的Action类,这个应用类必须继承自Action基类。
         View从框架角度是最终struts返回的页面,可以是JSP再次处理或者其他模版页面,从应用角度就是最终页面。
         可以看到struts对于MVC模式作为一个框架的作用,它同时扮演了组织者和实现者的角色。
    2.在核心的MVC框架之外,struts 提供了很多其他的功能,包括一套完整的TagLib、数据校验框架、WEB工具类等。
    3. struts的一个特点是它的配置方式,相对与传统的单web页面(asp,php,jsp),改变为一个URL关联了java的多个类文件、web页面、配置参数等等,这样它就可以比较容易的进行底层修改,而不影响上层的应用。
        当然这些xml配置,经过2、3年后也遭到很多人的反对,因为繁多的xml文件不容易维护。因此出现后来的code behind、convention、annotation/attribute等技术来解决配置问题。不过url对应多个对象处理、灵活配置的思想仍然保留。

2009-02-22

ExtJS 详解–布局与弹出窗口

Filed under: ajax — LiQiang @ 12:53:15

ExtJS支持多种布局样式,其中border layout比较类似Java Swing的BorderLayout,比较常用,比如常见的左右分栏:

            var tree=load_func_tree();
            tree.root.expand();
            var grid=loadGrid();
            var nav = new Ext.Panel({
                header:true,
                title       : '功能树',
                region      : 'west',
                split       : true,
                width       : 200,
                collapsible : true,
                margins     : '3 0 3 3',
                cmargins    : '3 3 3 3',
                autoScroll :true,
                items:[tree]
            });

            var viewport = new Ext.Panel({
                layout: "border",
                id: 'mainview',
                renderTo: 'main',
                width:980,
                height:450,
                items: [nav,grid]});
        });

Border布局,通过指定panel的region属性设置,位于东、南、西、北、中心,同时可以指定是否可以改变大小、容器是否自动出现滚动栏。

ExtJS的弹出窗口很容构造,只需要new window然后展示即可。

     win=new Ext.Window({title:"hello",
                            width:360,
                            height:120,
                            maximizable:true,
                            html:'hello',
                            modal:true
                      };
     win.show();

对于一般的消息框,ExtJS也提供了接口:

Ext.Msg.confirm("确认",msg,function(btn,txt){
    if(btn=='yes'){
      //do staff
    }
});

ExtJS 详解–树控件

Filed under: ajax — LiQiang @ 12:48:03

ExtJS的树控件有以下特点:

  • 异步加载树节点
  • 树节点拖拽
  • 回调接口

树控件构造如下:

var tree_func = new Ext.tree.TreePanel({
        region:'west',
        header:false,
        title            : '功能树',
        split:false,
        bodyStyle:          'padding:5px;',
        collapsible      : false,
        animCollapse     : false,
        border           : false,
        autoScroll       : true,
        autoWidth:true,
        autoHeight:true,
        animate          : false,
        enableDD         : true,
        containerScroll  : true,
        height           : 400,
        width            : 400,
        minSize: 200,
        loader           : tree_file_loader
    });

树控件的数据源:

var tree_file_loader = new Ext.tree.TreeLoader({
        dataUrl   :url_tree_func
    });

服务器端的JSON数据样例velocity模板如下:

[
#foreach($row in $functions)
	{
		id: ${row.func_id},
		text: '${row.name}(${row.func_id})',
		url: '${row.url}',
		leaf: ('${row.url}'==''||'${row.url}'=='#')?false:true
		#if($withCheck)
			,checked: '$!{row.checked}'==''?false:true
		#end
     }#if($velocityCount!=$functions.size()),#end
#end
]

id、text、leaf是树控件要求的属性,如果指定了checked属性,那么树控件会显示选择框。
数控件也有很多事件挂钩可供使用:

 tree_func.on("click",function(node,e){
        curid=node.attributes.id;
        if(node.attributes.url=='#'
                || node.attributes.url+''==''){
            reload_func_grid();
        }
    },this);

    tree_func.on("movenode",function(tree,node,oldpar,newpar,e){
        move(node.attributes.id,newpar.attributes.id);
    },this);

上面代码指定了树的点击和移动节点事件,移动节点通过构造树时的enableDD属性设置。

Next Page »

EMail:liqiang@xuecs.com