That way I want to stay

BlogJava 首页 新随笔 联系 聚合 管理
  55 Posts :: 1 Stories :: 41 Comments :: 0 Trackbacks

#

here are four isolation levels:

  • READ UNCOMMITTED (在一个事务中,可能读到别的事务还没提交的数据)
  • READ COMMITTED(在一个事务中,同样的语句可能查询到不同的数据,因为在这两个语句之间,别的事务更改提交了这两个语句涉及的数据)
  • REPEATABLE READ(保证一个事务A里面读到的数据不会变,即使期间别的事务B提交更改了数据,事务A中的语句仍然会读到原来的数据)
  • SERIALIZABLE(在事务期间,会将涉及的数据锁掉,防止别的事务修改)

    SQL server实现了四个级别
    Oracle只实现中间两个级别。
     

  • 文章来源:http://blog.csdn.net/Wingel/archive/2006/11/26/1414835.aspx
    posted @ 2006-11-29 11:18 Wingel 阅读(76) | 评论 (0)编辑 收藏

    在一个Swing的项目中,每个控制用户操作的action都是用new出来的,所以还要手动set一些被spring管理的对象。
    后来实在受不了这些冗余的代码了,写代码的时候有时候又可能会把spring的对象跟非spring的对象顺序弄乱了,让代码结构不清晰,在spring2的介绍中,听说它连new出来的对象都可以管理,便去下了spring rc3来,布署到项目中。
      研究了半天,才发现其实是很容易的事,可怜我们看文档看了半天。
    1。虚拟机加个参数:-javaagent:lib/aspectjweaver.jar(后面是spring带的aspectjweaver.jar的路径)
    2。在spring配置文件里面加:    <aop:spring-configured/>
    3。在要被管理的类中加上annotation:@Configurable(autowire = Autowire.BY_TYPE) autowire应该不用说了。  
    文章来源:http://blog.csdn.net/Wingel/archive/2006/11/26/1414836.aspx
    posted @ 2006-11-29 11:18 Wingel 阅读(107) | 评论 (0)编辑 收藏

      我们一般项目中,都是把字典存到数据库中的。几个月前在做一个政府的项目中,觉得其实一些字典是跟开发工程紧密结合在一起的,也就是说字典变了,工程肯定也要变,这样子的字典如果也存到数据库中的话,也是多增加一些麻烦而已,后来但将这些字典写成枚举。然后数据库里面取的所谓的字典的key就是枚举的name,如:"unsubmited",而前台页面显示的,就是枚举的一个属性text,不过这里用到了webwork里面的ognl语法。

    /**
     * Author: Wingel
     * Date: 2006-7-29
     * Time: 15:17:52
     
    */

    public enum ApplicationState {
        unsubmited(
    "未提交"),submited("提交/待审批"),agreed("通过"),disagreed("未同意");
        
    private String text;

        ApplicationState(String text) 
    {
            
    this.text = text;
        }


        
    public static String getText(String name) {//给页面用的方法
            try {
                
    return valueOf(name).text;
            }
     catch (Exception e) {
                
    return null;
            }

        }


        
    public String getText() {
            
    return text;
        }


        
    public static boolean isValidRegisterType(String name) {
            
    try {
                valueOf(name);
                
    return true;
            }
     catch (Exception e) {
                
    return false;
            }

        }


        
    public static ApplicationState[] allState() {
            
    return ApplicationState.values();
        }


        
    public String getName() {
            
    return this.name();
        }

    }



     

    文章来源:http://blog.csdn.net/Wingel/archive/2006/11/26/1414837.aspx
    posted @ 2006-11-29 11:18 Wingel 阅读(201) | 评论 (0)编辑 收藏

      以前做完类似MonoRails的那个Java框架后,一直想把MonoRails里面那个Layout的功能也加到现在的开发框架里面,因为那框架确实是很有用啊。举个例子吧,以前做页面都是这样子做的,做一个head.jsp,一个foot.jsp,然后在每个页面里面这样子做:
    <jsp:include file="head.jsp">
    <.....页面代码>
    <jsp:include file="footer.jsp">

    而现在的设想就是,在每个action的方法上加一个annotation,Layout,layout就是框架页面的路径,比如:main.jsp
    然后在main.jsp里面:
    <页首的代码>
    <pageFrame:body>
    <页尾的代码>
    这样多省事啊。
    两个月前动手要加这个功能的时候,突然有人告诉我,你干嘛不用一下sitemesh,于是就去了解了一下sitemesh。

    后来放弃的原来的打算,还是用sitemesh吧。






     
    文章来源:http://blog.csdn.net/Wingel/archive/2006/11/26/1414838.aspx
    posted @ 2006-11-29 11:18 Wingel 阅读(128) | 评论 (0)编辑 收藏

        sitemesh的一个问题,在web.xml中设置filter的时候,让sitemesh可以过滤/*也就是所有的后缀名,但是在decorate.xml文件里面,并没有给sitemesh增加gif,jpg等后缀的pattern,结果在打开页面的时候,发现所有的图像文件都引用失败,用resin3的话,它会报错说error content length,而用resin2或者tomcat的时候,它连报错都没有。弄了半天,都不明白是怎么回事,后来才想到有可能是sitemesh的问题,修改的filter的设置,让它只过滤部分后缀名,结果就没事了。
     
    文章来源:http://blog.csdn.net/Wingel/archive/2006/11/26/1414840.aspx
    posted @ 2006-11-29 11:18 Wingel 阅读(109) | 评论 (0)编辑 收藏

    前几天同事讲了Transaction isolation level,并且大家一起在SQLServer,Oracle跟MySQL数据库上实验了一下,发觉这些知识还是挺重要的。
    假如有两个事务并发,顺序如下
    Transaction A            Transaction B
    begin    begin
    query1 from table A   
    .......                  modify1 to table A(insert/update/delete)
       commit
    query2 from table A
    commit

    那么在事务A中,query1跟query2查询出来的结果是否一样呢?这就跟事务隔离级别有关了。
    SQL的标准定义里面,一共有四种级别:
    read uncommited读取未提交的数据 就是其他事务求提交的数据,都可以读取出来
    read commited读取已提交的数据 query2会跟query1读取的数据不一样
    repeatable read可重复读取,即query1跟query2读取的数据是一样的
    serializable 序列化,

     SQL 标准用三个必须在并行的事务之间避免的现象定义了四个级别的事务隔离。 这些不希望发生的现象是:
    脏读(dirty reads)
        一个事务读取了另一个未提交的并行事务写的数据。
    不可重复读(non-repeatable reads)
        一个事务重新读取前面读取过的数据, 发现该数据已经被另一个已提交的事务修改过。
    幻读(phantom read)
        一个事务重新执行一个查询,返回一套符合查询条件的行, 发现这些行因为其他最近提交的事务而发生了改变。
     隔离级别         脏读(Dirty Read)  不可重复读(NonRepeatable Read)  幻读(Phantom Read)
    读未提交(Read uncommitted)   可能      可能                           可能
    读已提交(Read committed)     不可能           可能                        可能
    可重复读(Repeatable read)    不可能             不可能                    可能
    可串行化(Serializable )      不可能              不可能                  不可能

    SQLServer
    我们首先在SQLServer上做了实验,SQLServer一共支持四种隔离级别,read uncommited跟read commited我们没有实验,我们直接先实验
    repeatable read,如果事务A定义了如下级别,那么当事务B执行到modify1这条语句时,如果modify1是update的话,就被锁起来,一直等
    到事务A提交完以后,锁才会被释放,而如果是insert的话,刚可以顺利进行下去,然后在事务A中,query2查到的数据,是已经被事务B
    修改过的数据,如果将级别定义在serializable的话,则在modify1语句中,update,insert或者delete都会被锁掉。
    也就是说,SQLServer对这些级别的支持,是通过锁来做到的,虽然可以保证事务正常进行,但是并行的性能却很差。
    Oracle
    oracle只支持两个级别,read commited跟serializable,结果这里就不用详细说明,实验的结果是,oracle的serializable是通过版本
    控制来完成的,而不是通过锁机制,这就保证了并行的性能。Oracle的默认级别是read commited
    MySQL
    MySQLServer也支持四个级别,而且MySQL也是通过版本控制而非锁机制来完成的。
     


    文章来源:http://blog.csdn.net/Wingel/archive/2006/11/26/1414839.aspx
    posted @ 2006-11-29 11:18 Wingel 阅读(184) | 评论 (0)编辑 收藏

    想搭建一个框架是使用AJAX的,首先考虑到的就是Google web toolkit,看了一下它的文档,就是将所有的dom元素封装成Java对象了,写起代码来,因为有IDE的帮助,而且凭着静态语法的特点,出错的机率就小了。但是有这样一个问题,比如说想给页面上随便增加一点东西的话,却不能随便编辑html文件,因为GWT生成的代码并不是那么好读,也就是说,每次要修改一下页面,就要重新再编译一下Java代码。这点可不好。后来就改用YUI了,YUI的example 倒是非常的丰富,但用了总感觉不舒服,后面想想,才明白是因为它的api设计得不好调用,代码不能写得很简洁。没得说,又去试了一下dojo了,感觉是简洁得多了,api用了感觉挺舒服的。写页面的时候,想用一下prototype的$,之前还以为dojo是基于prototype写成的,结果试了半天,才发现并不是这样,正巧又在网上看了一篇介绍jQuery的,试了一下,就迷上它了,然后就把dojo从项目中移走了。
      仔细回想了这四个框架,想想自己为什么会选中jQuery。才发现,因为jQuery的源代码是最简洁的,结构上也是最容易全部掌握了,写JavaScript代码的时候,总是希望所有的代码都是在自己的手里面控制的,这种想法,跟一年前的想法一模一样,当时AJAX刚火的时候,也想去试一些开源的框架,但用了一段时间以后,就放弃了,全部使用了自己设计的框架,因为框架掌握在自己手里面,舒坦。
      JavaScript库丰富固然好,但是越丰富,自己就越不了解全部层次,内心就越不安。不懂这是不是大多数人的通病。可是仔细想想,为什么Java的开源库用得这么自在,为什么JavaScript的就自在不起来呢。 
    文章来源:http://blog.csdn.net/Wingel/archive/2006/11/26/1414843.aspx
    posted @ 2006-11-29 11:18 Wingel 阅读(105) | 评论 (0)编辑 收藏

    用jquery碰到的问题
    文章来源:http://blog.csdn.net/Wingel/archive/2006/11/26/1414850.aspx
    posted @ 2006-11-29 11:18 Wingel 阅读(110) | 评论 (0)编辑 收藏

    上回碰到一个项目要求是要求写一个桌面程序,而这个程序的要求是越少占用资源越好,越小越好。
    虽然最近一直在写swing的程序,但Java肯定是不能用了,因为还怎么打包都要8M以上;.net的winform也是不能用了,;就只剩三个选择了,Delphi,VB跟MFC,MFC实在是不想用,就先试了下用VB写,正在写得很不爽的时候,在某个地方查到VB还要拷一些dll文件才能正常运行,于是就只剩下Delphi,后来终于在很痛苦的情况下,把程序完成了,唉,好的IDE用习惯了,对它的依赖也变得很多。(没错,我这里就是在暗示Delphi这个IDE真TMD太差了)
      后来才听说了,C++有个库,叫QT,写桌面程序非常的不错,还很像swing。呜!真TMD的知道得太迟了,还被折磨了很久,查了暴多的资料。 
    文章来源:http://blog.csdn.net/Wingel/archive/2006/11/26/1414851.aspx
    posted @ 2006-11-29 11:18 Wingel 阅读(91) | 评论 (0)编辑 收藏

      其实这种事情都会有两个观点。
    一个观点是:建议使用自己熟悉的技术,采用简单的架构去实现项目,等到你把项目做出来了,能用起来了,客户认可了。以后的升级,那是你就可以比较轻松的采用其 它的架构来重构,这样你的风险,压力就相对减少很多了。
    而这回,我想顶一下第二个观点:  
      其实如果你对代码要求比较严格的话,你就会经常发现,你的代码有很多东西可以抽取出来,或者做在公共的模块,或者作为框架的底层,我们就简单的拿jdbc来说吧,
        首先,是connection的管理,这点一般用jdbc熟一些的话,都会有管理connection的公共模块,虽然偶尔会碰到性能的问题,但是这点我们暂且压下不表。
        我们查询的时候,每次都要用
        rs.get...("name"),
        rs.get...("id"),
        rs.get...("age"),
        rs.get...("gender"),
        rs.get...("hobby"),
        然后修改数据库的时候,还要拼写update语句跟insert语句,经常还要费很多时间来调试这些多余代码的问题,这时候你就想,不行,我一定要写一个公共模块,省得让我每次都要定这么多代码,于是你的第一个公共模块产生了,然后测试啊测试,改进啊改进,叮叮响,过了几天时间的考验,这个公共模块终于可以放心使用了,项目进度开始快一些了,总算不用再拼SQL了。
       
        后来在做统计模块的时候,突然又发现,之前在用到的一些SQL函数,好像在客户要求的数据库上不怎么行啊,于是又去查了一下资料,又过了几天(可能这次不用几天),然后终于放心,所有的函数都正常了。
       
        接着又不可避免的碰到了分页的问题,你对自己说,不用怕,我上回就写了一个分页的,没有问题!可是Ya的你突然发现,上回的那个分页是用游标实现的,这回客户是要求用SQLServer,唉,SQLServer的游标,不提也罢,想来想去,只好自己拼SQL语句来写分页了,又是count又是top,测了又测之后,又过了几天,啊哈,终于分页的公共模块也做好的,可以放心使用了,好,项目的进度又可以加快了。

        做着做着的时候,发现,咦,好像这表得增加一个字段才行,增加了,然后所有查询的SQL语句加一下,所有insert跟update的代码修改一下,页面修改一下,嗯,现在应该正常了,看起来倒是没什么问题,咦,报表好像不怎么对啊,靠,这边还有调用这个表的代码,妈的,改吧改吧。磨蹭了好几个小时(当然,熟练的话,并不用几个小时),总算看起来都正常了。

        这一回,这个功能中有一次用户请求,访问了好几次数据库,不行,这里应该用个cache,否则性能上会有问题啊,算了,用算法解决一下,尽量少访问数据库好了,我对cache还不熟呢。(写啊写啊,Batch Size,这样多,那样多,Fetch Size。。。,终于,看起来正常一些了)。过了一段时间,靠,这边又要访问好几次数据库,Ya的受不鸟了,性能爱咋的咋的,反正一个地方慢又不要紧。Oh shit!!!这边也是好几次,这边又是好几次,那边又是好几次。不行了,我老老实实写个cache支持吧,于是又叮叮当当了好几天,终于,有个粗糙的cache出来了,终于速度可以看一些了。后来改进又改进,测试又测试,累死了,老子好不爽啊。

        好像天下有点太平了,啊,你说我这个地方忘记更新你增加的那个子表啊,算了,没关系,我明天看一下代码,这个容易解决点。嗯,我改了那边的代码了,会更新子表信息了。什么?你说取主表的记录跟相应的子表记录列表麻烦啊,没关系,我更新一下处理resultset的公共模块,明天再说。
        Oh shit......对这样子复杂的查询好像现在的公共模块支持不了啊,算了,这样子的查询不要用这个公共模块,我们手动写一些代码好啊,别跟我讲这样代码结构很难看,你以为我不知道啊,TMD。

        TMD的,怎么这边的SQL老是运行不了啊,不会是分页底层模块的问题吧,靠,怎么你的SQL语句有这么多order,group by,靠,还有top啊,这当然过不了了,不要吵了,现在时间改,不理它,直接用个假分页就行了。你又说代码结构难看,小心我抽你哦。

        公司新来一个程序员,看了几天代码,不停的抱怨说,这代码写得真差啊。。。。。。 


    文章来源:http://blog.csdn.net/Wingel/archive/2006/11/26/1414852.aspx
    posted @ 2006-11-29 11:18 Wingel 阅读(87) | 评论 (0)编辑 收藏

    目前jQuery网站上已经有了From的验证框架,FromValidation,但是一直觉得它的框架并不好用,因为重复写的东西太多了。
    于是就再次写了自己的JavaScript验证框架,完全废弃掉以前的。
    在新的框架下,是以这样子的用法设计的:
    首先,要包括自己的js文件(这点不必说),而且在包括自己写,要先包括jQuery的,如下

    <link rel="stylesheet" type="text/css" href="<ww:url value="/layout/css/style.css"/>">
    <link rel="stylesheet" type="text/css" href="<ww:url value="/layout/css/thickbox.css"/>" media="screen">
    <script type="text/javascript" src="<ww:url value="/layout/js/jquery-latest.js"/>"></script>
    <script type="text/javascript" src="<ww:url value="/layout/js/thickbox.js"/>"></script>
    <script type="text/javascript" src="<ww:url value="/layout/js/wingel.js"/>"></script>
    <decorator:head/>


    然后在要验证的Form里面加个属性validatable=true,如下:

    <form id="registerForm" action="user-register.action" validatable="true">

    注意,这边不要加onsubmit方法

    接下来,就好了,比如说有个输入框:
    <ww:textfield name="name" id="name"/>
    我想验证,让它必填,如下就可以了:
    <label for="name" validate="required">请填写名称</label>  其中 for属性里面填的要是验证的输入框id,validate填的是验证方法,;label里面的文本就是验证不过的时候要显示的信息。
    如果我想验证一个输入框的输入值长度怎么办,这样子就行了

    <label for="password" validate="lengthRange:6;20">

    后面的参数用;号隔开,验证的方法名跟参数用: 隔开。
    wingel.js里面已经包括了一些常用的验证方法,现在问题来了,如果要自定义验证方法怎么办,如下办:
    比如你想加个验证方法是hello
    则label里面的validate属性写成hello,
    然后加一个JavaScript方法:

    <script type="text/javascript">
        wingel.validator.rules.hello
    = function(value, element, parameters,utility) {
                 ...    }

    </script>


    里面三个参数,shit , couldn't input Chinese. now English will be used.

    The first parameter is the value of the input element you want to validate,the second one is the validated element, the third one, is the parameters you add in validate label, the last one, is a utility class, you can invoke its method to make your code easier.






     
    文章来源:http://blog.csdn.net/Wingel/archive/2006/11/26/1414856.aspx
    posted @ 2006-11-29 11:18 Wingel 阅读(257) | 评论 (0)编辑 收藏

    完整书籍
    http://www.blogjava.net/Files/Wingel/第4章 保持代码简洁.rar

    第4章 保持代码简洁

    第4章  保持代码简洁

        
    示例

        这是一个会议管理系统。它用来管理所有参会者的信息。刚开始的时候,我们只需要记录每个参会者的ID(这是会议组织者分配的),姓名,电话和地址就行。于是,我们写了如下的代码:
       
        class Participant {                                                                           
           String id;                                                                                 
           String name;                                                                               
           String telNo;                                                                              
           String address;                                                                            
        }   
       
        class ConferenceSystem {                                                                      
           Participant participants[];                                                                
        }                                                                                             

        接着,新的需求来了:现在每个参会者都可以让组织者帮忙预订酒店,所以我们要记录下他想预订的酒店名,入住日期,离开日期,房间类型(单人房或者双人房)。于是我们又扩充成如下的代码:   

        class Participant {                                                                           
           String id;                                                                                 
           String name;                                                                               
           String telNo;                                                                              
           String address;                                                                            
           boolean bookHotelForHim;                                                                   
           String hotelName;                                                                          
           Date checkInDate;                                                                          
           Date checkOutDate;                                                                         
           boolean isSingleRoom;                                                                      
           void setHotelBooking(String hotelName, Date checkInDate, ...) {                            
               ...                                                                                    
           }                                                                                          
        }                                                                                             

        接着,又有一个新的需求来了:参会者可以参加不同的研讨会,所以我们要记录下参会者参加的研讨会。对于他要参加的每一场研讨会,我们还要记录下他的登记时间,同时他还需要什么翻译设备。于是代码又扩充成:

    具体的内容在上面的下载链接里面的pdf文件里。

    完整书籍
    http://www.blogjava.net/Files/Wingel/%E7%AC%AC4%E7%AB%A0%E4%BF%9D%E6%8C%81%E4%BB%A3%E7%A0%81%E7%AE%80%E6%B4%81.rar
    posted @ 2006-11-28 20:51 Wingel 阅读(1302) | 评论 (7)编辑 收藏

      http://www.blogjava.net/Files/Wingel/第3章%20除去代码异味.rar
                    第3章 除去代码异味 


        异味这个词,可能有点抽象,我们先看一下下面的例子

        这是一个CAD系统. 现在,它已经可以画三种形状了:线条,长方形,跟圆.
    先认真的看一下下面的代码:

        class Shape {                                                                                  
           final static int TYPELINE = 0;                                                              
           final static int TYPERECTANGLE = 1;                                                         
           final static int TYPECIRCLE = 2;                                                            
           int shapeType;                                                                              
           //线条的开始点
           //长方形左下角的点
           //圆心
           Point p1;                                                                                   
           //线条的结束点
           //长方形的右上角的点
           //如果是圆的话,这个属性不用
           Point p2;                                                                                   
           int radius;                                                                                 
        }                                                                                              
        class CADApp {                                                                                 
           void drawShapes(Graphics graphics, Shape shapes[]) {                                        
               for (int i = 0; i < shapes.length; i++) {                                               
                   switch (shapes[i].getType()) {                                                      
                      case Shape.TYPELINE:                                                             
                          graphics.drawLine(shapes[i].getP1(), shapes[i].getP2());                     
                          break;                                                                       
                      case Shape.TYPERECTANGLE:                                                        
                          //画四条边
                          graphics.drawLine(...);                                                      
                          graphics.drawLine(...);                                                      
                          graphics.drawLine(...);                                                      
                          graphics.drawLine(...);                                                      
                          break;                                                                       
                      case Shape.TYPECIRCLE:                                                           
                          graphics.drawCircle(shapes[i].getP1(), shapes[i].getRadius());               
                          break;                                                                       
                   }                                                                                   
               }                                                                                       
           }                                                                                           
        }                                                                                              


        代码都是一直在改变的,而这也是上面的代码会碰到的一个问题.

        现在我们有一个问题: 如果我们需要支持更多的形状(比如三角形), 那么肯定要改动Shape这个类, CADApp里面的drawShapes这个方法也要改.
    好,改为如下的样子:
      
    ......


        如果我们想要支持更多的图形(比如:三角形),上面没有一个类需要修改。我们只需要创建一个新的类Triangle就行了。

    具体的内容在上面的下载链接里面的pdf文件里,看pdf比较舒服。

    http://www.blogjava.net/Files/Wingel/第3章%20除去代码异味.rar
    posted @ 2006-11-27 21:23 Wingel 阅读(1984) | 评论 (3)编辑 收藏

      http://www.blogjava.net/Files/Wingel/敏捷开发的必要技巧第1,2章.rar                                                                                                                   
                    第1章 移除重复代码
                                                                                   
    重复代码是怎么产生的?

    请观察下面的代码,我们已经有一个根据出租记录的id取出租用客户的姓名的方法:getCustomerName。

        public class BookRental { //该类描述出租记录
            String id;
            String customerName;

            ...

        }
        public class BookRentals {
           private Vector rentals;
           public String getCustomerName(String rentalId) { 根据出租id取出客户姓名
               for (int i = 0; i < rentals.size(); i++) {
                  BookRental rental = (BookRental) rentals.elementAt(i);
                  if (rental.getId().equals(rentalId)) {
                      return rental.getCustomerName();
                   }
               }
               throw new RentalNotFoundException();
            }
        }
        public class RentalNotFoundException extends Exception {

            ...

        }

    假定现在你要增加一个新的方法,该方法是根据出租记录的id删除该记录,然后把它命名为deleteRental(String rentalId)。现在你已经考虑到,就像getCustomerName这个方法一样,你要一个一个遍历出租记录。所以你就将getCustomerName这个方法里面的一些代码拷出来,然后稍微修改一下:

      
    .....


    为什么我们要移除重复代码?

    我来向各位程序员同学稍微说一下,在BookRentals这个类中,rentals这个属性的类型是Ventor,如果我们需要将它改为数组,那我们就必须将所有的"rentals.size()"改为"rentals.length". 在重构以后的版本中,我们只需要在getRentalIdxById这个方法中修改一次,而在原来的版本,我们就得在getCustomerName跟deleteRental两个方法中都改一次。类似的,我们还要将所有的"rentals.elementAt(i)" 改为 "rentals[i]". 又是改一次跟改两次的比较!

    大多数情况中,如果类似这样的代码在10个地方重复,当我们修改代码的时候,就要修改10个地方,我们并不能保证能把这10个地方都记住了,而一旦漏掉了几个地方,等待我们的,是一处一处的错误去修复。而最致命的是,当我们修改的是业务逻辑时,这时候,不管我们漏掉了几个地方,IDE都不会报错,那么,等待我们的,将一堆去检查,而造成的一些bug中,很可能是短时间内还发现不了了.惨-_-!!

    具体的内容在上面的下载链接里面的pdf文件里,看pdf比较舒服。

    http://www.blogjava.net/Files/Wingel/敏捷开发的必要技巧第1,2章.rar
    posted @ 2006-11-27 21:22 Wingel 阅读(1938) | 评论 (0)编辑 收藏

    仅列出标题
    共2页: 上一页 1 2