勇智's profileIT民工的日记PhotosBlogLists Tools Help

Blog


    23 April

    一个有用的CSS属性: ime-mode

    ime-mode 是 CSS2 标准. 我只在IE6中测试过, 可以使用.
    这个属性取值如果是: disabled 则会在可输入的模式下(input type=text, textarea元素等)禁用输入法.
     
    当编辑框中需要输入非中文字符时, 可以用此属性限制激活输入法,这样用户的输入就不会受输入法影响.
     
    此属性是在注册hotmail 邮箱时,看其表单源码发现的.
     
     
    另还有一发现,  当 keypress 事件激发时, 可以通过修改 event.keyCode 的值来修改最终的输出,比如你想把所有的字母都转换成大写, 可以用这个方式. 另外, keypress 事件若返回 false 值, 则字符不会输出到编辑框中.
     
     
    15 December

    Java/J2EE 应用程序事务处理入门

    原文标题叫(DAO编程模式) 但事实上讲得更多的是细节--事务处理
     
    J2EE开发人员使用数据访问对象(DAO)设计模式把底层的数据访问逻辑和高层的商务逻辑分开.实现DAO模式能够更加专注于编写数据访问代码.在这篇文章中,Java开发人员Sean C. Sullivan从三个方面讨论DAO编程的结构特征:事务划分,异常处理,日志记录.

    在最近的18个月,我和一个优秀的软件开发团队一起工作,开发定制基于WEB的供应链管理应用程序.我们的应用程序访问广泛的持久层数据,包括出货状态,供应链制度,库存,货物发运,项目管理数据,和用户属性等.我们使用JDBC API连接我们公司的各种数据库平台,并且在整个应用程序中应用了DAO设计模式.
    下图显示了应用程序和数据源的关系:
     

    通过在整个应用程序中应用数据访问对象(DAO)设计模式使我们能够把底层的数据访问逻辑和上层的商务逻辑分开.我们为每个数据源创建了提供CRUD(创建,读取,更新,删除)操作的DAO类.

    在之篇文章中,我将向你介绍DAO的实现策略以及创建更好的DAO类的技术.我会明确的介绍日志记录,异常处理,和事务划分三项技术.你将学在你的DAO类中怎样把这三种技术结合在一起.这篇文章假设你熟悉JDBC API,SQL和关系性数据库编程.

    我们先来回顾一下DAO设计模式和数据访问对象.
    DAO基础
    DAO模式是标准的J2EE设计模式之一.开发人员使用这个模式把底层的数据访问操作和上层的商务逻辑分开.一个典型的DAO实现有下列几个组件:
    1.    一个DAO工厂类;
    2.    一个DAO接口;
    3.    一个实现DAO接口的具体类;
    4.    数据传递对象(有些时候叫做值对象).

    具体的DAO类包含了从特定的数据源访问数据的逻辑。在下面的这段中你将学到设计和实现数据访问对象的技术。
    事务划分:
    关于DAO要记住的一件重要事情是它们是事务性对象。每个被DAO执行的操作(象创建,更新、或删除数据)都是和事务相关联的。同样的,事务划分(transaction demarcation)的概念是特别重要的。
    事务划分是在事务界定定义中的方式。J2EE规范为事务划分描述了两种模式:编程性事务(programmatic)和声明性事务(declarative).下表是对这两种模式的拆分:
    声明性事务划分    编程性事务划分
    程序员使用EJB的布署描述符声明事务属性    程序员担负编写事务逻辑代码的责任。
    运行时环境(EJB容器)使用这些属性来自动的管理事务。    应用程序通过一个API接口来控制事务。 

    我将把注意力集中的编程性事务划分上。
    象前面的介绍一样,DAOs是一些事务对象。一个典型的DAO要执行象创建、更新、和删除这的事务性操作。在设计一个DAO时,首先要问自己如下问题:
    1、    事务将怎样开始?
    2、    事务将怎样结束?
    3、    那个对象将承担起动一个事务的责任?
    4、    那个对象将承担结束一个事务的责任?
    5、    DAO应该承担起动和结束事务的责任?
    6、    应用程序需要交叉访问多个DAO吗?
    7、    一个事务包含一个DAO还是多个DAO?
    8、    一个DAO包含其它的DAO中的方法吗?

    回答这些问题将有助于你为DAO对象选择最好的事务划分策略。对ADO中的事务划分有两个主要的策略。一种方法是使用DAO承担事务划分的责任;另一种是延期性事务,它把事务划分到调用DAO对象的方法中。如果你选择前者,你将要在DAO类中嵌入事务代码。如果你选择后者,事务代码将被写在DAO类的外部。我们将使用简单的代码实例来更好的理解这两种方法是怎样工作的。
    实例1展示了一个带有两种数据操作的DAO:创建(create)和更新(update):
    public void createWarehouseProfile(WHProfile profile);
    public void updateWarehouseStatus(WHIdentifier id, StatusInfo status);
    实例2展示了一个简单的事务,事务划分代码是在DAO类的外部。注意:在这个例子中的调用者把多个DOA操作组合到这个事务中。

    tx.begin();    // start the transaction
    dao.createWarehouseProfile(profile);
    dao.updateWarehouseStatus(id1, status1);
    dao.updateWarehouseStatus(id2, status2);
    tx.commit();   // end the transaction

    这种事务事务划分策略对在一个单一事务中访问多个DAO的应用程序来说尤为重要。

    你即可使用JDBC API也可以使用Java 事务API(JTA)来实现事务的划分。JDBC事务划分比JTA事务划分简单,但是JTA提供了更好的灵活性。在下面的这段中,我们会进一步的看事务划分机制。
    使用JDBC的事务划分
    JDBC事务是使用Connection对象来控制的。JDBC的连接接口(java.sql.Connection)提供了两种事务模式:自动提交和手动提交。Java.sql.Connection为控制事务提供了下列方法:
    .public void setAutoCommit(Boolean)
    .public Boolean getAutoCommit()
    .public void commit()
    .public void rollback()
    实例3展示怎样使用JDBC API来划分事务:
    import java.sql.*;
    import javax.sql.*;
    // ...
    DataSource ds = obtainDataSource();
    Connection conn = ds.getConnection();
    conn.setAutoCommit(false);
    // ...
    pstmt = conn.prepareStatement("UPDATE MOVIES ...");
    pstmt.setString(1, "The Great Escape");
    pstmt.executeUpdate();
    // ...
    conn.commit();
    // ...

    使用JDBC事务划分,你能够把多个SQL语句组合到一个单一事务中。JDBC事务的缺点之一就是事务范围被限定在一个单一的数据库连接中。一个JDBC事务不能够跨越多个数据库。接下来,我们会看到怎样使用JTA来做事务划分的。因为JTA不象JDBC那样被广泛的了解,所以我首先概要的介绍一下JTA。

    JTA概要介绍
    Java事务API(JTA Java Transaction API)和它的同胞Java事务服务(JTS Java Transaction Service),为J2EE平台提供了分布式事务服务。一个分布式事务(distributed transaction)包括一个事务管理器(transaction manager)和一个或多个资源管理器(resource manager)。一个资源管理器(resource manager)是任意类型的持久化数据存储。事务管理器(transaction manager)承担着所有事务参与单元者的相互通讯的责任。下车站显示了事务管理器和资源管理的间的关系。
     

    JTA事务比JDBC事务更强大。一个JTA事务可以有多个参与者,而一个JDBC事务则被限定在一个单一的数据库连接。下列任一个Java平台的组件都可以参与到一个JTA事务中:
    .JDBC连接
    .JDO PersistenceManager 对象
    .JMS 队列
    .JMS 主题
    .企业JavaBeans(EJB)
    .一个用J2EE Connector Architecture 规范编译的资源分配器。

    使用JTA的事务划分
    要用JTA来划分一个事务,应用程序调用javax.transaction.UserTransaction接口中的方法。示例4显示了一个典型的JNDI搜索的UseTransaction对象。
    import javax.transaction.*;
    import javax.naming.*;
    // ...
    InitialContext ctx = new InitialContext();
    Object txObj = ctx.lookup("java:comp/UserTransaction");
    UserTransaction utx = (UserTransaction) txObj;

    应用程序有了UserTransaction对象的引用之后,就可以象示例5那样来起动事务。

    utx.begin();
    // ...
    DataSource ds = obtainXADataSource();
    Connection conn = ds.getConnection();
    pstmt = conn.prepareStatement("UPDATE MOVIES ...");
    pstmt.setString(1, "Spinal Tap");
    pstmt.executeUpdate();
    // ...
    utx.commit();
    // ...

    当应用程序调用commit()时,事务管理器使用两段提交协议来结束事务。
    JTA事务控制的方法
    .javax.transaction.UserTransaction接口提供了下列事务控制方法:
    .public void begin()
    .public void commit()
    .public void rollback()
    .public void getStatus()
    .public void setRollbackOnly()
    .public void setTransactionTimeout(int)
    应用程序调用begin()来起动事务,即可调用commit()也可以调用rollback()来结束事务。
    使用JTA和JDBC
    开发人员经常使用JDBC来作为DAO类中的底层数据操作。如果计划使用JTA来划分事务,你将需要一个实现了javax.sql.XADataSource,javax.sql.XAConnection和javax.sql.XAResource接口JDBC的驱动。实现了这些接口的驱动将有能力参与到JTA事务中。一个XADataSource对象是一个XAConnection对象的工厂。XAConnections是参与到JTA事务中的连接。

    你需要使用应用程序服务器管理工具来建立XADataSource对象。对于特殊的指令请参考应用程序服务器文档和JDBC驱动文档。

    J2EE应用程序使用JNDI来查找数据源。一旦应用程序有了一个数据源对象的引用,这会调用javax.sql.DataSource.getConnection()来获得数据库的连接。

    XA连接区别于非XA连接。要记住的是XA连接是一个JTA事务中的参与者。这就意味着XA连接不支持JDBC的自动提交特性。也就是说应用程序不必在XA连接上调用java.sql.Connection.commit()或java.sql.Connection.rollback()。相反,应用程序应该使用UserTransaction.begin()、UserTransaction.commit()和UserTransaction.rollback().

    选择最好的方法
    我们已经讨论了JDBC和JTA是怎样划分事务的。每一种方法都有它的优点,回此你需要决定为你的应用程序选择一个最适应的方法。

    在我们团队许多最近的对于事务划分的项目中使用JDBC API来创建DAO类。这DAO类总结如下:
    .事务划分代码被嵌入到DAO类内部
    .DAO类使用JDBC API来进行事务划分
    .调用者没有划分事务的方法
    .事务范围被限定在一个单一的JDBC连接

    JDBC事务对复杂的企业应用程序不总是有效的。如果你的事务将跨越多个DAO对象或
    多个数据库,那么下面的实现策略可能会更恰当。:
    .用JTA对事务进行划分
    .事务划分代码被DAO分开
    .调用者承担划分事务的责任
    .DAO参与一个全局的事务中

    JDBC方法由于它的简易性而具有吸引力,JTA方法提供了更多灵活性。你选择什么样的实现将依赖于你的应用程序的特定需求。

    日志记录和DAO
    一个好的DAO实现类将使用日志记录来捕获有关它在运行时的行为细节。你可以选择记录异常、配置信息、连接状态、JDBC驱动程序的元数据或查询参数。日志对开发整个阶段都是有益的。我经常检查应用程序在开发期间、测试期间和产品中的日志记录。
    在这段中,我们将展现一段如何把Jakarta Commaons Logging结合中一个DAO中的例子。在我们开始之前,让我们先回顾一些基础知识。

    选择一个日志例库
    许多开发人员使用的基本日志形式是:System.out.println和System.err.println.Println语句。这种形式快捷方便,但它们不能提供一个完整的日志系统的的能力。下表列出了Java平台的日志类库:
    日志类库    开源吗?    URL
    Java.util.logging    否    http://java.sun.com/j2ee

    Jakarta Log4j    是    http://hajarta.apache.org/log4j/
    Jakarta Commons Logging    是    http:/Jakarta.apache.org/commons/logging.html

    Java.util.logging是J2SE1.4平台上的标准的API。但是,大多数开发人员都认为Jakarta Log4j提供了更大的功能性和灵活性。Log4j超越java.util.logging的优点之一就是它支持J2SE1.3和J2SE1.4平台。

    Jakarta Commons Logging能够被用于和java.util.loggin或Jakarta Log4j一起工作。Commons Logging是一个把你的应用程序独立于日志实现的提取层。使用Commons Logging你能够通过改变一个配置文件来与下面的日志实现来交换数据。Commons Logging被用于JAKARTA Struts1.1和Jakarta HttpClient2.0中。

    一个日志示例
    示例7显示了在一个DOA类中怎样使用Jakarta Commons Logging

    import org.apache.commons.logging.*;
    class DocumentDAOImpl implements DocumentDAO
    {
          static private final Log log = LogFactory.getLog(DocumentDAOImpl.class);
          public void deleteDocument(String id)
          {
              // ...
              log.debug("deleting document: " + id);
              // ...
              try
              {
                  // ... data operations ...
              }
              catch (SomeException ex)
              {
                  log.error("Unable to delete document", ex);
                  // ... handle the exception ...
      }
          }
    }

    日志是评估应用程序的基本部分。如果你在一个DAO中遇到了失败,日志经常会为理解发生的什么错误提供最好的信息。把日志结合到你的DAO中,确保得到调试和解决问题的有效手段。

    DAO中的异常处理
    我们已经看了事务划分和日志记录,并且现在对于它们是怎样应用于数据访问对象的有一个深入的理解。我们第三部分也是最后要讨论的是异常处理。下面的一些简单的异常处理方针使用你的DAO更容易使用,更加健壮和更具有可维护性。

    在实现DAO模式的时候,要考滤下面的问题:
    .在DAO的public接口中的方法将抛出被检查的异常吗?
    .如果是,将抛出什么样的检查性异常?
    .在DAO实现类中怎能样处理异常。
    在用DAO模式工作的过程中,我们的团队为异常处理开发了一组方针。下面的这些方针会很大程度的改善你的DAO:
    .DAO方法应该抛出有意义的异常。
    .DAO方法不应该抛出java.lang.Exception异常。因为java.lang.Exception太一般化,它不能包含有关潜在问题的所有信息。
    .DAO方法不应该抛出java.sql.SQLException异常。SQLException是一个底层的JDBC异常,DAO应用努力封装JDBC异常而不应该把JDBC异常留给应用程序的其它部分。
    .在DAO接口中的方法应该只抛出调用者期望处理的检查性异常。如果调用者不能用适当的方法来处理异常,考滤抛出不检查性(运行时run-time)异常。

    .如果你的数据访问代码捕获了一个异常,不可要忽略它。忽略捕获异常的DAO是很处理的。
    .使用异常链把底层的异常传递给高层的某个处理器。
    .考滤定义一个标准的DAO异常类。Spring框架提供了一个优秀的预定义的DAO异常类的集合。
    看Resources,查看有异常和异常处理技术的更详细信息。

    实现示例:MovieDAO
    MoveDAO是一个示范了在这篇文章中所讨论的所有技术,包括事务划分、日志记录和异常处理。你会在Resources段找到MovieDAO的源代码。它被分下面的三个包:
    .daoexamples.exception
    .daoexamples.move
    .daoexamples.moviedemo

    这个DAO模式的实现由下面的类和接口组成:
    .daoexamples.movie.MovieDAOFactory
    .daoexamples.movie.MovieDAO
    .daoexamples.movie.MovieDAOImpl
    .daoexamples.movie.MovieDAOImplJTA
    .daoexamples.movie.Movie
    .daoexamples.movie.MovieImple
    .daoexamples.movie.MovieNotFoundException
    .daoexamples.movie.MovieUtil

    MovieDAO接口定义了DAO的数据操作。这个接口有如下五个方法:
    .public Movie findMovieById(String id)
    .public java.util.Collection findMoviesByYear(String year)
    .public void deleteMovie(String id)
    .public Movie createMovie(String rating,String year,String title)
    .public void updateMovie(String id,String rating,String year,String title)
    daoexamples.movie包包含了两个MovieDAO接口的实现。每个实现使用了一个同的事务划分方法,如下表所示:
        MovieDAOImpl    MovieDAOImplJTA
    实现了MovieDAO接口吗?    Yes    Yes
    通过JNDI获得DataSource吗?    Yes    Yes
    从一个DataSource获得java.sql.Connection对象吗?    Yes    Yes
    DAO界定内部的事务吗?    Yes    No
    使用JDBC事务吗?    Yes    No
    使用一个XA DataSource吗?    No    Yes
    分担JTA事务吗?    No    Yes


    MovieDAO 示范应用程序
    这个示范应用程序是一个叫做daoexamples.moviedemo.DemoServlet.DemoServlet的servlet类,它使用Movie DAO来查询和更新一个表中的movie数据。

    这个servlet示范了把JTA感知的MovieDAO和Java消息服务组合到一个单一的事务中,如示例8所示:
    UserTransaction utx = MovieUtil.getUserTransaction();
    utx.begin();
    batman = dao.createMovie("R",
          "2008",
          "Batman Reloaded");
    publisher = new MessagePublisher();
    publisher.publishTextMessage("I'll be back");
    dao.updateMovie(topgun.getId(),
          "PG-13",
          topgun.getReleaseYear(),
          topgun.getTitle());
    dao.deleteMovie(legallyblonde.getId());
    utx.commit();

    要运行这个范例应用程序,在你的应用程序服务器中配置一个XA 数据源和一个非XA数据源。然后布署daoexamples.ear文件。这个应用程序将运行在任何与J2EE兼容的应用程序服务器。
    08 December

    试用 Visual Studio C# 2005 Express

    前几天下了 c#2005一直没得用, 今天一用之下大为惊叹, 微软的中间语言代码居然执行得这么快,和exe几乎感觉不到差别. 想当年.NET FRAMEWORK1.0版出来的时候启动运行都有不少延迟.不禁感叹, 微软实力之强大. 微软意识到必须要活, 还要活得更好,就得大大超越开源免费.商业就是商业, 跟开源是有本质区别的.
     
    今天的测试只是感觉, 虽没有严格科学的测试, 但基本上目前JAVA的虚拟机,中间码的水平与.NET 2.0是有差距的.
     
     
    13 August

    HTML标签 fieldset

    今天要介绍大家一个HTML非常有用但被很多人忽视的标签 <fieldset>
     
    在WINDOWS桌面应用中,一个对话框里通常都能看到用frame将相关的一些属性,参数设置分组,使内容更有组织性,更容易明白理解.(你可以打开Internet属性对话框,在第一个"常规"选项卡里,就有三个frame,"主页","Internet临时文件","历史记录". 注意不要与HTML的<frame>标签搞混了,不是一个概念.
     
    是的, fieldset 在HTML里完成的功能与上述相同.fieldset与legend一起使用,legend要放在fieldset里,并且是fieldset里的第一个标签.legend是frame的标题. 像这样用:
    <fieldset>
    <legend>美丽的一天</legend>
    在花儿盛开的季节..........
    </fieldset>
     
    不过很遗憾地告诉大家,微软msn space不支持fieldset 标签,fieldset标签会在发布时被过滤掉.....残念.期待未来msn space能改进一下,这个标签并没有什么破坏性的动作嘛,而且也是W3C的标准
     
     

    项目笔记

    昨天忙了一下午终于把A项目给部署好了.收获颇多.虽然在部署过程中有少东西对我来说是
    新的.但还是一一被解决.下面就将此项目过程中的一些心得体会随便写写,随便写写.
     
    一. 技术性的收获.
    .NET 部署过程中,如果是新安装,记住ASP.NET运行的帐户权限很低, 一般来说若要正确运行
    一个应用,都得额外分配一个帐户.可以比较简单的在machine.config里设置processModel节
    ,把username改machine(machine是此属性的关键字,指出使用ASPNET这个帐户名作为用户名)
    为system,也就是让ASP.NET在系统帐户下运行. SYSTEM的权限基本上能让大多数ASP.NET应
    用正确运行.但是,SYSTEM帐户不大安全.权限太高了.另一种方式是在ASP.NET应用的web.con
    fig文件里单独为此ASP.NET应用配置运行帐户,在WEB.CONFIG的identity节里可以配置.更详
    细的信息可以参考MSDN.
    二. 软件开发过程方面收获
     
    细节决定成败
    昨天一下午,一半时间是搞清楚了为什么部署失败,就是帐户权限上的问题.一半时间是软
    件功能及细节上的问题.为什么会出现功能,细节上的问题呢.我想这又是老话题了.但是
    通过这个项目还是找到了一些方式方法,能在软件设计功能细节方面做得更好.
     
    立刻反馈与沟通

    推销员要面对客户的拒绝,软件开发人员要面对客户的挑剔.哈,我终于发现搞销售与技术
    上的区别.优秀的推销员不会害怕客户的拒绝,优秀的软件开发人员也不应该害怕客户的挑
    剔.有说,软件开发人员更高的要求是能随需应变.但也不能盲从,我们既要以饱满的精神
    挑战客户的需求变化,同时对客户的"无理要求"敢于提出自己的想法并以"权衡开发,修
    改难度与得到最佳效果为目的"的心态与客户进行有效地沟通.
    说点实际的吧,在A项目过
    程中发现,及时的与客户反馈沟通是很重要的,不要等到整个项目完了再跟客户说,"OK
    ,项目好了,你看看,没问题就发布了"任何时候,一小块功能的完成,你都应该及时告诉
    客户说:"好了,X功能完成,将来发布就是这样,你看看怎么样,如果有问题请及时告诉
    我,我现在去搞Y功能了"及时反馈与沟通还要在细节上,反馈沟通的内容很灵活的,粒度可大可小,比如一个单词,某项操作的设计,某项逻辑的决定.同时在面对"随需变化"时,要求技术上更为过硬.一个糟糕的技术实现框架会让你增加不少改动上的麻烦.
    我为什么要用"立刻"这个字眼,就是要马上行动,立刻行动,不要害怕,OK?也许你不害怕,那很好,请你立刻沟通!有人会问,害怕什么呢,害怕麻烦,客户SAY NO等于就是麻烦来了.你要做好挑战麻烦的准备,不要害怕,这是心态上的调整.如果没有这种心态,不愿面对客户,那不等于闭门造车吗?客户SAY NO时可怕,客户SAY YES时你高不高兴?你要想着YES的情况.偏题了,又是心理学.心理学的游戏又来了....
    写这个花太多时间了.......到此为止....888888
    10 August

    BLOGER体验

    我实在算不上是什么BLOGER,因为今天才是我有生以来BLOG的第二天。昨天是怎么BLOG的呢?我一大早来到单位什么人都没有除了我和鬼~照例在网上看看资料,登录MSN,QQ,BQQ。MSN SPACES也许有很多优点,但在那一天唯一吸引我的地方就是他的页面设计,排版。做网页是我现在的工作,我只关心MSNSPACES的设计,虽然它可能在某些大虾眼里不是最好的,但至少不差吧。不差就学喽,反正我是很差,学到不差也是有进步了。 好了,学了看了,一时不知道怎么想起来要把网上刚看的资料贴到MSNSPACES上,好了,贴就贴吧,就这样贴出个BLOGER了哈哈
     
     
    我这人是一点也不喜欢写东西的,一来写不好,二来觉得没必要,我写来给谁看啊,无非是一堆没用的文字,污染眼睛还污染网络,网络上的文字已经够多了不是吗,甚至我还曾想劝大家都不要这么张杨了,根据3-7或者2-8法则,7,80%的日志都是默默无闻的。这有什么用呢,还花我时间。我不喜欢只会写只会说的人,我凡事都要做,不做,说什么都没有用。与其在这里喷墨,不如多干点XXXX(填任何你喜欢做的事)
     
    很不幸的是,我破例了。尽管如此,我仍然不会花太多时间在这上面,我只是我的另一个家,来这里只是游子回家过年,女婿回娘家看岳父岳母,时间不会太长。但每次回家都会带上好东西。。。。

    MSN SPACES 的浏览器后台更新

     
    前段时间就关注过 MSN Spaces的后台更新操作.什么是 MSN Spaces 的后台更新操作呢? 在你编辑自己的共享空间时,你在添加列表,编辑列表,删除列表时,页面是不会重新生成的,是MSN SPACES通过javascript在后台为你向服务器发送URL来完成操作.
     
    前段时间眼花没看出来,昨晚闲时随便看看就看出来了.大家有没有这样的经验,找个东西找半天找不出来,可是当你不要找它,隔几天偶然就发现了~ 所谓柳暗花明又一村就是这个道理了~
     
    MSN SPACES具体在后台如何操作呢. 当你打开它的JS源码时,看得是比较头痛的,有个JS文件叫STRONG>listsvisitor.js,里面的最末尾有个函数叫_sd_Post,这就是关键的后台更新主函数.大多数后台更新的操作最后都将调用这个函数,通过参数URL发送的服务器进行处理.它使用了XMLHTTPRequest,通过ACTIVEX控件向服务器发送请求并接收响应来完成整个操作。我没有继续深入研究请求,响应的数据格式,有兴趣的朋友可以继续,若有新的发现请别忘了与我一起分享DIV>
    我们看到,后台更新的优点很明显,局部更新,不刷新整个页面,让用户感觉没有什么延迟,不会闪眼,对程序的整体感觉更有延续性,连惯性。这是用户交互上的优点。当然有得必有失,你必须付出更多的代价,包括测试调试,整合,在客户端你需要更多的处理,调试也不大方便。这种方式我个人认为在小项目里不适合采用,如果是比较大的项目,付出点代价得到更好的用户交互体验是值得的DIV>