??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲精品之草原avav久久,男人的天堂久久,国产精品精品国产一区二区http://www.aygfsteel.com/jx1984520/w是菩提树,心如明镜収ͼ时时勤拂拭,勿染尘埃? 菩提本无树,明镜亦非収ͼ本来无一物,何处惹尘埃?/description>zh-cnFri, 20 Jun 2025 01:34:57 GMTFri, 20 Jun 2025 01:34:57 GMT60使用struts+spring+hibernate l装web应用http://www.aygfsteel.com/jx1984520/archive/2007/06/11/123296.htmljavabrightjavabrightMon, 11 Jun 2007 01:35:00 GMThttp://www.aygfsteel.com/jx1984520/archive/2007/06/11/123296.htmlhttp://www.aygfsteel.com/jx1984520/comments/123296.htmlhttp://www.aygfsteel.com/jx1984520/archive/2007/06/11/123296.html#Feedback0http://www.aygfsteel.com/jx1984520/comments/commentRss/123296.htmlhttp://www.aygfsteel.com/jx1984520/services/trackbacks/123296.html其实Q就用Java建造一个不是很烦琐的web应用Q也不是件轻杄事情?在构架的一开始就有很多事情要考虑?从高处看Q摆在开发者面前有很多问题Q要考虑是怎样建立用户接口Q在哪里处理业务逻辑Q?怎样持久化的数据?而这三层构架中,每一层都有他们要仔细考虑的?各个层该使用什么技术? 怎样的设计能松散耦合q能灉|改变Q?怎样替换某个层而不影响整体构架Q应用程序如何做各种U别的业务处理(比如事务处理Q?



构架一个Web应用需要弄明白好多问题?q运的是Q已l有不少开发者已l遇到过q类问题Qƈ且徏立了处理q类问题的框架?一个好框架具备以下几点Q?减轻开发者处理复杂的问题的负担(“不重复发明轮?#8221;Q; 内部有良好的扩展Q?q且有一个支持它的强大的用户团体?好的构架一般有针对性的处理某一c问题,q且能将它做好(Do One Thing wellQ?然而,你的E序中有几个层可能需要用特定的框架Q已l完成的UI(用户接口) q不代表你也可以把你的业务逻辑和持久逻辑偶合C的UI部分?举个例子Q?你不该在一个Controller(控制?里面写JDBC代码作ؓ你的业务逻辑Q?q不是控制器应该提供的?一个UI 控制器应该委z其它l在UI范围之外的轻量lg?好的框架应该能指g码如何分布?更重要的是,框架能把开发者从~码中解攑և来,使他们能专心于应用程序的逻辑Q这对客h说很重要Q?



q篇文章讨论怎样l合几种著名的框架来使得你的应用E序做到村ּ耦合?

如何建立你的架构Qƈ且怎样让你的各个应用层保持一致。?如何整合框架以便让每个层在以一U松散偶合的方式彼此作用而不用管低层的技术细节?q对我们来说真是一U挑战?q里讨论一个整合框架的{略( 使用3 U受Ƣ迎的开源框? Q表C层我们用StrutsQ?业务层我们用SpringQ而持久层则用Hibernate?你也可以用其他FrameWork替换只要能得到同L效果?见图1 Q框架组合示意图Q?



应用E序的分?/span>

大部分的Web应用在职责上臛_能被分成4层?q四层是QpresentationQ描qͼQpersistenceQ持久)QbusinessQ业务)和domain modelQ域模块Q。每个层在处理程序上都应该有一Ҏ的责Q, 而不应该在功能上与其它层混合Qƈ且每个层要与其它层分开的,但要l他们之间放一个通信接口?我们׃介绍各个层开始,讨论一下这些层应该提供什么,不应该提供什么?



表示?The Presentation Layer)

一般来Ԍ一个典型的Web应用的的末端应该是表C层?很多Java发者也理解Struts所提供的?象业务逻辑之类的被打包到org.apache.struts.Action.Q?因此Q我们很赞成使用Strutsq样的框架?



下面是Struts所负责的:

* 理用户的请?做出相应的响应?

* 提供一个Controller ,委派调用业务逻辑和其它上层处理?

* 处理异常Q抛lStruts Action

* 为显C提供一个模?

* UI验证?



以下条款Q不该在Struts昄层的~码中经常出现?它们与显C层无关的?

* 直接的与数据库通信Q例如JDBC调用?

* 与你应用E序相关联的业务逻辑以及校验?

* 事物理?

在表C层引入q些代码Q则会带来高偶合和麻烦的l护?





持久?The Persistence Layer)

典型的Web应用的另一个末端是持久层。这里通常是程序最Ҏ失控的地斏V开发者L低估构徏他们自己的持久框架的挑战性。系l内部的持箋层不但需要大量调试时_而且q经常缺功能之变得难以控Ӟq是持久层的通病?q好有几个ORM开源框架很好的解决了这c问题。尤其是Hibernate?Hibernate为java提供了OR持久化机制和查询服务, 它还l已l熟悉SQL和JDBC API 的Java开发者一个学习桥梁,他们学习h很方ѝ?Hibernate的持久对象是ZPOJO和Java collections。此外,使用Hibernateq不妨碍你正在用的IDE?



L下面的条目,你在持久层编码中需要了解的?

* 查询对象的相关信息的语句?Hibernate通过一个OO查询语言QHQLQ或者正则表辄API来完成查询?HQL非常cM于SQL-- 只是把SQL里的table和columns用Object和它的fields代替?你需要学习一些新的HQL语言Q?不管怎样Q他们容易理解而文也做的很好?HQL是一U对象查询的自然语言Q花很小的代价就能学习它?

* 如何存储Q更斎ͼ删除数据库记录?

* 象Hibernateq类的高UORM框架支持大部分主数据库Qƈ且他们支?Parent/child关系Q事物处理,l承和多态?



