[Miles' Blog]

Welcome 2 My Planet

Available categories: [/] [development. ~] [working on downwap.] [trouble shooting] [working on Yup Mailman] [general infomation.] [life style]

一个奇怪的中文编码问题的粗暴解决办法 [Permalink]

Fri Jan 21 08:14:45 CST 2005
Category [trouble shooting]

老系统中文编码有问题。如果不设置contentType为text/html; charset=gb2312,则虽然是html源文件是中文,但是需要更改IE的charset设置(这时候实际上察看http header看到的contentType是text/html; charset=iso8859-1);如果设置了contentType为gb2312,则html源里面的中文直接成了???。

这个老系统当时运行于jdk1.3+tomcat3下,当时就不知道是那根筋不对,怎么都搞不定,最后套了一个客户端包IE,强制了编码才掩盖了问题。现在3年多过去了,怎么也得长点本事吧?于是就开始想尽办法折腾。试过了所有的方法,包括设置filter,给html加所有相关的,甚至包括设置jb的默认字符集,都完全无效。实在气不过,甚至反编译了tomcat的HttpServletResponse、JspWriter等的实现代码,一时也没看出门道。。

最后,心一横,给问题定了性:不就是一个老系统么?咱不浪费那个时间,简单粗暴地解决问题就算搞完!下面就是暴力解决法:

public class HtmlMimeResponseWrapper extends HttpServletResponseWrapper {
  
  //....

  public PrintWriter getWriter() throws IOException {
    PrintWriter writer = super.getWriter();
    MyWriter myWriter = new MyWriter(writer);
    return myWriter;
  }

  //...
}
没错!就是用一个filter,把他的PrintWriter包裹起来。decorator里面decorate,哈哈。。PrintWriter是一个内部类,细节如下:
  class MyWriter extends PrintWriter {
    PrintWriter writer;

    public MyWriter(PrintWriter writer) {
      super(writer);
      this.writer = writer;
    }

    // 关键在这里!
    public void write(String buf) {
      String newbuf = null;
      try {
        newbuf = new String(buf.getBytes("iso-8859-1"));
      }
      catch (UnsupportedEncodingException ex) {
      }
      writer.write(newbuf);
    }

    public boolean checkError() {
      return writer.checkError();
    }

    public void print(Object obj) {
      writer.print(obj);
    }

    public void print(String s) {
      writer.print(s);
    }

    public void print(boolean b) {
      writer.print(b);
    }

    public void print(char c) {
      writer.print(c);
    }

    public void print(char[] s) {
      writer.print(s);
    }

    public void print(double d) {
      writer.print(d);
    }

    public void print(float f) {
      writer.print(f);
    }

    public void print(int i) {
      writer.print(i);
    }

    public void print(long l) {
      writer.print(l);
    }

    public void println() {
      writer.println();
    }

    public void println(Object x) {
      writer.println(x);
    }

    public void println(String x) {
      writer.println(x);
    }

    public void println(boolean x) {
      writer.println(x);
    }

    public void println(char x) {
      writer.println(x);
    }

    public void println(char[] x) {
      writer.println(x);
    }

    public void println(double x) {
      writer.println(x);
    }

    public void println(float x) {
      writer.println(x);
    }

    public void println(int x) {
      writer.println(x);
    }

    public void println(long x) {
      writer.println(x);
    }

    public void close() {
      writer.close();
    }

    public void flush() {
      writer.flush();
    }

    public void write(String str, int off, int len) {
      writer.write(str, off, len);
    }

    public void write(char[] cbuf) {
      writer.write(cbuf);
    }

    public void write(char[] cbuf, int off, int len) {
      String s=new String(cbuf, off, len);
      this.write(s);
    }

    public void write(int c) {
      writer.write(c);
    }
  }
现在把问题从头掐了。虽然粗暴了一点,不过效果达到了。对于那些没有时间深究,或者懒得深究的问题,用这样的方法还是不错的。

另外值得一提的是jb的Delegate member wizard功能。通过他可以快速的作出一个Wrapper类,不用把super class的方法都一个一个去机械的实现,很是省力。只不过以前的jb里,这个功能处于Wizard主菜单,而现在则藏到了Edit下。。害我一顿好找 /images/emoticons/sad.gif

Posted by: miles
Comments [0] |

yesterday once more|怀旧经典 [Permalink]

Fri Jan 21 08:13:41 CST 2005
Category [development. ~]

今天拿了一个2001年底做的老系统出来维护,感触颇多啊。。一方面那时候java经验不丰富,很多地方的实现都很别扭;另一方面,也正因为这种生涩再加上工期的压力,造就了很多“当量换精度”的超繁琐代码,现在看来都佩服那个时候的毅力。

<miles:validinput name="SulfRate" 
  type="singleline" maxlength="50" size="22" class_="embed">
  <miles:checker checktype="req" errorwords="硫份不能为空"/>
  <miles:checker checktype="num" errorwords="硫份必须为数字"/>
  <miles:value><%=(hashCoal.getDouble("SulfRate")*100)%></miles:value>
</miles:validinput>
其实这是一个不错的实现。通过customized tag做出了一个很有创意的文本输入控件。带有自检功能,可进行多项输入检查。

再来看看这个大巫:
<miles:curveset
  width="700" height="400"
  xoff="10" yoff="0"
  xdecimal="<%=xdecimal%>" ydecimal="0"
  xspace="0" yspace="0"
  xmax="<%=xmax/1000%>" ymax="<%=ymax/10000%>"
  bgcolor='255|240|192'
  gridcolor='144|144|192|100'
  grid="1"
  xcount="20" ycount="10"
  xlabel="Qj" ylabel="Cost"
  border="1"
  legend="2" legendwidth="150" legendheight="20"
>
  <miles:curve funcclass="<%=AC%>" start="0" curvecolor="192|192|192" end="0" 
    desc="许可权成本" xmax="<%=xmax%>" ymax="<%=ymax%>"/>
  <miles:curve funcclass="<%=DR%>" start="0" curvecolor="cyan" end="0" 
    desc="脱硫-换煤最小成本" xmax="<%=xmax%>" ymax="<%=ymax%>"/>
  <miles:curve funcclass="<%=FC%>" start="0" curvecolor="blue" end="0" 
    desc="固定成本(脱硫-换煤最小成本 + 排污费)" xmax="<%=xmax%>" ymax="<%=ymax%>"/>
  <miles:curve funcclass="<%=EC%>" start="0" curvecolor="magenta" end="0" 
    desc="排污费" xmax="<%=xmax%>" ymax="<%=ymax%>"/>
  <%--<miles:curve funcclass="<%=BI%>" start="0" curvecolor="gray" end="0" 
    desc="基准投入" xmax="<%=xmax%>" ymax="<%=ymax%>"/>--%>
  <miles:curve funcclass="<%=SUM%>" start="0" curvecolor="red" end="0" 
    desc="电厂减排成本曲线(固定成本 + 许可权成本)" xmax="<%=xmax%>" ymax="<%=ymax%>"/>
  <miles:vertical vertcolor="255|0|0|50" 
    xmax="<%=xmax%>" ymax="<%=ymax%>" xpos="<%=MinReduction%>" area="1"/>
</miles:curveset>
猜得到这个做什么的么?做这个的!

这个taglib之复杂,已经完全超越了我现阶段分析代码的耐心。。。

Posted by: miles
Comments [0] |

Butterfly Effect | 蝴蝶效应 [Permalink]

Fri Jan 07 15:58:55 CST 2005
Category [life style]

"One meteorologist remarked that if the theory were correct, one flap of a seagull's wings would be enough to alter the course of the weather forever."

"Predictability: Does the Flap of a Butterfly’s Wings in Brazil set off a Tornado in Texas?"

- By Edward Lorenz




Q:如果生命中每一个选择都可以重做,我们和上帝还有什么区别?
A:区别在于——弃权仍然只是一个选择。


不仔细辨认,几乎认不出扮演Evan的是 Dude, Where Is My Car? 中的Ashton Kutcher。胡子拉碴,神经兮兮,基本颠覆了之前偶像剧专业户的形象。片中对于角色的诠释总体上来说不错。虽然无功,但也无过,很好的完成了任务。不由得又让我想起了“美国人天生是演员”的那篇阅读理解。相比之下,中文版Matrix中Neo一开口的“全是噩梦”,立马把俗称“蜡笔小新”的LYP GG推上了前台。这个桥段堪称经典,因为大多数亲临影院或者是通过枪版“亲临”影院的观众都会在这个时候听到一阵哄笑。。剧情片加入了喜剧效果,估计打死龌龊司机们也想不到吧。

。。扯远了扯远了。不过由此可见,电影是一个综合系统的工程,每个细节都可能影响最终的效果。想达到自己的目的,光靠周密的计划是不现实的,因为未知因素太多。
就算有好的故事,不见得有好的剧本;
就算有好的剧本,不见得请得到理想的演员;
就算请到了合适的演员,不见得有符合要求的摄影;
就算摆平了片厂的一切,也难保哪个跑龙套的搞个车祸;
就算是平平安安拍出来了,还得看boss有没有请别人“帮”你剪辑;
就算是天随人愿,拍出了绝世好片,也指不定上映前两天哪个疯子劫了飞机撞了楼,你的片子犯了冲,无限期搁置;
就算是如期上映,好评如潮,也很难算得到boss搞来了个“蜡笔小新”过来帮你的cool guy配音,呕心之作呕呀呕呀的呕出来一只苍蝇。。

郁闷吧。生活又何尝不是如此?每时每刻,你都站在一个岔路口上,选择任何一条路都会让你的未来独一无二。你没有时间停下思考,只能主动或者被动的沿一条向下走,而且无法回头。看上去每个岔路之间角度差别都不大,可是如果每天你都要走过86400个路口,最后又怎么可能分得清方向呢?

相信大多数电影迷第一次听到“蝴蝶效应”这个名词都是 侏罗纪公园 中。混沌数学家给女主角解释自己的专业时,用一滴水在她手上划过的不同轨迹给出了绝好的示例:因为震动,角度,皮肤瑕疵等等等等诸多的细节影响,造成了结果迥异。同样,一只蝴蝶扇动翅膀,对周围的空气产生了影响,而这一小团空气对气候造成的微量影响,又可能作为一个较大的气流活动的一部分,对更大范围的环境产生更明显的影响。。这种效应最终产生的结果已经无法预料,有可能是一次龙卷风,或是一次地震,一次海啸。。。这里的“蝴蝶”是一个符号,代表的是每一个造就龙卷风的细节。他的力量并不是来源于表面上体现的宿命性的特质,而是因为组成系统的细节太多,多到已经无法用数学建模的方式来预测、表达系统本身。的确,一次龙卷风的形成,和这只蝴蝶有关。但是实际上,他还和千千万万的蝴蝶关联在了一起。对于一次龙卷风来说,每只参与其中的蝴蝶都是必要条件,缺了其中任何一只或几只,风速、风向可能都会有微小差别,甚至会让龙卷风变成宜人的微风。可是反过来说,仅靠其中任何一只或几只,也都不可能产生完全相同的结果。所以,每天都有蝴蝶扇动翅膀,可是不见得德州天天有龙卷风产生;大多数的努力得到的只是平淡,而创造历史的往往也只是平淡的努力。butterfly effect表面上表达的是因果关系,可深层次上表现的是现实系统的复杂性。精确的长期天气预报在我们可以看到的未来无法实现的原因,也正是如此。虽然人类可以得到所有主要季风、洋流和气流的信息,但是那些隐藏细节,却无法一一捕获。即使捕获得到每一只蝴蝶的实时运动情况,也很难得知下一秒会有什么样的因素让蝴蝶如何运动,什么样的“蝴蝶”会让蝴蝶扇动翅膀。。。如果要刨根问底,面对的可能就是一个无限递归。

一个看似简单的系统尚且如此,何况是复杂的宇宙呢?“往古来今谓之宙,四方上下谓之宇”宇宙作为时间和空间的总称,虽然其中每一个元素都是可测的,但是综合起来以后,其复杂程度已经根本无法给之建模。所以从现实意义上说,对未来的预测永远只能是一个概率,而不可能是一个确数。一切事物的生命力也来源于这种不确定性。要说理想的随机数,也就莫过于此了。联想到Matrix漏洞百出的剧本中圈养人类的价值的解释,还是这个合理的多。

影片总体来说比较紧凑,情节吸引人,同时还有偶像派影星。虽然有不少漏洞(比如向Carlos证明神迹那段),但是主线不乱。唯一的问题是过于突出主角的悲剧性的宿命色彩。尤其是结尾,传达的信息似乎是没有Evan世界就不会疯狂。让人有一种Butterfly Effect等同于“butterfly造成恶果”这样的错觉。而实际上,butterfly既不会直接造成后果,而且这个后果的基调也和后果一样不可知。当然作为一部娱乐片,哲学的探讨始终只会是手段而非目的,也不能对他太过苛求。本片IMDB得分7.6,也算是相当高的得分了。



在下面的空白处点击一下。慎重选择落点,因为它会给你完全不同的未来。


This applet used with permission. Copyright 1996, James P. Crutchfield. All rights reserved.

Posted by: miles
Comments [0] |

vs.net开发初体验 [Permalink]

Wed Dec 29 20:47:02 CST 2004
Category [development. ~]

以前虽然也用过vs.net,但主要还是处于好奇进行的一些示例研究,关注点在于.net和java在架构上的异同点。这次有机会作一个win平台的standalone application,自然就想趁这个机会深入一下.net的开发细节。深入一用,细节的确是多。前两天基本上算是交学费了,有一半时间在google和msdn上。过了这个阶段效率就慢慢上去了。还好不算太久。 /images/emoticons/silly.gif

总体上来讲,vs.net的可视化开发支持还是要强于jbuilder。这也和.net本身特性有关。毕竟.net类库更庞大,顾及的层面也更丰富一些。而且本身和win平台结合紧密,所以做桌面程序要比java方便不少。就从我用过的DataGrid和JTable来说,功能孰强孰弱暂且不说,光看开发效率,用vs.net开发DataGrid是要比Jb开发JTable应用快不少。

语言层面,我用的是c#。总体感觉和java区别不大,不过更人性化一些,正如MS一贯的风格。目前java和.net的相互学习使得他们之间的差别在变小,比如

Long id=1l;
这样的boxing操作已经自jdk1.4开始支持,但是总体上说,无论从语言层面上,还是从环境设置、文件组织上,java给人的感觉还是严谨一些,而.net则更灵活和便捷。应该说两种方式各有利弊,还算不上核心竞争力。

vs.net可以直接制作windows installer安装包。如果安装了vs.net 2003 bootstraper plug-in的话,甚至可以将.net frameworks一起打包分发。这一点的确很是方便。不过.net frameworks 23MB的体积还是有点太大。如果能最小化的安装frameworks就更好了。

borland也有.net的产品线,我只是一年前观摩过c# builder。感觉上和vs.net的界面有点像似。按照borland的风格,应该还是会有一大堆borland自己开发的类库吧。。。等研究好了vs.net再看看他。

最后说一下ide本身的情况。jbX启动后一般要占用80MB左右的内存,使用中,如果内存不足,会逐步增加内存用量,有时候能达到200MB以上;而vs.net启动的动静相对要小很多,大约只要十几MB的内存,运行期也不过几十MB。效果上看,vs.net的确也要更顺畅一些,很少出现jb的那种除了最大化什么也作不成的情况。造成这种状况的原因应该和CLR在win平台的天生优势以及jb的纯java身份有关。这也从另一个角度说明了在win平台开发桌面程序,java对.net构不成威胁。实际上的应用程序运行体验也是如此,而且感觉相当明显。

Posted by: miles
Comments [0] |

去掉了service和data access层的类中所有的非static成员变量 [Permalink]

Wed Dec 22 19:09:54 CST 2004
Category [working on downwap.]

主要针对pageCount这个property。很多牵扯分页的类都有他。以前通过

String xml=service.getXxxByYyy();
int pageCount=service.getPageCount();
这样方式读取页数,而现在则是通过标准化返回的xml,让他本身包含pageCount这个ExtInfo。

这样一来,就可以大量应用singleton模式了。毕竟对于目前系统,频繁的new是不可忽视的性能瓶颈之一。

Posted by: miles
Comments [0] |

mail.jar无法释放 [Permalink]

Thu Dec 09 10:04:51 CST 2004
Category [trouble shooting]

环境:win2k+tomcat5.0.24 我的webapp用到了java mail api。按理说每次上传新的xxx.war以后,tomcat会先清除现有的xxx目录,然后展开新war。可是我这个应用却出了问题:web-inf/lib/mail.jar无法删除,提示占用(其他的jar、jsp已经全部删掉了)!只有shutdown tomcat才可以删除并重新deploy。。

释放java mail资源的地方只有
transport.close();
不过以前也是这样的,似乎并没有问题。

究竟怎么回事儿啊??去sun和google转了好大一圈,还是无解。。。

Posted by: miles
Comments [0] |

firefox和ie对于<input type=file>的不同处理 [Permalink]

Tue Dec 07 14:27:08 CST 2004
Category [trouble shooting]

传递过来的filename,IE会是全路径,而firefox则是文件名。因为这个前两天还搞出来一个bug。 其实按理说,后者更合理。因为对于server端,没有必要也没有权利得到客户端的文件完整路径信息。

Posted by: miles
Comments [0] |

关于servlet的线程模式 [Permalink]

Mon Nov 29 10:25:06 CST 2004
Category [working on downwap.]

昨天做refactoring时候差点犯错误。因为目前的设计,是所有servlet继承公共基类,而基类中进行一些例如错误处理之类的系统级操作(参看这里),所以两者都要用到request/response。以前的做法,是从基类传入request/response,而在子类中调用各个方法时候,也是统统传入。

本来这样做是没什么问题的,可是昨天却怎么看都不舒服。到处都是HttpServletRequest request HttpServletResponse response,看着都烦。结果可想而知:在基类中弄一个private HttpServletRequest requestprivate HttpServletResponse response,一进入主方法先就设置成员变量,以后就再也不用传递request/response了。

看上去完美了很多,可是仔细一想,如果这样能行,为什么容器还要传递这些玩意??一定有问题!!这时候突然想到了SingleThreadModal这个接口(真的是突然阿。。 /images/emoticons/plain.gif )。。恍然大悟。servlet是单实例多线程的,如果这样做,岂不是会有同步冲突??晕死。。联想到我的SessionListener:

public class SessionListener extends BaseListener implements 
HttpSessionListener, ServletRequestListener, Constant {

    private HttpServletRequest request;

    //Notification that a session was created
    public void sessionCreated(HttpSessionEvent se) {
        logger.debug("New session started!");
        setEquipmentInfo(se.getSession());
        clearAllAntiAttackRecs();
    }

    private void setEquipmentInfo(HttpSession session) {
        WebStringUtil webStringUtil=WebStringUtil.getInstance();
        String agent=webStringUtil.getUserAgent(request);

        String info=null;
        EquipmentService service=EquipmentServiceFactory.getService();
        try {
            info=service.getUserEquipmentByAgent(agent);
        } catch( DidyException ex) {
            logger.warn(ex.getMessage());
        }

        UserTracker userTracker=UserTracker.getInstance();
        userTracker.setEquipmentInfo(session, info);
    }

    //Notification that a session was invalidated
    public void sessionDestroyed(HttpSessionEvent se) {
        logger.debug("Session ended!");
    }

    private void clearAllAntiAttackRecs() {
        Map actAntiAttackRecs=BaseDidyServlet.getActAntiAttackRecs();
        Iterator it=actAntiAttackRecs.keySet().iterator();

        while(it.hasNext()) {
            clearAntiAttackRecs(actAntiAttackRecs, (String) it.next());
        }
    }

    private void clearAntiAttackRecs(Map actAntiAttackRecs, String ip) {
        NumberUtil numberUtil=NumberUtil.getInstance();
        Map ipAntiAttackMap=(Map) actAntiAttackRecs.get(ip);

        if(ipAntiAttackMap == null) {
            return;
        }

        Set obsoleteKeys=new HashSet();
        Iterator it=ipAntiAttackMap.keySet().iterator();
        while(it.hasNext()) {
            String key=it.next().toString();
            Map myIpActAntiAttackMap=(Map) ipAntiAttackMap.get(key);

            long lastActTime=
              numberUtil.getLong(myIpActAntiAttackMap.get("TIME"));
            long minInterval=
              numberUtil.getLong(
                AppProp.read(ANTI_ATTACK_PREFIX_INTERVAL + "." + key)
              );

            if(System.currentTimeMillis() - lastActTime >= minInterval) {
                obsoleteKeys.add(key);
            }
        }

        it=obsoleteKeys.iterator();
        while(it.hasNext()) {
            ipAntiAttackMap.remove(it.next());
        }

        if(ipAntiAttackMap.isEmpty()) {
            actAntiAttackRecs.remove(ip);
        }
    }

    /** The request is about to go out of scope of the web application. */
    public void requestDestroyed(ServletRequestEvent sre) {
    }

    /** The request is about to come into scope of the web application. */
    public void requestInitialized(ServletRequestEvent sre) {
        request=(HttpServletRequest) sre.getServletRequest();
    }
}
这里就麻烦大了!上网找了资料,还是没有找到合适的。不行的话只能试试看加一个overall的filter来为session listener取得request了。UGLY啊!!

Posted by: miles
Comments [0] |

xslt实现select distinct [Permalink]

Thu Nov 25 11:51:55 CST 2004
Category [working on downwap.]

今天做显示支持的手机列表时候遇到一个技术问题,就是select distinct。目前状况是,一次选出所有的equipment纪录,每条记录带有自己的brand(品牌)信息。选出纪录可能是这样格式:

<ROW>
  <ID>1</ID>
  <BRAND>NOKIA</BRAND>
  <MODEL>6100</MODEL>
</ROW>
<ROW>
  <ID>2</ID>
  <BRAND>NOKIA</BRAND>
  <MODEL>7250</MODEL>
</ROW>
<ROW>
  <ID>3</ID>
  <BRAND>NOKIA</BRAND>
  <MODEL>8210</MODEL>
</ROW>
<ROW>
  <ID>4</ID>
  <BRAND>MOTO</BRAND>
  <MODEL>E365</MODEL>
</ROW>
<ROW>
  <ID>5</ID>
  <BRAND>NOKIA</BRAND>
  <MODEL>V3</MODEL>
</ROW>
...
这样的数据,我们需要组织成:
  1. 主card只显示brand,并提供连接到每个brand的model列表card;
  2. model列表card有多个,对应不同品牌。每个card显示所有该品牌的model。
问题很明白,就是需要用distinct来分类组织,让数据从2d变3d。用xslt/xpath2.0或者EXSL.NET十分方便,本身就有distinct功能;但是用xslt/xpath1.0就不那么容易了。下面就是最终使用的xsl文件:
<?xml version="1.0" encoding="gb2312"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="wml" omit-xml-declaration="no" indent="no" 
      doctype-public="-//WAPFORUM//DTD WML 1.1//EN" 
      doctype-system="http://www.wapforum.org/DTD/wml_1.1.xml" />

  <xsl:include href="../common/common.func.xsl"/>
  <xsl:include href="../common/header.inc.xsl"/>
  <xsl:include href="../common/footer.inc.xsl"/>

  <xsl:variable name="pn" select="/ROOT/EXTINFO/PAGENO"/>

  <xsl:template match="/">
    <wml>
      <card>
        <xsl:call-template name="inc.header"/>
        <p>
          <xsl:for-each select="/ROOT/DATA/ROW">
            <xsl:variable name="thisEm" select="EM_ID"/>

            <xsl:if test="count(preceding-sibling::ROW)=0">
              <a>
              <xsl:attribute name="href">#<xsl:value-of select="EM_ID"/></xsl:attribute>
                <xsl:value-of select="BRAND"/></a><br/>
            </xsl:if>

            <xsl:if test="preceding-sibling::ROW[1]/EM_ID != $thisEm">
              <a>
              <xsl:attribute name="href">#<xsl:value-of select="EM_ID"/></xsl:attribute>
              <xsl:value-of select="BRAND"/></a><br/>
            </xsl:if>
          </xsl:for-each>
        </p>
        <xsl:call-template name="inc.footer"/>
      </card>

      <xsl:for-each select="/ROOT/DATA/ROW">
        <xsl:variable name="thisEm" select="EM_ID"/>
        <xsl:if test="count(preceding-sibling::ROW)=0">
          <card>
          <xsl:attribute name="id"><xsl:value-of select="EM_ID"/></xsl:attribute>
            <xsl:call-template name="inc.header"/>
            <p align="center">品牌[<xsl:value-of select="BRAND"/>]的支持机型</p>
            <p>
              <xsl:for-each select="../ROW[EM_ID=$thisEm]">
               型号:<xsl:value-of select="MODEL"/><br/>
               描述:<xsl:value-of select="DESCRIPTION"/><br/>
              </xsl:for-each>
            </p>
            <xsl:call-template name="inc.footer"/>
          </card>
        </xsl:if>

        <xsl:if test="preceding-sibling::ROW[1]/EM_ID != $thisEm">
          <card>
            <xsl:attribute name="id"><xsl:value-of select="EM_ID"/></xsl:attribute>
            <xsl:call-template name="inc.header"/>
            <p align="center">品牌[<xsl:value-of select="BRAND"/>]的支持机型</p>
            <p>
              <xsl:for-each select="../ROW[EM_ID=$thisEm]">
               型号:<xsl:value-of select="MODEL"/><br/>
               描述:<xsl:value-of select="DESCRIPTION"/><br/>
              </xsl:for-each>
            </p>
            <xsl:call-template name="inc.footer"/>
          </card>
        </xsl:if>
      </xsl:for-each>
    </wml>
  </xsl:template>

</xsl:stylesheet>
绕着弯子实现简单功能,是xslt一大特点。 enjoy /images/emoticons/plain.gif

Posted by: miles
Comments [0] |

关于指定资源下载的控制 [Permalink]

Thu Nov 25 00:33:32 CST 2004
Category [working on downwap.]

因为kjava要求文件格式的特殊性,最终设计决定采用如下方案:

  1. 所有的权限控制都由filter处理,这样可以最大限度保证灵活性。实现上,所有的资源都会过filter。实际控制上,对于wml页面,用/*.jwml /*.kwml /*.wml来区分不同状态用户所能访问的页面;对于servlet,则通过他们共同父类,来进行精确到动作的访问控制(参看下面那个关于糟糕的'AOP'的文章)。
  2. 对于客户端,kjava游戏需要的两个文件(*.jad和*.jar)将会在逻辑上处于一个目录下。比如:
    http://wap.didy.net/game/1.jad
    http://wap.didy.net/game/1.jar
    实现上,/game/*映射到一个servlet,通过path_info取得后面的/1.jar部分,然后在里面进行资源访问的逻辑细节,包括扣点,记录流水,以及读取指定资源,并用stream写到客户端。path_info是一个不错的东西,利用它可以作出灵活的应用。只要可以自由定制uri mapping的技术就能用它。当然,asp就做不到。

    这里有一个细节,就是为了提供高可维护性、灵活性和扩展性,jad和jar文件(文件名不限)存储时候,只需要放入一个zip文件,而且jad文件的MIDlet-Jar-URL字段也不需要绝对路径。具体下载时候,程序会寻找正确的zip,解压,并且处理后交给客户端。将来对于图片铃声也类似处理。这样控制力很强,可以实现防止盗链、给图片打戳等高级功能。

附上kjava的jad和jar文件contenttype(mimetype):
    private static final String CONTENT_TYPE_DOWN_JAD="text/vnd.sun.j2me.app-descriptor";
    private static final String CONTENT_TYPE_DOWN_JAR="application/java-archive";

Posted by: miles
Comments [0] |

?
四月 2024
Sun? Mon? Tue? Wed? Thu? Fri? Sat?
 123456
78910111213
14151617181920
21222324252627
282930    
       
<  Mar???Today??? May  >
<< <   1 2 3 4 5   > >>

Available categories: [/] [development. ~] [working on downwap.] [trouble shooting] [working on Yup Mailman] [general infomation.] [life style]

Powered By blojsom?? RSS Feed? RSS2 Feed? RDF Feed

html hits:?51263