解惑

解己之惑,解人之惑

2009年5月 (第2页共3页)

无状态化

越来越感觉各种系统在构架的时候进行了无状态化,因为在大规模系统中,要更好的进行负载均衡以及集群,无状态的服务是最好的选择,因为每个请求都是独立的不依赖上下文的,任何一个服务节点的崩溃都不会影响整个系统,而且要增加系统的负载能力也很容易,增加更多的服务节点就行了。从GAE默认不包含Session我们就可以看到一些这样做的好处。而且Context或者Session之类的东西也比较好弄,也作为一个服务,根据某个UUID或者session id之类的东西就可以进行存取,如果某些服务真的需要session,那么可以到session服务取。但是这样做会导致session的那个服务成为系统的瓶颈和薄弱点,也会导致那部分的负载均衡和HA更难达到。结合客户端的RIA倾向,更多的Session和Context保存在客户端,利用客户端框架在发起请求的时候把需要的内容发送给服务器端。

ZK国际化的原型

昨天说了ZK的国际化做得不够好,今天稍微试了下,发现昨天提到的方案是可行的,创建一个Initiator,自动的把文本替换为国际化的内容:
<?init class="xxx.I18nBinderInit"?>
<toolbarbutton label="button.add" image="../images/add.png" onClick="userListWindow.onAdd()"/>

这个只是原型,现在可能还不能处理所有的组件类型,可以简单的修改下变成通用的解决方案:
增加一个Property文件,里面添加需要处理的组件类型以及需要处理的属性,然后读取这个配置,如果谁觉得不够可以在classpath中放置一个同名的配置文件进行定制。
源代码:

阅读全文

zk的国际化不够好

官方文档中说国际化很简单,资源文件放在WEB-INF下,文件名固定,都是i3-label.properties,简体中文的就是i3-label_zh_CN.properties。
按照官方文档说的,修改Locale就是:
session.setAttribute(Attributes.PREFERRED_LOCALE,xxxLocale)
但是根本不好使,后来搜索了下,发现需要设置:
Locales.setThreadLocal(xxxLocale)

另外一个问题是页面的刷新是个问题,如果不考虑用户已有的操作,假设用户进入首页没有做什么事情,首先改变Locale,那么刷新比较简单:
Executions.getCurrent().sendRedirect(“”)

国际化在页面中使用也比较丑陋,先是:
<?taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c" ?>

<toolbarbutton label="${c:l(‘button.add’)}" image="../images/add.png" onClick="userListWindow.onAdd()"/>
比较理想的应该是像数据绑定一样,能够声明某个东西,然后Label的内容都从资源文件取:
<?init class="xxx.I18nBinderInit"?>
<toolbarbutton label="button.add" image="../images/add.png" onClick="userListWindow.onAdd()"/>

当然,这个功能可能自己也可以自己实现,有时间我会试试。

最后说的一点就是zk的默认中文是繁体中文,比较难受。

办居住证变得更麻烦了

居住证快到期了,原本以为很简单,到HR的wiki上看了下发现流程变了:

(1) 居住证到期前两个月60天, 如之前以在网上办理国个人注册及密码,凭个人身份登录,如之前未办理过网上注册,请E-mail 身份证号码及中文姓名至HR, HR将会协助注册及密码申请

(2) 前往http://218.242.131.164, 用个人身份证号码及密码登陆

(3) 填写完整<上海市居住证申请表>保存,并通知HR办理网上审核

(4) 备齐资料后前往*首次居住证办理点*递交材料

申请材料:

1、国内人才《上海市居住证》申请表;(表格上加盖单位公章,表格见附件一,盖章请至财务部门);

2、身份证及居住证原件,留复印件。