业务层(The Business LayerQ?/span>

一个典型Web应用的中间部分是业务层或者服务层?从编码的视角来看Q这层是最Ҏ被忽视的一层?而我们却往往在UI层或持久层周围看到这些业务处理的代码Q这其实是不正确的,因ؓ它导致了E序代码的紧密偶合,q样一来,随着旉推移q些代码很难l护。幸好,针对q一问题有好几种Frameworks存在?最受欢q的两个框架是Spring和PicoContainer?q些Z被称为microcontainersQ他们能让你很好的把对象搭配h?q两个框枉着手于‘依赖注射’(dependency injection)(q有我们知道?#8216;控制反{’Inversion of Control=IoC)q样的简单概c?q篇文章关注于Spring的注(译注Q通过一个给定参数的SetterҎ来构造Bean,有所不同于FactoryQ? Springq提供了Setter Injection(type2)QConstructor Injection(type3){方式供我们选择?Spring把程序中所涉及到包含业务逻辑和Dao的Objects——例如transaction management handlerQ事物管理控Ӟ、Object Factoris(对象工厂)、service objectsQ服务组Ӟ——都通过XML来配|联pv来?



后面我们会D个例子来揭示一下Spring 是怎样q用q些概念?

业务层所负责的如下:

* 处理应用E序?业务逻辑和业务校?

* 理事物

* 允许与其它层怺作用的接?

* 理业务层别的对象的依赖?

* 在显C层和持久层之间增加了一个灵zȝ机制Q得他们不直接的联pd一赗?

* 通过揭示 从显C层C务层之间的Context来得到business services?

* 理E序的执行(从业务层到持久层Q?





域模块层QThe Domain Model Layer Q?/span>
既然我们致力于的是一个不是很复杂的Web的应用, 我们需要一个对象集合,让它在不同层之间Ud的?域模块层由实际需求中的业务对象组?比如, OrderLineItem , Product{等?开发者在q层 不用那些DTOsQ仅xdomain object卛_?例如QHibernate允许你将数据库中的信息存攑օ对象Qdomain objectsQ,q样你可以在q接断开的情况下把这些数据显C到UI层?而那些对象也可以q回l持l层Q从而在数据库里更新?而且Q你不必把对象{化成DTOsQ这可能似的它在不同层之间的在传输过E中丢失Q,q个模型使得Java开发者能很自然运用OOQ而不需要附加的~码?

一个简单例?



既然我们已经从全局上理解这些组件?现在p我们开始实践吧?我们q是?StrutsQSpring 和Hibernate。这三个框架已经被描q够多了Q这里就不重复介l了?q篇文章举例指导你如何用这三个框架整合开? q向你揭C?一个请求是如何贯穿于各个层的。(从用L加入一个Order到数据库Q显C;q而更新、删除)?



从这里可以下载到E序E序原代码(
downloadQ?

既然每个层是互相作用的,我们先来创建domain objects。首先,我们要在q些Object中要定那些是需要持久化的,哪些是提供给business logicQ那些是昄接口的设计?下一步,我们配|我们的持久层ƈ且定义好Hibernate的OR mappings。然后定义好Business Objects。有了这些组成部分之后,我们?使用Spring把这些连接v来?最后,我们提供lSpring一个持久层Q从q个持久层里我们可以知道它是如何与业务逻辑层(business service layerQ通信的,以及它是怎样处理其他层抛出的异常的。?



域对象层QDomain Object LayerQ?/span>


q层是编码的着手点Q我们的~码׃q层开始?例子中Order 与OrderItem 是一个One—To—Many的关pR?下面是Domain Object Layer的两个对象:



· com.meagle.bo.Order.java: 包含了一个Order的概要信?

· com.meagle.bo.OrderLineItem.java: 包含了Order的详l信?

好好考虑怎你的package命名,q反应出了你是怎样分层的?例如 domain objects在程序中可能打包在com.meagle.bo内?更详l一点将打包在com. meagle.bo的子目录下面。business logic应该从com.meagle.serice开始打包,而DAO 对象应该位于com.meagle.service.dao.hibernate。反应Forms和Actions?持久对象Qpresentation classesQ?应该分别攑֜ com.meagle.action和com.meagle.forms包?准确的给包命名得你的classes很好分割q且易于l护Qƈ且在你添加新的classesӞ能得程序结构上保持上下一致?

持久层的配置QPersistence Layer ConfigurationQ?/span>

建立Hibernate的持久层 需要好几个步骤?W一步让我们把BO持久化?既然Hibernate是通过POJO工作的, 因此Order?OrderLineItem对象需要给所有的fileds 加上getter,setterҎ?Hibernate通过XML文g来映?OR)对象Q以下两个xml文g分别映射了Order 和OrderItem对象。(q里有个叫XDoclet工具可以自动生成你的XML影射文gQ?

- Order.hbm.xml
- OrderLineItem.hbm.xml

你可以在WebContent/WEB-INF/classes/com/meagle/bo目录下找到这些xml文g。Hibernate?[urlhttp://www.hibernate.org/hib_docs/api/net/sf/hibernate/SessionFactory.html]SessionFactory [/url]是用来告诉程?应该与哪个数据库通信Q该使用哪个q接池或使用了DataSourceQ?应该加蝲哪些持久对象。?/font>Session接口是用来完成SelectingQSavingQDelete和Updatingq些操作?后面的我们将讲述SessionFactory和Session是怎样讄的?

业务层的配置QBusiness Layer ConfigurationQ?/span>

既然我们已经有了domain objectsQ接下来我们pbusiness service objects了,用他们来执行E序的logic,调用持久层,得到UI层的requests,处理transactionsQƈ且控制exceptions?Z这些连接v来ƈ且易于管理,我们用面向方面的 SpringFramework?Spring 提供?控制倒置Qinversion of control 0==IoC)和注依赖设|(setter dependency injectionQ这些方式(可供选择Q,用XML文g对象连接v来?IoC是一个简单概念(它允怸个对象在上层接受其他对象的创建)Q用IoCq种方式让你的对象从创徏中释放了出来Q降低了偶合度?




q里是一个没有用IoC的对象创建的例子Q它有很高偶合度?




?2.没有使用 IoC. A 创徏?B ?C

而这里是一个用IoC的例子,q种方式允许对象在高层可以创建ƈq入另外一个对象,所以这样可以直接被执行?


?3. 对象使用?IoC?A 包含了接受B,C?setterҎ , q同栯C 由A创徏B,C的目的?/span>

建立我们的业务服务对象(Building Our Business Service ObjectsQ?


Business Object中的SetterҎ接受的是接口Q这h们可以很松散的定义对象实玎ͼ然后注入?在我们的案例中,我们用一个business service object接收一个DAO,用它来控制domain objects的持久化?׃在这个例子中使用了HibernateQ我们可以很方便的用其他持久框架实现 同时通知Spring 有新的DAO可以使用了?

在面向接口的~程中,你会明白 “注射依赖”模式是怎样松散耦合你的业务逻辑和持久机制的Q)?



下面是一个接口business service objectQDAO代码片段Q?


代码:

public interface IOrderService {

  public abstract Order saveNewOrder(Order order)

    throws OrderException,

           OrderMinimumAmountException;

 

  public abstract List findOrderByUser(

                                     String user)

                           throws OrderException;

 

  public abstract Order findOrderById(int id)

                           throws OrderException;

 

  public abstract void setOrderDAO(

                             IOrderDAO orderDAO);

}

 

注意到这D代码里有一?setOrderDaoQ)Q它是一个DAO Object讄ҎQ注器Q?但这里ƈ没有一个getOrderDao的方法,q不必要Q因Zq不会在外部讉Kq个orderDao。这个DAO Objecte被调用Q和我们的persistence layer 通信。我们将用Spring把DAO Object ?business service object搭配h的。因为我们是面向接口~程的,所以ƈ不需要将实现cȝ密的耦合在一赗?



接下L们开始我们的DAO的实现类q行~码?既然Spring已经有对Hibernate的支持,那这个例子就直接l承HibernateDaoSupportcMQ这个类很有用,我们可以参?a class=postlink target=_blank>HibernateTemplateQ它主要是针对HibernateDaoSupport的一个用法,译注Q具体可以查?a class=postlink target=_blank>Srping 的APIQ?下面是这个DAO接口代码Q?

代码:
public interface IOrderDAO {
  public abstract Order findOrderById(
                                    final int id);
 
  public abstract List findOrdersPlaceByUser(
                           final String placedBy);
  public abstract Order saveOrder(
                               final Order order);
}


我们仍然要给我们持久层组装很多关联的对象Q这里包含了HibernateSessionFactory 和TransactionManager?Spring 提供了一?HibernateTransactionManagerQ他用线E捆l了一个Hibernate SessionQ用它来支持transactions(h?a class=postlink target=_blank>ThreadLocal) ?

下面是HibernateSessionFactory ?HibernateTransactionManager:的配|:

代码:
<bean id="mySessionFactory"
       class="org.springframework.orm.hibernate.
              LocalSessionFactoryBean">
  <property name="mappingResources">
    <list>
      <value>
        com/meagle/bo/Order.hbm.xml
      </value>
      <value>
        com/meagle/bo/OrderLineItem.hbm.xml
      </value>
    </list>
  </property>
  <property name="hibernateProperties">
    <props>
      <prop key="hibernate.dialect">
        net.sf.hibernate.dialect.MySQLDialect
      </prop>
      <prop key="hibernate.show_sql">
        false
      </prop>
      <prop key="hibernate.proxool.xml">
        C:/MyWebApps/.../WEB-INF/proxool.xml
      </prop>
      <prop key="hibernate.proxool.pool_alias">
          spring
      </prop>
    </props>
  </property>
</bean>
 
<!-- Transaction manager for a single Hibernate
SessionFactory (alternative to JTA) -->
<bean id="myTransactionManager"
         class="org.
                springframework.
                orm.
                hibernate.
                HibernateTransactionManager">
  <property name="sessionFactory">
    <ref local="mySessionFactory"/>
  </property>
  </bean>



可以看出Q每个对象都可以在Spring 配置信息中用<bean>标签引用。在q里QmySessionFactory引用了HibernateSessionFactoryQ而myTransactionManager引用了HibernateTransactionManage?注意代码中myTransactionManger Bean有个sessionFactory属性?HibernateTransactionManager有个sessionFactory setter ?getterҎQ这是用来在Spring启动的时候实?#8220;依赖注入” Qdependency injectionQ的?在sessionFactory 属性里 引用mySessionFactory。这两个对象在Spring容器初始化后pl装了v来了?q样的搭配让你从 单例Qsingleton objectsQ和工厂QfactoriesQ中解放了出来,降低了代码的l护代h?mySessionFactory.的两个属性,分别是用来注入mappingResources ?hibernatePropertes的。通常Q如果你在Spring之外使用Hibernate,q样的设|应该放在hibernate.cfg.xml中的?不管怎样,Spring提供了一个便L方式-----在Spring内部配置中ƈ入了Hibernate的配|?如果要得到更多的信息Q可以查阅Spring API?





既然我们已经l装配置好了Service BeansQ就需要把Business Service Object?DAO也组装v来,q把q些对象配到一个事务管理器Qtransaction managerQ里?



在Spring中的配置信息Q?
代码:

<!-- ORDER SERVICE -->
<bean id="orderService"
  class="org.
         springframework.
         transaction.
         interceptor.
         TransactionProxyFactoryBean">
  <property name="transactionManager">
    <ref local="myTransactionManager"/>
  </property>
  <property name="target">
    <ref local="orderTarget"/>
  </property>
  <property name="transactionAttributes">
    <props>
      <prop key="find*">
     PROPAGATION_REQUIRED,readOnly,-OrderException
      </prop>
      <prop key="save*">
     PROPAGATION_REQUIRED,-OrderException
      </prop>
    </props>
  </property>
</bean>
 
<!-- ORDER TARGET PRIMARY BUSINESS OBJECT:
Hibernate implementation -->
<bean id="orderTarget"
         class="com.
                meagle.
                service.
                spring.
                OrderServiceSpringImpl">
  <property name="orderDAO">
    <ref local="orderDAO"/>
  </property>
</bean>
 
<!-- ORDER DAO OBJECT -->
<bean id="orderDAO"
         class="com.
                meagle.
                service.
                dao.
                hibernate.
                OrderHibernateDAO">
  <property name="sessionFactory">
    <ref local="mySessionFactory"/>
  </property>
</bean>




? 是我们对象搭建的一个提UӀ?从中可以看出Q每个对象都联系着SpringQƈ且能通过Spring注入到其他对象。把它与Spring的配|文件比较,观察他们之间的关p?



?4. Spring是q样Z配置文gQ将各个Bean搭徏在一赗?/span>

q个例子使用一个TransactionProxyFactoryBeanQ它定义了一个setTransactionManager()?q对象很有用Q他能很方便的处理你x的事物还有Service Object?你可以通过transactionAttributes属性来定义怎样处理?想知道更多还是参考TransactionAttributeEditor吧?

TransactionProxyFactoryBean q有个setter. q会被我?Business service objectQorderTargetQ引用, orderTarget定义?业务服务层,q且它还有个属性,由setOrderDAO()引用。这个属?



Spring 和Bean 的还有一点要注意的: bean可以以用两种方式创造?q些都在单例模式QSingtonQ和原型模式QpropotypeQ中定义了?默认的方式是singleton,q意味着׃n的实例将被束~?而原形模式是在Spring用到bean的时候允许新建实例的。当每个用户需要得C们自己Bean的CopyӞ你应该仅使用prototype模式。(更多的请参考设计模式中的单例模式和原Ş模式Q?

提供一个服务定位器QProviding a Service LocatorQ?/span>
既然我们已经我们的Serices和DAO搭配h了。我们需要把我们的Service昄到其他层?q个通常是在Struts或者Swingq层里编码。一个简单方法就是用 服务定位器返回给Spring context 。当Ӟ可以通过直接调用Spring中的Bean来做?

下面是一个Struts Actin 中的服务定位器的一个例子?
代码:

public abstract class BaseAction extends Action {
 
  private IOrderService orderService;
 
  public void setServlet(ActionServlet
                                 actionServlet) {
    super.setServlet(actionServlet);
    ServletContext servletContext =
               actionServlet.getServletContext();
 
    WebApplicationContext wac =
      WebApplicationContextUtils.
         getRequiredWebApplicationContext(
                                 servletContext);
 
      this.orderService = (IOrderService)
                     wac.getBean("orderService");
  }
 
  protected IOrderService getOrderService() {
    return orderService;
  }
}
 

UI 层配|?QUI Layer ConfigurationQ?/span>

q个例子里UI?使用了Struts framework. q里我们要讲qC下在l程序分层的时候, 哪些是和Struts部分的。我们就从一个Struts-config.xml文g中的Action的配|信息开始吧?
代码:

struts-config.xml file.

<action path="/SaveNewOrder"
    type="com.meagle.action.SaveOrderAction"
    name="OrderForm"
    scope="request"
    validate="true"
    input="/NewOrder.jsp">
  <display-name>Save New Order</display-name>
  <exception key="error.order.save"
    path="/NewOrder.jsp"
    scope="request"
    type="com.meagle.exception.OrderException"/>
  <exception key="error.order.not.enough.money"
    path="/NewOrder.jsp"
    scope="request"
    type="com.
          meagle.
          exception.
          OrderMinimumAmountException"/>
  <forward name="success" path="/ViewOrder.jsp"/>
  <forward name="failure" path="/NewOrder.jsp"/>
</action>

SaveNewOrder q个Action是用来持久化UI层里的表单提交过来Order的。这是Struts中一个很典型的Action; 注意观察q个Action中exception配置Q这些Exceptions也在Spring 配置文g(applicationContext-hibernate.xml)中配|了Q就?business service object 的transactionAttributes属性里Q?当异常在业务层被被抛出时Q我们可以控制他们,q当的显C给UI层?

W一个异常,OrderException,在持久层保存order对象p|的时候被触发。这导致事物回滚ƈ且通过BO把异常回传到Strutsq一层?

W二个异常,OrderMinimumAmountException也同W一个一栗?





搭配整和的最后一?通过是让你显C层和业务层相结合。这个已l被服务定位器(service locatorQ实CQ前面讨了)Q?q里服务层作Z个接口提供给我们的业务逻辑和持久层?



SaveNewOrder Action 在Struts中用一个服务定位器Qservice locatorQ来调用执行业务Ҏ的?Ҏ代码如下Q?



代码:
public ActionForward execute(

  ActionMapping mapping,

  ActionForm form,

  javax.servlet.http.HttpServletRequest request,

  javax.servlet.http.HttpServletResponse response)

  throws java.lang.Exception {

 

  OrderForm oForm = (OrderForm) form;

 

  // Use the form to build an Order object that

  // can be saved in the persistence layer.

  // See the full source code in the sample app.

 

  // Obtain the wired business service object

  // from the service locator configuration

  // in BaseAction.

  // Delegate the save to the service layer and

  // further upstream to save the Order object.

  getOrderService().saveNewOrder(order);

 

  oForm.setOrder(order);

 

  ActionMessages messages = new ActionMessages();

  messages.add(

      ActionMessages.GLOBAL_MESSAGE,

            new ActionMessage(

      "message.order.saved.successfully"));

 

  saveMessages(request, messages);

 

  return mapping.findForward("success");

}


ȝ

q篇文章在技术和构架斚w掩盖了很多低层的基础信息Q?文章的主要的意图在于让你意识到如何给你应用程序分层?分层可以“解?#8221;你的代码——允许新的组件被dq来Q而且让你的代码易于维护?q里用到的技术只是专注于?#8220;解偶”做好?不管怎样Q用这L构架可以让你用其他技术代替现在的层?例如Q你可能不用Hibernate实现持久化。既然你在DAO中面向接口的~程的,所以你完全可以用iBATIS来代ѝ或者,你也可能想用Struts外的其他的技术或者框架替换现在的UI层(转换久层Q实现层q不应该直接影响C的业务逻辑和业务服务层Q?用适当的框架搭Z的Web应用Q其实也不是一件烦琐的工作Q更主要的是?#8220;解?#8221;了你E序中的各个层?





后记Q?

看完q篇文章后,只是觉得很喜Ƣ,于是q译了Q当然同时也准备着挨大家扔来的鸡蛋Q)?

q篇文章里ƈ没有太多的技术细节,和详l的步骤。如果你从未使用q这些框架而在q行实例E序遇上困难的话Q可以到CSDN论坛Java Open Source版发_我一定会详细解答的(啊哦Q这不算做广告吧Q)Q?

文章是从一个构架的角度讲述了如何搭配现有的开源框架进行分层, 有太多的术语我都不知道怎么表达Q而且可能有很多语句存在错误。如果媄响了你的阅读Q请你直接点原文地址Q我同时也象你说声抱歉?


javabright 2007-06-11 09:35 发表评论
]]>
Java基础Q关于session的详l解?(3)http://www.aygfsteel.com/jx1984520/archive/2007/05/15/117671.htmljavabrightjavabrightTue, 15 May 2007 10:38:00 GMThttp://www.aygfsteel.com/jx1984520/archive/2007/05/15/117671.htmlhttp://www.aygfsteel.com/jx1984520/comments/117671.htmlhttp://www.aygfsteel.com/jx1984520/archive/2007/05/15/117671.html#Feedback0http://www.aygfsteel.com/jx1984520/comments/commentRss/117671.htmlhttp://www.aygfsteel.com/jx1984520/services/trackbacks/117671.html  你可以创Llistenerȝ控session的创建和销毁事Ӟ使得在发生这L事g时你可以做一些相应的工作。注意是session的创建和销毁动作触发listenerQ而不是相反。类似的与HttpSession有关的listenerq有HttpSessionBindingListenerQHttpSessionActivationListener和HttpSessionAttributeListener?

5、存攑֜session中的对象必须是可序列化的?/p>

  不是必需的。要求对象可序列化只是ؓ了session能够在集中被复制或者能够持久保存或者在必要时server能够暂时把session交换出内存。在Weblogic Server的session中放|一个不可序列化的对象在控制C会收C个警告。我所用过的某个iPlanet版本如果session中有不可序列化的对象Q在session销毁时会有一个ExceptionQ很奇怪?/p>

  6、如何才能正的应付客户端禁止cookie的可能?/p>

  Ҏ有的URL使用URL重写Q包括超链接Qform的actionQ和重定向的URLQ具体做法参见[6]
http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770

  7、开两个览器窗口访问应用程序会使用同一个sessionq是不同的session

  参见W三节对cookie的讨论,对session来说是只认id不认人,因此不同的浏览器Q不同的H口打开方式以及不同的cookie存储方式都会对这个问题的{案有媄响?/p>

  8、如何防止用h开两个览器窗口操作导致的session混ؕ

  q个问题与防止表单多ơ提交是cM的,可以通过讄客户端的令牌来解冟뀂就是在服务器每ơ生成一个不同的idq回l客LQ同时保存在session里,客户端提交表单时必须把这个id也返回服务器Q程序首先比较返回的id与保存在session里的值是否一_如果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表C层模式的部分。需要注意的是对于用javascript window.open打开的窗口,一般不讄q个idQ或者用单独的idQ以防主H口无法操作Q徏议不要再window.open打开的窗口里做修Ҏ作,q样可以不用设|?/p>

  9、ؓ什么在Weblogic Server中改变session的值后要重新调用一ơsession.setValue
做这个动作主要是Z在集环境中提示Weblogic Server session中的值发生了改变Q需要向其他服务器进E复制新的session倹{?/p>

  10、ؓ什么session不见?/p>

  排除session正常失效的因素之外,服务器本w的可能性应该是微乎其微的,虽然W者在iPlanet6SP1加若q补丁的Solaris版本上倒也遇到q;览器插件的可能性次之,W者也遇到q?721插g造成的问题;理论上防火墙或者代理服务器在cookie处理上也有可能会出现问题?/p>

  出现q一问题的大部分原因都是E序的错误,最常见的就是在一个应用程序中去访问另外一个应用程序。我们在下一节讨个问题?/p>

  七、跨应用E序的session׃n

  常常有这L情况Q一个大目被分割成若干项目开发,Z能够互不q扰Q要求每个小目作ؓ一个单独的web应用E序开发,可是C最后突然发现某几个项目之间需要共享一些信息,或者想使用session来实现SSO(single sign on)Q在session中保存login的用户信息,最自然的要求是应用E序间能够访问彼此的session?/p>

  然而按照Servlet规范Qsession的作用范围应该仅仅限于当前应用程序下Q不同的应用E序之间是不能够互相讉KҎ的session的。各个应用服务器从实际效果上都遵守了q一规范Q但是实现的l节却可能各有不同,因此解决跨应用程序session׃n的方法也各不相同?/p>

  首先来看一下Tomcat是如何实现web应用E序之间session的隔ȝQ从Tomcat讄的cookie路径来看Q它对不同的应用E序讄的cookie路径是不同的Q这样不同的应用E序所用的session id是不同的Q因此即使在同一个浏览器H口里访问不同的应用E序Q发送给服务器的session id也可以是不同的?br>

  Ҏq个Ҏ,我们可以推测Tomcat中session的内存结构大致如下?br>

  W者以前用q的iPlanet也采用的是同L方式Q估计SunONE与iPlanet之间不会有太大的差别。对于这U方式的服务器,解决的思\很简单,实际实行h也不难。要么让所有的应用E序׃n一个session idQ要么让应用E序能够获得其他应用E序的session id?/p>

  iPlanet中有一U很单的Ҏ来实现共享一个session idQ那是把各个应用程序的cookie路径都设?Q实际上应该?NASAppQ对于应用程序来讲它的作用相当于根)?/p>

/NASApp

  需要注意的是,操作׃n的session应该遵@一些编E约定,比如在session attribute名字的前面加上应用程序的前缀Q得setAttribute("name", "neo")变成setAttribute("app1.name", "neo")Q以防止命名I间冲突Q导致互相覆盖?/p>


  在Tomcat中则没有q么方便的选择。在Tomcat版本3上,我们q可以有一些手D|׃nsession。对于版?以上的TomcatQ目前笔者尚未发现简单的办法。只能借助于第三方的力量,比如使用文g、数据库、JMS或者客LcookieQURL参数或者隐藏字D늭手段?/p>

  我们再看一下Weblogic Server是如何处理session的?br>

  从截屏画面上可以看到Weblogic ServerҎ有的应用E序讄的cookie的\径都?Q这是不是意味着在Weblogic Server中默认的可以共享session了呢Q然而一个小实验卛_证明即不同的应用程序用的是同一个sessionQ各个应用程序仍然只能访问自己所讄的那些属性。这说明Weblogic Server中的session的内存结构可能如?br>

  对于q样一U结构,在session机制本n上来解决session׃n的问题应该是不可能的了。除了借助于第三方的力量,比如使用文g、数据库、JMS或者客LcookieQURL参数或者隐藏字D늭手段Q还有一U较为方便的做法Q就是把一个应用程序的session攑ֈServletContext中,q样另外一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下,

  应用E序A

context.setAttribute("appA", session);

  应用E序B

contextA = context.getContext("/appA");
HttpSession sessionA = (HttpSession)contextA.getAttribute("appA");

  值得注意的是q种用法不可ULQ因为根据ServletContext的JavaDocQ应用服务器可以处于安全的原因对于context.getContext("/appA");q回I|以上做法在Weblogic Server 8.1中通过?/p>

  那么Weblogic ServerZ么要把所有的应用E序的cookie路径都设?呢?原来是ؓ了SSOQ凡是共享这个session的应用程序都可以׃n认证的信息。一个简单的实验可以证明这一点,修改首先d的那个应用程序的描述Wweblogic.xmlQ把cookie路径修改?appA讉K另外一个应用程序会重新要求dQ即使是反过来,先访问cookie路径?的应用程序,再访问修改过路径的这个,虽然不再提示dQ但是登录的用户信息也会丢失。注意做q个实验时认证方式应该用FORMQ因为浏览器和web服务器对basic认证方式有其他的处理方式Q第二次h的认证不是通过session来实现的。具体请参看[7] secion 14.8 AuthorizationQ你可以修改所附的CZE序来做q些试验?/p>

  八、ȝ

  session机制本nq不复杂Q然而其实现和配|上的灵zL却使得具体情况复杂多变。这也要求我们不能把仅仅某一ơ的l验或者某一个浏览器Q服务器的经验当作普遍适用的经验,而是始终需要具体情况具体分析?/p>

javabright 2007-05-15 18:38 发表评论
]]>
Java基础Q关于session的详l解?(2)http://www.aygfsteel.com/jx1984520/archive/2007/05/15/117670.htmljavabrightjavabrightTue, 15 May 2007 10:37:00 GMThttp://www.aygfsteel.com/jx1984520/archive/2007/05/15/117670.htmlhttp://www.aygfsteel.com/jx1984520/comments/117670.htmlhttp://www.aygfsteel.com/jx1984520/archive/2007/05/15/117670.html#Feedback0http://www.aygfsteel.com/jx1984520/comments/commentRss/117670.htmlhttp://www.aygfsteel.com/jx1984520/services/trackbacks/117670.html  存储在硬盘上的cookie可以在不同的览器进E间׃nQ比如两个IEH口。而对于保存在内存里的cookieQ不同的览器有不同的处理方式。对于IEQ在一个打开的窗口上按Ctrl-NQ或者从文g菜单Q打开的窗口可以与原窗口共享,而用其他方式新开的IEq程则不能共享已l打开的窗口的内存cookieQ对于Mozilla Firefox0.8Q所有的q程和标{N都可以共享同Lcookie。一般来说是用javascript的window.open打开的窗口会与原H口׃n内存cookie。浏览器对于会话cookie的这U只认cookie不认人的处理方式l常l采用session机制的web应用E序开发者造成很大的困扰?/p>

  下面是一个goolge讄cookie的响应头的例?/p>

HTTP/1.1 302 Found
Location: http://www.google.com/intl/zh-CN/
Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
Content-Type: text/html

  q是使用HTTPLookq个HTTP Sniffer软g来俘LHTTP通讯U录的一部分


  览器在再次讉Kgoolge的资源时自动向外发送cookie

  使用Firefox可以很容易的观察现有的cookie的?/p>

  使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理?/p>


  IE也可以设|在接受cookie前询?/p>

  q是一个询问接受cookie的对话框?/p>

  四、理解session机制

 session机制是一U服务器端的机制Q服务器使用一U类g散列表的l构Q也可能是使用散列表)来保存信息?/p>

  当程序需要ؓ某个客户端的h创徏一个session的时候,服务器首先检查这个客L的请求里是否已包含了一个session标识 - UCؓsession idQ如果已包含一个session id则说明以前已lؓ此客L创徏qsessionQ服务器按照session id把这个session索出来用(如果索不刎ͼ可能会新Z个)Q如果客Lh不包含session idQ则为此客户端创Z个sessionq且生成一个与此session相关联的session idQsession id的值应该是一个既不会重复Q又不容易被扑ֈ规律以仿造的字符Ԍq个session id被在本ơ响应中q回l客L保存?/p>

  保存q个session id的方式可以采用cookieQ这样在交互q程中浏览器可以自动的按照规则把q个标识发挥l服务器。一般这个cookie的名字都是类gSEEESIONIDQ而。比如weblogic对于web应用E序生成的cookieQJSESSIONID=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764Q它的名字就是JSESSIONID?/p>

  ׃cookie可以被h为的止Q必L其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一U技术叫做URL重写Q就是把session id直接附加在URL路径的后面,附加方式也有两种Q一U是作ؓURL路径的附加信息,表现形式为http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764另一U是作ؓ查询字符串附加在URL后面Q表现Ş式ؓhttp://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
q两U方式对于用h说是没有区别的,只是服务器在解析的时候处理的方式不同Q采用第一U方式也有利于把session id的信息和正常E序参数区分开来?/p>

  Z在整个交互过E中始终保持状态,必d每个客户端可能请求的路径后面都包含这个session id?/p>

  另一U技术叫做表单隐藏字Dc就是服务器会自动修改表单,d一个隐藏字D,以便在表单提交时能够把session id传递回服务器。比如下面的表单



javabright 2007-05-15 18:37 发表评论
]]>
Java基础Q关于session的详l解?(1)http://www.aygfsteel.com/jx1984520/archive/2007/05/15/117669.htmljavabrightjavabrightTue, 15 May 2007 10:36:00 GMThttp://www.aygfsteel.com/jx1984520/archive/2007/05/15/117669.htmlhttp://www.aygfsteel.com/jx1984520/comments/117669.htmlhttp://www.aygfsteel.com/jx1984520/archive/2007/05/15/117669.html#Feedback0http://www.aygfsteel.com/jx1984520/comments/commentRss/117669.htmlhttp://www.aygfsteel.com/jx1984520/services/trackbacks/117669.html 

一、术语session

  在我的经验里Qsessionq个词被滥用的程度大概仅ơ于transactionQ更加有的是transaction与session在某些语境下的含义是相同的?/p>

  sessionQ中文经常翻译ؓ会话Q其本来的含义是指有始有l的一pd动作/消息Q比如打电话时从拿v电话拨号到挂断电话这中间的一pdq程可以UCZ个session。有时候我们可以看到这L?#8220;在一个浏览器会话期间Q?..”Q这里的会话一词用的就是其本义Q是指从一个浏览器H口打开到关闭这个期间①。最混ؕ的是“用户Q客LQ在一ơ会话期?#8221;q样一句话Q它可能指用L一pd动作Q一般情况下是同某个具体目的相关的一pd动作Q比如从d到选购商品到结账登样一个网上购物的q程Q有时候也被称Z个transactionQ,然而有时候也可能仅仅是指一ơ连接,也有可能是指含义①,其中的差别只能靠上下文来推断②?/p>

  然而当session一词与|络协议相关联时Q它又往往隐含?#8220;面向q接”??#8220;保持状?#8221;q样两个含义Q?#8220;面向q接”指的是在通信双方在通信之前要先建立一个通信的渠道,比如打电话,直到Ҏ接了电话通信才能开始,与此相对的是写信Q在你把信发出去的时候你q不能确认对方的地址是否正确Q通信渠道不一定能建立Q但对发信h来说Q通信已经开始了?#8220;保持状?#8221;则是指通信的一方能够把一pd的消息关联v来,使得消息之间可以互相依赖Q比如一个服务员能够认出再次光的老顾客ƈ且记得上ơ这个顾客还Ơ店里一块钱。这一cȝ例子?#8220;一个TCP session”或?#8220;一个POP3 session”③?/p>

  而到了web服务器蓬勃发展的时代Qsession在web开发语境下的语义又有了新的扩展Q它的含义是指一cȝ来在客户端与服务器之间保持状态的解决Ҏ④。有时候session也用来指q种解决Ҏ的存储结构,?#8220;把xxx保存在session?#8221;⑤。由于各U用于web开发的语言在一定程度上都提供了对这U解x案的支持Q所以在某种特定语言的语境下Qsession也被用来指代该语a的解x案,比如l常把Java里提供的javax.servlet.http.HttpSessionUCؓsession⑥?/p>

  鉴于q种混ؕ已不可改变,本文中session一词的q用也会Ҏ上下文有不同的含义,请大家注意分辨?/p>

  在本文中Q用中?#8220;览器会话期?#8221;来表辑֐义①Q?#8220;session机制”来表辑֐义④Q?#8220;session”表达含义⑤,使用具体?#8220;HttpSession”来表辑֐义⑥

  二、HTTP协议与状态保?/p>

  HTTP协议本n是无状态的Q这与HTTP协议本来的目的是相符的,客户端只需要简单的向服务器h下蝲某些文gQ无论是客户端还是服务器都没有必要纪录彼此过ȝ行ؓQ每一ơ请求之间都是独立的Q好比一个顾客和一个自动售货机或者一个普通的Q非会员Ӟ大卖Z间的关系一栗?/p>

  然而聪明(或者贪心?Q的Z很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用Q就像给有线电视加上Ҏ功能一栗这U需求一斚wqHTML逐步d了表单、脚本、DOM{客L行ؓQ另一斚w在服务器端则出现了CGI规范以响应客L的动态请求,作ؓ传输载体的HTTP协议也添加了文g上蝲、cookieq些Ҏ。其中cookie的作用就是ؓ了解决HTTP协议无状态的~陷所作出的努力。至于后来出现的session机制则是又一U在客户端与服务器之间保持状态的解决Ҏ?/p>

  让我们用几个例子来描qC下cookie和session机制之间的区别与联系。笔者曾l常ȝ一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠Q然而一ơ性消?杯咖啡的Z微乎其微Q这时就需要某U方式来U录某位֮的消Ҏ量。想象一下其实也无外乎下面的几种ҎQ?/p>

  1、该店的店员很厉宻I能记住每位顾客的消费数量Q只要顾客一走进咖啡店,店员q道该怎么对待了。这U做法就是协议本w支持状态?/p>

  2、发l顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每ơ消ҎQ如果顾客出C张卡片,则此ơ消费就会与以前或以后的消费相联pv来。这U做法就是在客户端保持状态?/p>

  3、发l顾客一张会员卡Q除了卡号之外什么信息也不纪录,每次消费Ӟ如果֮出示该卡片,则店员在店里的纪录本上找到这个卡号对应的U录d一些消费信息。这U做法就是在服务器端保持状态?/p>

  ׃HTTP协议是无状态的Q而出于种U考虑也不希望使之成ؓ有状态的Q因此,后面两种Ҏ成为现实的选择。具体来说cookie机制采用的是在客L保持状态的ҎQ而session机制采用的是在服务器端保持状态的Ҏ。同时我们也看到Q由于采用服务器端保持状态的Ҏ在客L也需要保存一个标识,所以session机制可能需要借助于cookie机制来达C存标识的目的Q但实际上它q有其他选择?/p>

  三、理解cookie机制

  cookie机制的基本原理就如上面的例子一L单,但是q有几个问题需要解冻I“会员?#8221;如何分发Q?#8220;会员?#8221;的内容;以及客户如何使用“会员?#8221;?/p>

  正统的cookie分发是通过扩展HTTP协议来实现的Q服务器通过在HTTP的响应头中加上一行特D的指示以提C浏览器按照指示生成相应的cookie。然而纯_的客户端脚本如JavaScript或者VBScript也可以生成cookie?/p>

  而cookie的用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器查所有存储的cookieQ如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置Q则把该cookie附在h资源的HTTPh头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示Q如果某家分店还发行了自q会员卡,那么q这家店的时候除了要出示麦当劳的会员卡,q要出示q家店的会员卡?/p>

  cookie的内容主要包括:名字Q|q期旉Q\径和域?/p>

  其中域可以指定某一个域比如.google.comQ相当于d招牌Q比如宝z公司,也可以指定一个域下的具体某台机器比如www.google.com或者froogle.google.comQ可以用飘柔来做比?/p>

  路径是跟在域名后面的URL路径Q比?或?foo{等Q可以用某飘柔专柜做比?/p>

  路径与域合在一起就构成了cookie的作用范围?/p>

javabright 2007-05-15 18:36 发表评论
]]>
林信良版Spring技术手册遇到的问题QSpringHibernateDemoQ?/title><link>http://www.aygfsteel.com/jx1984520/archive/2007/04/15/110778.html</link><dc:creator>javabright</dc:creator><author>javabright</author><pubDate>Sun, 15 Apr 2007 07:17:00 GMT</pubDate><guid>http://www.aygfsteel.com/jx1984520/archive/2007/04/15/110778.html</guid><wfw:comment>http://www.aygfsteel.com/jx1984520/comments/110778.html</wfw:comment><comments>http://www.aygfsteel.com/jx1984520/archive/2007/04/15/110778.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.aygfsteel.com/jx1984520/comments/commentRss/110778.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/jx1984520/services/trackbacks/110778.html</trackback:ping><description><![CDATA[林信良版Spring技术手册第6章,在Spring中整合Hibernate,遇到如下错误Q?br><br><span>Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory<br> at org.springframework.context.support.AbstractApplicationContext.<init>(AbstractApplicationContext.java:127)<br> at org.springframework.context.support.AbstractApplicationContext.<init>(AbstractApplicationContext.java:159)<br> at org.springframework.context.support.AbstractRefreshableApplicationContext.<init>(AbstractRefreshableApplicationContext.java:66)<br> at org.springframework.context.support.AbstractXmlApplicationContext.<init>(AbstractXmlApplicationContext.java:49)<br> at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:79)<br> at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:67)<br> at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:58)<br> at onlyfun.caterpillar.SpringHibernateDemo.main(SpringHibernateDemo.java:10)<br><br><span>相关环境Q?br>Spring 1.2<br>Hibernate3<br>Eclipse 3.1<br>MyEclipse 3.9<br><br>代码Q配|环境都是按照书上的Qcommons-longing.jar已经加入cd中,log4j.properties文g也已l考进去,q且同样的代码在更高的Eclipse和myeclipse中能够顺利运行。网上相关的解决Ҏ都是说commons-longing.jar包没加,有一位也提到~辑环境的关p,但是却没有给出相应的解决Ҏ?br><br>希望大家l过门口的时候多多帮忙,在此留下你的Q谢谢!</span></span> <img src ="http://www.aygfsteel.com/jx1984520/aggbug/110778.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/jx1984520/" target="_blank">javabright</a> 2007-04-15 15:17 <a href="http://www.aygfsteel.com/jx1984520/archive/2007/04/15/110778.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank">Զ</a>| <a href="http://" target="_blank">կ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">¸</a>| <a href="http://" target="_blank">֣</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ȫ</a>| <a href="http://" target="_blank">ֿ</a>| <a href="http://" target="_blank">ʼ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">΢ɽ</a>| <a href="http://" target="_blank">Ԫı</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ո</a>| <a href="http://" target="_blank">ݸ</a>| <a href="http://" target="_blank">ͭɽ</a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank">ϰ</a>| <a href="http://" target="_blank">׶</a>| <a href="http://" target="_blank">ǿ</a>| <a href="http://" target="_blank">º</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ʲ</a>| <a href="http://" target="_blank">½</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Դ</a>| <a href="http://" target="_blank">Ĵʡ</a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɼ</a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank">կ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>