3、居住证有效期内最近一年的在沪缴纳个人收入所得税证明(请至财务部门领取)和社会保险的证明(请至网章http://www.12333sh.gov.cn/index.shtml)下载(原件及复印件,加盖单位公章)。

 

流程中的第一步就是网上申请,而那个密码是需要单位帮你申请的,而材料中的社会保险证明的那个密码也是需要到社保中心窗口申请的。

看来得几天捣腾了。

更新:
给HR发了邮件,5分钟以后拿到网上申报居住证的网站的密码。
公司外面就有个人才服务中心,走路过去五分钟,出示身份证,一分钟拿到初始密码111111。
回公司就上网打印了社会保险的证明。
至于个人收入所得证明,应该用税务局寄的那个个税证明也可以,因为去年12月才到这边,公司应该不会给我出具去年的收入所得证明。

java.lang.ClassCastException: com.sun.tools.javadoc.ClassDocImpl

这个是在生成Javadoc的时候发现的,google了下,不少问的,第一个是说这个是个bug,其实以前也google过,看到那个说是bug而且优先级是4-Low,状态也不是close就没有去理会这个问题,这次又搜索了下,耐着性子看了几个帖子,发现这个不是bug,而是有解决方案,因为我是在ant脚本里面加的,解决方案就是在javadoc的task指定classpath或者classpathref,只要和你编译那些类使用一样的classpath或者classpathref就行。

淘汰金山词霸Google版

从前天开始不能启动了,发现其他一些同事也遇到同样的问题,今天先卸载了,然后重装,过了一会提示它更新了,需要重启,点击确定,啪,出错了。系统都变得不稳定,打开什么都出那个问题。重启系统,金山词霸倒是可以运行了,但是很失望,卸载,换用灵格斯。

一个通用的面向对象的查询接口

现在做持久化基本上都会用到ORM,现在最通用的解决方案当然就是Hibernate以及由之引申出来的EJB3的持久化方案,我们在做DAO层的时候经常是直接写HQL,并不是说它不好,而是不够通用。例如本来有个功能是查询某种类型的User,但是需要额外的过滤和排序,那么就需要拼HQL的,不太好维护,所以有一个面向对象的查询接口还是比较好。
下面就是这个雏形,是我现在的项目中用到的,抛砖引玉吧。
下面是全部的类和主要的方法,其他的方法都忽略了,可以到Google Code下载全部的源代码。
阅读全文

createComponents的问题

ZK很好的一个功能就是打开一个zul文件把组件添加到页面上:
Executions.createComponents(“yyy/xxx.zul”, null, params)
但是用这种方式打开的页面有一个奇怪的问题,和直接加载的不同,直接加载的的那些image是写相对路径的,例如:
<toolbarbutton label="Add" image="../images/add.png"/>
如果是用createComponents打开,这个方式不好使,找不到图片,显示一个红叉叉,需要修改成:
<toolbarbutton image="images/add.png"/>

继承中的Serializable问题

为了实现深度克隆,一个最简单的办法就是让需要克隆的类全部实现Serializable,然后:
            ByteArrayOutputStream byteArrOs = new ByteArrayOutputStream();
            ObjectOutputStream objOs = new ObjectOutputStream(byteArrOs);
            objOs.writeObject(this);

            ByteArrayInputStream byteArrIs = new ByteArrayInputStream(byteArrOs.toByteArray());
            ObjectInputStream objIs = new ObjectInputStream(byteArrIs);
            Object deepCopy = objIs.readObject();
在实现的时候遇到一个问题,就是我的this的类的父类忘记增加implements Serializable,导致克隆出来的对象丢失了父类中的信息,解决方法当然也很简单了,在父类加上implements Serializable就行了。
所以用这个方式的时候一定要小心,就是你需要深度克隆的对象相关的所有对象都要implements Serializable,否则那部分不会被克隆,而且没有任何异常。那些类的子类也需要加上。

服务器端的分页功能

ZK的分页功能默认是在客户端做的,也就是服务器端返回所有的结果,然后客户端每次显示一页的数据,翻页的时候不提交请求到服务器端重新查询。如果服务器端返回的结果比较多,这种方案就不太好了,要实现服务器端的分页也很简单,在使用Listbox或者grid的时候不要使用mold="paging",而是添加一个Paging组件:
<paging id="groupListboxPaging" pageSize="10"/>
然后给Paging增加事件监听:
        final Paging paging = getPaging(pagingName);
        paging.addEventListener(
            "onPaging", new EventListener()
        {
            public void onEvent(Event event)
            {
                PagingEvent pagingEvent = (PagingEvent) event;
                int pageNumber = pagingEvent.getActivePage();
                int firstRow = pageNumber * paging.getPageSize();
                queryInfos.get(listName).getPageInfo().setFirstRow(firstRow);
                refreshList(listName);
            }
        });
代码中的getPaging和refreshList都是我自定义的方法,getPaging很简单,因为我的这个代码是在自定义的Window类里面的,所以:
    protected Paging getPaging(String pagingName)
    {
        return (Paging) getFellow(pagingName);
    }
而refreshList就比较复杂一些了,根据传入的list的名字查询结果并刷新list:
    public void refreshList(String name)
    {
        try
        {
            getListbox(getListboxName(name)).setModel(new BindingListModelList(list(name), false));
        }
        catch (Throwable t)
        {
            handleException(t);
        }
    }
核心就是拿到Listbox或者Grid然后setModel。

更早的文章 更新的文章

© 2025 解惑

本主题由Anders Noren提供向上 ↑