﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-j2ee绿洲-文章分类-Portlet</title><link>http://www.blogjava.net/livery/category/27286.html</link><description>找到属于自己的一片天空</description><language>zh-cn</language><lastBuildDate>Tue, 13 Nov 2007 12:47:57 GMT</lastBuildDate><pubDate>Tue, 13 Nov 2007 12:47:57 GMT</pubDate><ttl>60</ttl><item><title>框架构建Portlet应用</title><link>http://www.blogjava.net/livery/articles/160096.html</link><dc:creator>心情经纬</dc:creator><author>心情经纬</author><pubDate>Tue, 13 Nov 2007 01:08:00 GMT</pubDate><guid>http://www.blogjava.net/livery/articles/160096.html</guid><wfw:comment>http://www.blogjava.net/livery/comments/160096.html</wfw:comment><comments>http://www.blogjava.net/livery/articles/160096.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/livery/comments/commentRss/160096.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/livery/services/trackbacks/160096.html</trackback:ping><description><![CDATA[<p>2005 年 8 月 18 日</p>
<blockquote>在最近的Web应用开发中，Hibernate，Spring，Struts框架做为开源的轻量级框架，正被越来越多的开发者使
用，而如何将这些框架集成起来，应用到WebSphere
Portlet开发中去，将是本文讨论的内容。本文还描述了将这些框架应用到Portlet上的时候，遇到的一些细节问题。</blockquote>
<p><font size="4">引言</font></p>
<p>Hibernate是最近比较流行的一个用来处理O/R
Mapping的持久层框架。它的工作原理是通过文件把值对象和数据库表之间建立起一个映射关系，这样，我们只需要通过操作这些值对象和
Hibernate提供的一些基本类，就可以达到使用数据库的目的。使用Hibernate可以很好的将持久层和逻辑层进行隔离。请参阅参考资料一节获得
更多Hibernate框架的信息。</p>
<p>Spring框架是一个包含了MVC层，中间层和持久层管理的框架，其核心模块是bean管理，现在很多的应用都采用Spring的bean管理机制来管理其逻辑层。请参阅参考资料一节获得更多Spring框架的信息。</p>
<p>Struts框架是Apache Jakarta项目的一部分，它为构建Web应用程序提供了很流行的MVC框架。WebSphere
Portal V5提供了Struts
Portlet框架，这个框架针对Portlet应用，将Struts的类包和taglib在URL生成，URL解析等处，做了自己的改写，使
Portlet框架也可以支持Struts应用，将其作为Portlet来部署。</p>
<p>本文将通过构建一个使用Hibernate，Spring，Struts框架的Portlet应用，来描述如何在Portlet应用中使用这些框
架。对于那些并不熟悉使用这些框架进行开发的Web应用程序的读者来说，本文提供了足够的信息使您可以掌握一些基础知识。但本文并不是一篇介绍如何使用这
些框架的教程。</p>
<p>在本文中讨论的应用程序的开发或部署中用到了以下产品：<br />
WebSphere Portal 5.0.2.2<br />
WebSphere Studio Application Developer 5.1.2</p>
<p>请您注意！如果您的部署服务器Portal
Server的版本低于5.0.2.2，您在部署web.xml的时候，在过滤器设置上将会遇到问题导致不能部署，从而无法通过设置过滤器来解决应用程序
的中文问题。如果您的开发环境低于WebSphere Studio Application Developer
5.1.2，您可能不能得到本文中所述的Struts Portlet的全部支持。</p>
<br />
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%" /></td>
        </tr>
    </tbody>
</table>
<table align="right" cellpadding="0" cellspacing="0">
    <tbody>
        <tr align="right">
            <td>
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16" /><br />
                        </td>
                        <td align="right" valign="top"><br />
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><font size="4">示例应用程序</font></p>
<p>我们的示例应用程序将实现对一组持久数据的标准的创建、读取、更新、删除(Create/Read/Update/Delete，CRUD)操作。这个示例应用程序为一个新闻编辑程序，用户可以在列表中查看新闻，并新建，修改，删除新闻。</p>
<p>虽然这个示例应用程序是一个比较简单的应用，但为了更好的阐述Hibernate，Spring和Struts的作用范围，我们还是将这个应用程序进行分层的阐述：</p>
<p><strong><font size="3">应用程序的分层</font></strong></p>
<p>和通常大多数的Web应用程序一样，本应用程序分为四层，这四层是：presentation（描述），business（业务），persistence（持久）和domain model（域模型）。</p>
<p><strong><font size="3">表示层(The Presentation Layer) </font></strong></p>
<p>一般来讲，一个典型的Web应用的的末端应该是表示层。用来管理用户的请求，做出相应的响应，给出显示。在这里，我们使用了Struts Portlet框架来实现本应用程序的表示层。</p>
<p><strong><font size="3">域模型层（The Domain Model Layer ）</font></strong></p>
<p>域模块层由实际需求中的业务对象组成，即我们常说的BO（Business Object） 比如, Order , Pet等等。
开发者在这层 不用管那些DTOs，仅关注domain object即可。
例如，Hibernate允许你将数据库中的信息存放入对象（domain objects），这样你可以在连接断开的情况下把这些数据显示到UI层。
而那些对象也可以返回给持久层，从而在数据库里更新。</p>
<p><strong><font size="3">业务层（The Business Layer）</font></strong></p>
<p>一个典型Web应用的中间部分是业务层或者服务层。这一层最容易受到忽视，从而导致大量的代码紧密的耦合在一起，从而使整个程序变的难以维护。在这
里，我们使用Spring框架来解决这个问题，Spring把程序中所涉及到包含业务逻辑和Dao？的Objects--例如transaction
management handler（事物管理控制）、Object Factories(对象工厂)、service
objects（服务组件）--都通过XML来配置联系起来，从而使业务层变得非常灵活和易于维护。</p>
<p><strong><font size="3">持久层(The Persistence Layer)</font></strong></p>
<p>持久层是我们典型的Web应用的另一个末端。现在已经有很多很好的ORM开源框架来解决持久层的各种问题，尤其是Hibernate。
Hibernate为Java提供了OR持久化机制和查询服务, 它还给已经熟悉SQL和JDBC API
的Java开发者一个学习桥梁，他们学习起来很方便。 Hibernate的持久对象是基于POJO和Java collections。</p>
<p><strong><font size="3">前期准备工作</font></strong></p>
<p>1. 打开WSAD，点击 文件－新建－其他，在弹出的对话框左边选择Portlet开发，右边选择Portlet项目。如图1： </p>
<br />
<strong>图1</strong><br />
<img alt="图1" src="http://www-128.ibm.com/developerworks/cn/websphere/library/techarticles/guorui/images/image002.jpg" border="0" height="537" width="660" /><br />
<p>2. 点下一步，在项目名中输入Sample，类型选择Struts
Portlet，如果没有需要配置的高级选项，点击完成。这样，就创建了一个设置为使用 WebSphere Portal Server 所包括的
Struts Portlet Framework 的 Portlet。如图2：</p>
<br />
<strong>图2</strong><br />
<img alt="图2" src="http://www-128.ibm.com/developerworks/cn/websphere/library/techarticles/guorui/images/image004.jpg" border="0" height="521" width="553" /><br />
<p>3.
建立目录结构。在刚建的Sample项目上点右键，选择属性－JAVA构建路径－源，选中Sample/JavaSource，选中'除去'，将这个目录
从构建路径中清除。点击'添加文件夹'，在JavaSource下创建目录：dao,service,web，并将这三个目录添加到构建路径中。在下面的
步骤中，我们将在dao目录下放置和持久层相关的代码，在service目录下放置业务层相关的代码，在web目录下放置struts相关的
action，form代码。在Sample目录下建立Test目录，Test目录下建立dao，service目录。我们将在Test/dao下放置
dao层的JUnit测试代码，在Test/service下放置service层的JUnit测试代码。如图3：</p>
<br />
<strong>图3</strong><br />
<img alt="图3" src="http://www-128.ibm.com/developerworks/cn/websphere/library/techarticles/guorui/images/image006.jpg" border="0" height="406" width="553" /><br />
<p>4. 配置环境变量将附件中lib目录下的文件，全部拷贝到Sample项目的对象lib目录下，并在构建路径中完成类路径设置。</p>
<p>5.
配置数据库。在附件中，你可以找到两个文件，分别名为build.xml和build.properties，将其拷贝到Sample应用的根目录下。修
改build.properties文件中关于数据库的设置，包括数据库用户名，数据库密码，数据库名，数据库驱动类名，连接数据库的URL，以及
Hibernate需要使用的数据库Dialect类名。将其设置为你的测试环境数据库一致即可。默认的数据库设置为MySql。</p>
<br />
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%" /></td>
        </tr>
    </tbody>
</table>
<table align="right" cellpadding="0" cellspacing="0">
    <tbody>
        <tr align="right">
            <td>
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16" /><br />
                        </td>
                        <td align="right" valign="top"><br />
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><font size="4">创建域模型层</font></p>
<p>这层是编码的着手点，我们的编码就从这层开始。 本应用中的Domain Object比较简单，只使用了一个对象：com.ibm.sample.bo.InfoObject.java。</p>
代码清单 ： <br />
<br />
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code><br />
            <font face="Lucida Console">package com.ibm.sample.bo;<br />
            public class InfoObject {<br />
            private Long infoId;<br />
            private String title;<br />
            private String content;<br />
            }<br />
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>infoId记录了这个InfoObject对象的唯一标识，title记录了新闻标题,content记录了新闻内容。</p>
<p><strong><font size="3">创建持久层</font></strong></p>
<p><strong>1． 持久化BO。</strong> Hibernate是通过POJO工作的，
因此我们先给InfoObject对象的fileds
加上getter,setter方法。Hibernate通过XML文件来映射(OR)对象，在这里，我们使用XDoclet工具来生成
hibernate的XML映射文件。为了使用Xdoclet这个工具，我们需要在BO对象的代码里面添加一些描述语句。修改后的BO对象代码如下：</p>
<br />
<strong>代码清单2：</strong><br />
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code><br />
            <font face="Lucida Console">package com.ibm.sample.bo;<br />
            /**<br />
            * @author rayguo  mail:guorui@cn.ibm.com<br />
            *<br />
            * @hibernate.class table="InfoObject"<br />
            *<br />
            */<br />
            public class InfoObject {<br />
            private Long infoId;<br />
            private String title;<br />
            private String content;<br />
            /**<br />
            * Returns the Content.<br />
            * @return String<br />
            *<br />
            * @hibernate.property<br />
            * @hibernate.column name="Content" not-null="false"<br />
            *  length="3000"<br />
            */<br />
            public String getContent() {<br />
            return content;<br />
            }<br />
            /**<br />
            * Returns the id.<br />
            * @return Long<br />
            *<br />
            * @hibernate.id column="infoId"<br />
            *  generator-class="native"<br />
            */<br />
            public Long getInfoId() {<br />
            return infoId;<br />
            }<br />
            /**<br />
            * Returns the Title.<br />
            * @return String<br />
            *<br />
            * @hibernate.property<br />
            * @hibernate.column name="title" not-null="true"<br />
            *  length="200"<br />
            */<br />
            public String getTitle() {<br />
            return title;<br />
            }<br />
            public void setContent(String string) {<br />
            content = string;<br />
            }<br />
            public void setInfoId(Long long1) {<br />
            infoId = long1;<br />
            }<br />
            public void setTitle(String string) {<br />
            title = string;<br />
            }<br />
            }<br />
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>在类名前的注释@hibernate.class table="InfoObject"，表明了这个类将被映射到数据库表InfoObject，在get方法前的注释，表明了每个属性在数据库表中的对应字段。</p>
<p><strong>2.运行Ant的XDoclet任务，生成InfoObject.hbm.xml文件。</strong>在WSAD中右键点击build.xml文
件，并选择"运行Ant"，运行其中的hibernatedoclet任务，将会在classes目录下生成所需要的
InfoObject.hbm.xml文件。在这个文件中，还定义了用来生成数据库表结构的任务，将在下面做详细说明。</p>
<p><strong>3．创建DAO接口。</strong>为了程序的扩展性，我们首先需要创建一个提供数据访问服务的接口层，定义出对外的访问接口，在本示例中，为IInfoObjectDAO，代码如下：</p>
<br />
<strong>代码清单3：</strong><br />
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code><br />
            <font face="Lucida Console">package com.ibm.sample.dao;<br />
            public interface IInfoObjectDAO {<br />
            public abstract InfoObject saveInfoObject(InfoObject info);<br />
            public abstract InfoObject getInfoObjectById(Long infoId);<br />
            public abstract List getAllInfoObjects();<br />
            public abstract void removeInfoObject(Long infoId);<br />
            }<br />
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>这个接口定义了对InfoObject的RUCD各项操作。</p>
<p>4． <strong>创建DAO层的实现。</strong>本示例的DAO层实现，我们采用了Hibernate，按通常的实现，我们需要先得到Hibernate
的session对象，然后调用session对象的save,delete,update等方法来实现对数据对象的CRUD操作，但由于Spring框
架已经提供了对Hibernate框架的良好支持，使我们不再需要再头痛于Hibernate的session管理，事务管理等方面，这些Spring框
架已经进行了很好的封装，我们只需要将我们的Hibernate实现类继承HibernateDaoSupport类，然后通过调用
HibernateTemplate类上的方法，就可以实现我们需要的数据对象访问的操作。代码如下：</p>
<br />
<strong>代码清单4：</strong><br />
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code><br />
            <font face="Lucida Console">package com.ibm.sample.dao.hibernate;<br />
            public class InfoObjectDAOHibernate extends<br />
            HibernateDaoSupport implements IInfoObjectDAO {<br />
            public InfoObjectDAOHibernate(){<br />
            super();<br />
            }<br />
            public InfoObject saveInfoObject(InfoObject info) {<br />
            getHibernateTemplate().saveOrUpdate(info);<br />
            return info;<br />
            }<br />
            public InfoObject getInfoObjectById(Long infoId){<br />
            InfoObject info =<br />
            (InfoObject) getHibernateTemplate().load(InfoObject.class, infoId);<br />
            return info;<br />
            }<br />
            public void removeInfoObject(Long infoId) {<br />
            InfoObject info = getInfoObjectById(infoId);<br />
            getHibernateTemplate().delete(info);<br />
            }<br />
            public List getAllInfoObjects() {<br />
            return getHibernateTemplate().loadAll(InfoObject.class);<br />
            }<br />
            }<br />
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>5．<strong>通过配置，将Spring框架与Hibernate框架结合使用。</strong><br />
如果你以前使用过Hibernate，你现在该感到有些迷惑：使用Hibernate框架的时候，需要提供的hibernate.cfg.xml配置文件
应该放在哪里呢？为了使Spring框架能够真正的感知到Hibernate对象，为其添加事务管理，SessionFactory管理等功能，我们需要
添加一个Spring的配置文件，而且，Spring提供了一个便捷的方式-----在Spring内部配置中并入了Hibernate的
hibernate.cfg.xml配置文件。首先在Sample项目的JavaSource/dao目录下，建立文件
applicationContext-hibernate.xml，在文件中添加如下内容：</p>
<br />
<strong>代码清单5：</strong><br />
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code><br />
            <font face="Lucida Console">&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
            &lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"&gt;<br />
            &lt;beans&gt;<br />
            &lt;!-- ==================== Start of PERSISTENCE DEFINITIONS ================== --&gt;<br />
            &lt;bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"<br />
            destroy-method="close"&gt;<br />
            &lt;property name="driverClassName"&gt;<br />
            &lt;value&gt;com.mysql.jdbc.Driver&lt;/value&gt;<br />
            &lt;/property&gt;<br />
            &lt;property name="url"&gt;<br />
            &lt;value&gt;jdbc:mysql://localhost:3306/infos&lt;/value&gt;<br />
            &lt;/property&gt;<br />
            &lt;property name="username"&gt;<br />
            &lt;value&gt;root&lt;/value&gt;<br />
            &lt;/property&gt;<br />
            &lt;property name="password"&gt;<br />
            &lt;value&gt;&lt;/value&gt;<br />
            &lt;/property&gt;<br />
            &lt;/bean&gt;<br />
            &lt;!-- Choose the dialect that matches your "dataSource" definition --&gt;<br />
            &lt;bean id="mySessionFactory"<br />
            class="org.springframework.orm.hibernate.LocalSessionFactoryBean"&gt;<br />
            &lt;property name="dataSource"&gt;<br />
            &lt;ref local="dataSource" /&gt;<br />
            &lt;/property&gt;<br />
            &lt;property name="mappingResources"&gt;<br />
            &lt;list&gt;<br />
            &lt;value&gt;com/ibm/sample/bo/InfoObject.hbm.xml&lt;/value&gt;<br />
            &lt;/list&gt;<br />
            &lt;/property&gt;<br />
            &lt;property name="hibernateProperties"&gt;<br />
            &lt;props&gt;<br />
            &lt;prop<br />
            key="hibernate.dialect"&gt;net.sf.hibernate.dialect.MySQLDialect&lt;/prop&gt;<br />
            &lt;/props&gt;<br />
            &lt;/property&gt;<br />
            &lt;/bean&gt;<br />
            &lt;!-- DAO object: Hibernate implementation --&gt;<br />
            &lt;bean id="infoObjectDAO"<br />
            class="com.ibm.b2e.app.itsubsystem.dao.hibernate.InfoObjectDAOHibernate"&gt;<br />
            &lt;property name="sessionFactory"&gt;&lt;ref<br />
            local="mySessionFactory"/&gt;&lt;/property&gt;<br />
            &lt;/bean&gt;<br />
            &lt;/beans&gt;<br />
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>Spring的核心功能就是Bean管理，在这个配置文件中，我们配置了3个Java对象，id分别为：dataSource,
mySessionFactory和infoObjectDAO。mySessionFactory的dataSource属性引用了
dataSource对象，infoObjectDAO的sessionFactory属性又引用了mySessionFactory对象。在
Spring框架启动的时候，会自动的根据这个配置文件，生成相应的对象，并将生成的对象注入到对应的属性中去，这就是所谓的"依赖注入"
（dependency injection）。通过这样的方式，可以将我们从 单例模式（singleton
objects）和工厂模式（factories）中解放出来，降低代码的维护成本。在这里，mySessionFactory中配置的属性，对应于
Hibernate的hibernate.cfg.xml配置文件。</p>
<p>dataSource中的属性设置是针对MySql数据库的，你需要将其改成与你的测试环境数据库一致。</p>
<p>好了,至此，我们完成了示例应用的DAO层创建工作，是不是感到有些心神不宁？是的，虽然我们用的不是测试驱动开发（Test Driver Development），可现在也该写点测试用例来测试一下我们刚刚新建的DAO层了。</p>
<p><strong><font size="3">建立JUnit单元测试来测试DAO层</font></strong></p>
<p>1． 测试前的数据准备工作。</p>
<p>如果你使用的是MySql数据库，运行ant任务setup-db，此任务将创建一个名为infos的数据库，并在数据库中建立数据表
infoobject。如果你使用的不是MySql数据库，你需要手工建立测试数据库，然后运行ant任务db-prepare，将会在数据库中自动建立
表infoobject。</p>
<p>2． 编写单元测试基类</p>
<br />
<strong>代码清单6：</strong><br />
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code><br />
            <font face="Lucida Console">package com.ibm.sample.dao;<br />
            public class BaseDAOTestCase extends TestCase{<br />
            protected final static XmlBeanFactory factory ;<br />
            static {<br />
            Resource rs1 = new ClassPathResource("applicationContext-hibernate.xml");<br />
            factory = new XmlBeanFactory(rs1);<br />
            }<br />
            }<br />
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>这个基类非常简单，完成的功能就是通过读入Spring的配置文件，构建一个Spring的bean管理工厂，通过将这段代码包含在静态段中，可以确保Spring的Bean工厂对所有的测试只装载了一次。</p>
<p>3． 编写DAO的单元测试</p>
<p>本示例中用到的对InfoObjectDAO进行测试的类为InfoObjectDAOTest，具体代码可以查看附件中的
InfoObjectDAOTest.java类代码。测试覆盖了InfoObject的各个方法，你可以简单的将其拷贝到自己的项目中并运行，如果数据
库都配置正确的话，你将看到绿色的状态条，OK，测试通过，我们的DAO层已经可以顺利运行了，下面我们进入业务层代码的编写。</p>
<p><strong><font size="3">创建业务层</font></strong></p>
<p>现在，我们需要来构建我们的BSO（business service
objects）了，用来执行程序的逻辑,调用持久层，得到UI层的requests,处理transactions，并且控制exceptions。
在这里，我们将使用Spring框架，很快，你就会感受到使用Spring框架来管理业务层，将给你的应用程序带来极大的灵活性，和更松散的耦合度。</p>
<p>1． 建立业务服务对象接口</p>
<p>首先我们需要做的，还是要定义出我们在业务层提供的接口。在Spring框架中，任何注册到Spring框架中的bean，如果实现了某个接口，那
么在得到这个bean的时候，只能将其下溯造型成其接口进行操作，而不能直接下溯造型成具体的类型进行操作。原因在于Spring的AOP实现机制，
Spring中的Bean管理实际上是基于动态AOP机制实现，为了实现动态AOP，Spring在默认情况下会使用Java Dynamic
Proxy，但是，Dynamic Proxy要求其代理的对象必须实现一个接口，该接口定义了准备进行代理的方法。而对于没有实现任何接口的Java
Class，需要采用其他方式，Spring通过CGLib实现这一功能。当类实现了一个接口之后，Spring将通过Java Dynamic
Proxy机制实现代理功能，此时返回的Bean，是通过java.lang.reflect.Proxy.newProxyInstance方法创建的
其接口的一个代理实现，这个实例实现了其接口，但与类已经没有继承关系，因此无法通过下溯造型进行强制转型，如果进行转换，则会抛出异常。这也就强制要求
编程人员要面向接口编程，使程序员能够从接口的角度考虑程序设计，从而降低了程序的耦合度。</p>
<br />
<strong>代码清单7：</strong><br />
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code><br />
            <font face="Lucida Console">package com.ibm.sample.service;<br />
            public interface IInfoObjectService {<br />
            public abstract InfoObject saveInfoObject(InfoObject infoObject) throws InfoObjectException;<br />
            public abstract InfoObject findInfoObjectById(Long id) throws InfoObjectException;<br />
            public abstract List findAllInfoObjects() throws InfoObjectException;<br />
            public abstract void removeInfoObject(Long deleteId) throws InfoObjectException;<br />
            public abstract void setInfoObjectDAO(IInfoObjectDAO infoObjectDAO);<br />
            }<br />
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>通过接口可以看到，在业务层对底层的Exception进行了捕捉，并进行了统一的封装，再用定义好的业务服务级别的Exception抛出。注意
到这段代码里有一个 setInfoObjectDAO()，它就是一个DAO Object设置方法，将DAO的实现注射到Service对象中。
但这里并没有一个getInfoObjectDao的方法，这不必要，因为并不会在外部访问这个DAO。Service层将调用这个DAO
Object和持久层通信。我们将用Spring把DAO Object 和 business service
object搭配起来的。因为我们是面向接口编程的，所以并不需要将实现类紧密的耦合在一起。</p>
<p>2．
实现业务服务对象接口，并通过Spring将其和DAO对象关联起来因为本例比较简单，所以接口的实现也很简单，并没有什么复杂的操作，通过调用
InfoObjectDAO对象上的方法，就可以实现服务对象接口，具体的代码见附件中的com.ibm.sample.service.impl.
InfoObjectServiceImpl.java文件。我们主要需要关注的是如何通过Spring将业务对象与DAO对象关联起来，并实现事务。在
Spring的配置文件中添加如下代码：</p>
<br />
<strong>代码清单8：</strong><br />
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code><br />
            <font face="Lucida Console">		&lt;!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) --&gt;<br />
            &lt;bean id="myTransactionManager"<br />
            class="org.springframework.orm.hibernate.HibernateTransactionManager"&gt;<br />
            &lt;property name="sessionFactory"&gt;&lt;ref local="mySessionFactory"/&gt;<br />
            &lt;/property&gt;<br />
            &lt;/bean&gt;<br />
            &lt;!-- ***** InfoObject SERVICE *****--&gt;<br />
            &lt;bean id="infoObjectService"<br />
            class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"&gt;<br />
            &lt;property name="transactionManager"&gt;&lt;ref<br />
            local="myTransactionManager"/&gt;&lt;/property&gt;<br />
            &lt;property name="target"&gt;&lt;ref local="infoObjectTarget"/&gt;&lt;/property&gt;<br />
            &lt;property name="transactionAttributes"&gt;<br />
            &lt;props&gt;<br />
            &lt;prop key="find*"&gt;PROPAGATION_REQUIRED,readOnly,-InfoObjectException<br />
            &lt;/prop&gt;<br />
            &lt;prop key="save*"&gt;PROPAGATION_REQUIRED,-InfoObjectException&lt;/prop&gt;<br />
            &lt;/props&gt;<br />
            &lt;/property&gt;<br />
            &lt;/bean&gt;<br />
            &lt;!-- InfoObjectTarget primary business object implementation --&gt;<br />
            &lt;bean id="infoObjectTarget" class="com.ibm.sample.service.impl. InfoObjectServiceImpl"&gt;<br />
            &lt;property name="infoObjectDAO"&gt;&lt;ref local="infoObjectDAO"/&gt;&lt;/property&gt;<br />
            &lt;/bean&gt;<br />
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>在这里， myTransactionManager引用了mySessionFactory bean。
本例使用一个TransactionProxyFactoryBean，它定义了一个属性transactionManager。
这个对象很有用，它能很方便的处理你申明的事物还有Service Object。你可以通过transactionAttributes
属性来定义怎样处理。TransactionProxyFactoryBean 还有个属性target. 这将会注入我们的 Business
service object（infoObjectTarget）引用， infoObjectTarget定义了
业务服务层，并且它还有个属性，将会注入我们的DAO对象(InfoObjectDAO)引用，通过这个配置，我们就将DAO对象和Service
Object对象关联了起来，并在Business
Service这一层提供了事务管理，在InfoObjectService中所有以find开头的方法，则以只读的事务处理机制进行处理。（设为只读型
事务，可以使持久层尝试对数据操作进行优化，如对于只读事务Hibernate将不执行flush操作，而某些数据库连接池和JDBC
驱动也对只读型操作进行了特别优化。）；而使用save开头的方法，将会纳入事务管理范围。如果此方法中抛出异常，则Spring将当前事务回滚，如果方
法正常结束，则提交事务。</p>
<p>在这里，我们的DAO层是使用Hibernate实现的，如果我们将DAO层的实现技术改为JDBC，JDO，DAO等，只需要实现
IInfoObjectDAO接口，并在Spring配置文件里，将infoObjectDAO
bean的实现类名替换为新实现的类名即可，如此就可以将改动控制在最小的范围之内，不会因为DAO层的变化而引起程序结构大规模的改变，显得非常的灵
活，具有良好的可维护性。</p>
<p><strong><font size="3">建立表示层(The Presentation Layer)</font></strong></p>
<p>我们已经建立了应用程序的DAO层和Service层，现在我们需要做的就是将Service的接口暴露给表示层，使表示层能够调用到
Service层的接口，并将处理结果展现给用户。在这一层，我们在本示例中将使用Struts Portlet框架编写Portlet进行展现。</p>
<p>设计页面流程</p>
<p>我们先设计一下实现本示例功能的页面操作流程：</p>
<p>用户访问本示例Portlet后，首先看到的是新闻列表，点击新闻链接，可以查看新闻内容，点击新建按钮，进入新建新闻页面，可以新建新闻，选择新闻后，点击编辑新闻按钮，进入编辑新闻页面，可以编辑新闻，选择新闻后，点击删除按钮，可以删除新闻。</p>
<p>由此，我们可以设计出Struts框架下应用需要的元素：</p>
<p>FormBean 表单bean<br />
InfoObjectForm 我们在com.ibm.sample.web.forms包下建立InfoObjectForm类，用来记录一条新闻信息的Formbean对象<br />
Action 操作<br />
我们在 com.ibm.sample.web.actions 包中创建三个 Struts 操作。<br />
GetInfoObjectAction<br />
SaveInfoObjectAction<br />
ListInfoObjectsAction<br />
JSP<br />
ListInfoObjects.jsp ：展示新闻列表页面<br />
ViewInfoObject.jsp ： 查看新闻页面<br />
EditInfoObject.jsp ： 编辑新闻页面</p>
<p>整个应用的Web图如下：</p>
<br />
<strong>图4</strong><br />
<img alt="图4" src="http://www-128.ibm.com/developerworks/cn/websphere/library/techarticles/guorui/images/image008.jpg" border="0" height="418" width="553" /><br />
<p><strong><font size="3">实现表现层对Service层的访问</font></strong></p>
<p>1. 配置web.xml文件</p>
<p>为了实现表现层对Service层的调用，我们首先需要更改web.xml文件，在里面添加如下代码：</p>
<br />
<strong>代码清单9：</strong><br />
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code><br />
            <font face="Lucida Console">		&lt;context-param&gt;<br />
            &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;<br />
            &lt;param-value&gt;/WEB-INF/classes/applicationContext-hibernate.xml&lt;/param-value&gt;<br />
            &lt;/context-param&gt;<br />
            &lt;servlet id="servlet_12345"&gt;<br />
            &lt;servlet-name&gt;SpringContextServlet&lt;/servlet-name&gt;<br />
            &lt;servlet-class&gt;org.springframework.web.context.ContextLoaderServlet&lt;/servlet-class&gt;<br />
            &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;<br />
            &lt;/servlet&gt;<br />
            &lt;servlet-mapping&gt;<br />
            &lt;servlet-name&gt;SpringContextServlet&lt;/servlet-name&gt;<br />
            &lt;url-pattern&gt;/*&lt;/url-pattern&gt;<br />
            &lt;/servlet-mapping&gt;<br />
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>通过这样的配置，示例应用程序在启动的时候，会首先初始化Spring框架自带的ContextLoaderServlet，这个Servlet的
作用就是读取由contextConfigLocation指定的Spring配置文件的位置，初始化Spring框架的Context对象，并将这个对
象保存在ServletContext中，留待Action调用。</p>
<p>同时，为了解决中文输入问题，我们在web.xml中加入过滤器，过滤器的具体代码请见附件。</p>
<br />
<strong>代码清单10：</strong><br />
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code><br />
            <font face="Lucida Console">		&lt;filter&gt;<br />
            &lt;filter-name&gt;SetCharacterEncodingFilter&lt;/filter-name&gt;<br />
            &lt;display-name&gt;SetCharacterEncodingFilter&lt;/display-name&gt;<br />
            &lt;filter-class&gt;com.ibm.sample.web.filter.SetCharacterEncodingFilter&lt;/filter-class&gt;<br />
            &lt;init-param&gt;<br />
            &lt;param-name&gt;encoding&lt;/param-name&gt;<br />
            &lt;param-value&gt;GB2312&lt;/param-value&gt;<br />
            &lt;/init-param&gt;<br />
            &lt;init-param&gt;<br />
            &lt;param-name&gt;ignore&lt;/param-name&gt;<br />
            &lt;param-value&gt;true&lt;/param-value&gt;<br />
            &lt;/init-param&gt;<br />
            &lt;/filter&gt;<br />
            &lt;filter-mapping&gt;<br />
            &lt;filter-name&gt;SetCharacterEncodingFilter&lt;/filter-name&gt;<br />
            &lt;url-pattern&gt;/SetCharacterEncodingFilter&lt;/url-pattern&gt;<br />
            &lt;/filter-mapping&gt;<br />
            &lt;filter-mapping&gt;<br />
            &lt;filter-name&gt;SetCharacterEncodingFilter&lt;/filter-name&gt;<br />
            &lt;servlet-name&gt;action&lt;/servlet-name&gt;<br />
            &lt;/filter-mapping&gt;<br />
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>2．定义BaseAction</p>
<br />
<strong>代码清单11：</strong><br />
<table bgcolor="#eeeeee" border="1" cellpadding="5" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td>
            <pre><code><br />
            <font face="Lucida Console">public class BaseAction  extends StrutsAction{<br />
            protected transient final Log log = LogFactory.getLog(getClass());<br />
            private static WebApplicationContext wac = null;<br />
            public Object getBean(String name) {<br />
            return wac.getBean(name);<br />
            }<br />
            public void setServlet(ActionServlet actionServlet) {<br />
            super.setServlet(actionServlet);<br />
            ServletContext servletContext = actionServlet.getServletContext();<br />
            wac =<br />
            WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);<br />
            }<br />
            }<br />
            </font></code></pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p>可以看到，在BaseAction中，维持了一个WebApplicationContext对象，通过调用这个对象的getBean方法，传入配置文件中的bean id，我们就可以定位到这个bean，也就是我们前面定义的业务层的各种服务。</p>
<p>在这里，我们的Action继承自StrutsAction，这个类继承自Struts框架中的Action类，其作用在Portlet
Struts框架中与Action类在Struts框架中的作用类似。我们需要通过重载其public ActionForward
execute(ActionMapping mapping,ActionForm form,PortletRequest
request)throws
Exception方法来实现我们自己的Action类。与Struts框架中的Action类相比，可以发现这个方法的参数中取消了Response对
象，使我们无法简单的引用到，这个设计是由于IBM的WebSphere Portal Server的Portlet框架设计引起的，Portlet
处理分两阶段实现，操作阶段和呈现阶段。操作处理在呈现显示视图之前执行。在操作阶段，只有请求对象才会被传递给
portlet，而响应对象则不会传递，一些在操作阶段提供的信息（即请求参数）在呈现阶段不再可用。另外，因为在 portlet
没有新的事件发生时，刷新 portlet 页面时会调用呈现方法（如
doView()），因此所有呈现该页面所需的信息必须在每次调用该方法时可用，这就意味着，所有需要呈现的信息，都需要保存在
PortletSession对象中，而不能保存在PortletRequest对象中，如果保存在Request对象中，在刷新页面的时候，会因为没有
可用的变量而导致页面出错。</p>
<p>Action类的具体实现，请参见<font color="#5c81a7">附件中的代码文件</font>。</p>
<p>整个项目文件结构图：</p>
<br />
<br />
<img alt="" src="http://www-128.ibm.com/developerworks/cn/websphere/library/techarticles/guorui/images/image009.jpg" border="0" height="896" width="459" /><br />
<br />
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tbody>
        <tr>
            <td><img alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" height="1" width="100%" /></td>
        </tr>
    </tbody>
</table>
<table align="right" cellpadding="0" cellspacing="0">
    <tbody>
        <tr align="right">
            <td>
            <table border="0" cellpadding="0" cellspacing="0">
                <tbody>
                    <tr>
                        <td valign="middle"><img alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" border="0" height="16" width="16" /><br />
                        </td>
                        <td align="right" valign="top"><br />
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<br />
<br />
<p><font size="4">结束语</font></p>
<p>本示例介绍了如何在 Portlet 开发中引入 Hibernate，Spring 和 Struts Portlet 框架，在下面的下载部分提供了本例的完整实现。<font color="#5c81a7">附件是本示例的war包</font>，其中已经包含了示例的源代码，可以直接将其导入WSAD中查看。</p>
<img src ="http://www.blogjava.net/livery/aggbug/160096.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/livery/" target="_blank">心情经纬</a> 2007-11-13 09:08 <a href="http://www.blogjava.net/livery/articles/160096.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Portlet入门</title><link>http://www.blogjava.net/livery/articles/160088.html</link><dc:creator>心情经纬</dc:creator><author>心情经纬</author><pubDate>Tue, 13 Nov 2007 00:49:00 GMT</pubDate><guid>http://www.blogjava.net/livery/articles/160088.html</guid><wfw:comment>http://www.blogjava.net/livery/comments/160088.html</wfw:comment><comments>http://www.blogjava.net/livery/articles/160088.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/livery/comments/commentRss/160088.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/livery/services/trackbacks/160088.html</trackback:ping><description><![CDATA[<p><span style="font-size: 20px;"><strong>Portlets <br />
</strong>&#8220;Portlets
是一种Web组件－就像servlets－是专为将合成页面里的内容聚集在一起而设计的。通常请求一个portal页面会引发多个portlets被调
用。每个portlet都会生成标记段，并与别的portlets生成的标记段组合在一起嵌入到portal页面的标记内。&#8221;（摘自Portlet规范，
JSR 168）<br />
<br />
本文探讨了以下内容：<br />
<span style="color: purple;">1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Portal页面的元素 <br />
2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Portal是什么？<br />
3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Portlets是什么？<br />
4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;开发&#8220;Hello World&#8221; Portlet<br />
5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在Pluto上部署HelloWorld Portlet<br />
6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如何创建Portal页面<br />
7.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;结束语 <br />
8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;资源</span><br />
<br />
Portlet规范将portlet定义为一种&#8220;基于Java技术的web组件，由处理请求和生成动态内容的portlet容器管理&#8221;。这段话听起来是不是有些费解？本文将说明portlets是什么以及能用它们做什么。<br />
<br />
<br />
图1显示了在访问一个portal服务器时浏览器中页面的样子。<br />
<br />
<img onmouseover="javascript:ImgShowTip(this);" style="display: inline;" onclick="javascript:ImgClick(this);" alt="image" src="http://www.matrix.org.cn/resource/upload/forum/2005_12_05_021236_BwaZOpizXk.gif" onload="javascript:ImgLoad(this);" border="0" width="600" /><br />
图1 典型的portal服务器的页面（点击查看原图）<br />
<br />
如果仔细查看浏览器里的页面，就会看到页面是由不同的&#8220;窗口&#8221;组成的。一个窗口用于刷新天气，另一个用于新闻，还有一个用于刷新股价，等等。这里的每一
个窗口都代表了一个portlets。如果看得再仔细些，还会发现每个窗口都有一个标题条和一些按钮，包括最小化和最大化按钮。<br />
<br />
在系
统里，这些窗口是相互独立开发、各不同的应用。新闻portlet的开发者创建应用并打包成war格式的文件,随后portal服务器的管理员在服务器上
部署该war文件并创建页面，接下来每个用户会选择在他的页面里有哪些应用。例如，如果用户对股价不感兴趣而对体育感兴趣，他可以用&#8220;体育&#8221;窗口替换&#8220;股
价&#8221;窗口。<br />
<br />
Portlet技术需要学习许多新概念，本文不可能全都涵盖，因此本文分为两部分。在第一部分里我们详细说明portals和portlets，并开发一个简单的&#8220;Hello World&#8221;portlet；在第二部分我们将探讨一些高级主题。<br />
<br />
我们将用Apache的Pluto服务器（Portlet API 1.0规范的参考实现）来测试我们的示例portlets，我们还会花些时间探讨如何安装和使用Pluto服务器。<br />
<br />
<strong><span style="font-size: 16px;">Portal页面的元素</span></strong><br />
<br />
图2显示了Portal页面的各种元素。<br />
<br />
<img onmouseover="javascript:ImgShowTip(this);" style="display: inline;" onclick="javascript:ImgClick(this);" alt="image" src="http://www.matrix.org.cn/resource/upload/forum/2005_12_05_021329_NzXorUBuvR.gif" onload="javascript:ImgLoad(this);" border="0" /><br />
图2 portal页面的元素<br />
<br />
每个portlet页面由一个或多个portlet窗口组成，每个portlet窗口又分为两部分：一个是外观，它决定了portlet窗口的标题条、控制和边界的样式；另一个是portlet段，它由portlet应用填充。<br />
<br />
Portal服务器决定了portal页面的整体观感，像标识、标题条颜色、控制图标等。通过修改几个JSP和css模板文件就可以改变portal的整个观感。我们将在&#8220;如何创建portal页面&#8221;部分对此做深入讨论。<br />
<br />
<strong><span style="font-size: 16px;">Portal是什么？</span></strong><br />
<br />
在了解portlet之前有必要先了解portal。在Portlet规范里是这样讲的：&#8220;portal是一种web应用，通常用来提供个性化、单次登
录、聚集各个信息源的内容，并作为信息系统表现层的宿主。聚集是指将来自各个信息源的内容集成到一个web页面里的活动&#8221;。<br />
<br />
Portal的功能可以分为三个主要方面：<br />
1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Portlet
容器：Portlet容器与servlet容器非常类似，所有的portlet都部署在portlet容器里，portlet容器控制portlet的生
命周期并为其提供必要的资源和环境信息。Portlet容器负责初始化和销毁portlets，向portlets传送用户请求并合成响应。<br />
2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;内容聚集：Portlet规范中规定portal的主要工作之一是聚集由各种portlet应用生成的内容，我们将在&#8220;如何创建Portal页面&#8221;部分对此做进一步讨论。<br />
3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;公共服务：portlet服务器的一个强项是它所提供的一套公共服务。这些服务并不是portlet规范所要求的，但portal的商业实现版本提供了丰富的公共服务以有别于它们的竞争者。在大部分实现中都有望找到的几个公共服务有：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o 单次登录：只需登录portal服务器一次就可以访问所有其它的应用，这意味着你无需再分别登录每一个应用。例如一旦我登录了我的intranet网站，我就能访问mail应用、IM消息应用和其它的intranet应用，不必再分别登录这些应用。<br />
Portal服务器会为你分配一个通行证库。你只需要在mail应用里设定一次用户名和密码，这些信息将以加密的方式存储在通行证库中。在你已登录到
intranet网站并要访问mail应用的时候，portal服务器会从通行证库中读取你的通行证替你登录到mail服务器上。你对其它应用的访问也将
照此处理。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;o个性化：个性化服务的基本实现使用户能从两方面个性化她的页面：第一，用户可以根据她的自身喜好决定标题条的颜
色和控制图标。第二，用户可以决定在她的页面上有哪些portlets。例如，如果我是个体育迷，我可能会用一个能提供我钟爱球队最新信息的
portlet来取代股票和新闻portlets。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;　　一些在个性化服务方面领先的商业实现版本允许你建立为用户显示什么样的应用所
依据的标准（如收入和兴趣）。在这种情况下，可以设定一些像&#8220;对任何收入为X的用户显示馈赠商品的portlet&#8221;和&#8220;对任何收入为X的用户显示打折商品
的portlet&#8221;这样的商业规则。<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;此外还有一些公共服务，比如机器翻译，是由portal服务器将portlet生成的内容翻译为用户要求的语言。大部分的商业portal服务器都支持手持设备访问并具有针对不同的浏览终端生成不同内容的能力。<br />
<br />
<strong><span style="font-size: 16px;">Portlets是什么？</span></strong><br />
<br />
与servlets类似，portlets是部署在容器内用来生成动态内容的web组件。从技术角度讲portlet是一个实现了javax.portlet.Portlet接口的类，它被打包成war文件格式部署到portlet容器里。<br />
<br />
Portlets在以下方面与servlets相似：<br />
1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;portlets由特定的容器管理。<br />
2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;portlets生成动态内容。<br />
3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;portlet的生命周期由容器管理。<br />
4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;portlets通过请求/响应模式与web客户端交互。<br />
<br />
Portlets在以下方面与servlets相异：<br />
1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;portlets只能生成标记段，而不是整个文档。<br />
2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;portlets没有可供直接访问的URL地址。不过你还是能够让别人通过URL访问到portlet，你可以把包含该portlet的页面的URL发给他。<br />
3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;portlets
不能随意地生成内容，这是因为portlet生成的内容最终要成为portal页面的一部分。如果portal服务器要求的是html/text类型，那
么所有的portlets都应生成html/text类型的内容。再比方说，如果portal服务器要求的是WML类型，那么所有的portlets都应
生成WML类型的内容。<br />
<br />
portlets还提供了一些附加的功能：<br />
1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;设置参数的持久化存储：portlets提供了一个PortletPreferences对象用来保存用户的设置参数。这些参数被存入一个持久化数据库，这样服务器重启后数据依然有效。开发者不必关心这些数据存储的具体实现机制。<br />
2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
请求处理：portlets提供了更为细粒度的请求处理。对于用户在portlet上动作时向该portlet发出的请求(一种称为活跃期的状态)，或者
因用户在其它portlet上动作而引发的刷新页面请求，Portal服务器提供了两种不同的回调方法来处理。<br />
3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Portlet
模式：portlets用模式的概念来表示用户在做什么。在使用mail应用的时候，你可能会用它来读信、写信或检查信件――这些都是mail应用的预定
功能，Portlets通常以VIEW模式提供这些功能。但还有一些活动，像指定刷新时间或（重新）设置用户名和密码，这些活动允许用户定制应用的行为，
因此它们用的是EDIT模式。Mail应用的帮助功能用的是HELP模式。<br />
<br />
如果仔细想想其实这里面并没有什么新东西，它们反而大部分都是普通的业务需求。Portlet规范的作用在于它提供了一个抽象层，这才是它对所有与之相关的人－最终用户、开发者和管理员－的价值所在。<br />
<br />
作为一个开发者，我会将所有与VIEW模式有关的业务逻辑放入doView()方法，将与应用配置有关的业务逻辑放入doEdit()方法，将与帮助有关的逻辑放入doHelp()方法<br />
<br />
这就简化了管理员对portlet应用的访问控制管理，因为他只需改变portlet的访问权限就能决定用户能做什么。例如，如果mail应用的一个用户能够在EDIT模式下设定用户名和密码，那么就可以断定他具有EDIT模式访问权限。<br />
<br />
不妨考虑这样一种情形：我是一个intranet网站的管理员，我的公司买了一个能显示新闻信息的第三方portlet应用，该应用允许用户指定跟踪新
闻更新的URL地址，我想借助它为用户显示公司的内部新闻。另一个需求是我不想让用户通过该应用来跟踪任何其它的新闻信息来源。作为管理员，我可以为所有
的用户指定一个用于内部新闻更新的URL地址，同时通过改变portlet应用的部署描述符来取消其它人修改该地址的权限。<br />
<br />
由于所有的portlet应用都具有相似的UI界面，因此采用portlets可使网站对最终用户更具吸引力。如果她想阅读任何一个应用的帮助信息，她可以点击帮助按钮；她也知道点击编辑按钮能让她进入应用的配置屏。标准化的用户界面使你的portlet应用更引人。<br />
<br />
4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
窗口状态：窗口状态决定了portal页面上留给portlet生成内容的空间。如果点击最大化按钮，portlet将占据整个屏幕，成为用户唯一可用的
portlet；而在最小化状态，portlet只显示为标题条。作为开发者应当根据可用空间的大小来定做内容。<br />
<br />
5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;用
户信息：通常portlets向发出请求的用户提供个性化的内容，为了能更加行之有效，portlets需要访问用户的属性信息，如姓名、email、电
话等。Portlet
API为此提供了用户属性的概念，开发者能够用标准的方式访问这些属性，并由管理员负责在这些属性与真实的用户信息数据库（通常是LDAP服务器）之间建
立映射关系。<br />
<br />
我们将在本文的第二部分深入讨论这些特点－请求处理、用户信息和portlet模式。<br />
<br />
<strong><span style="font-size: 16px;">开发"Hello World" Portlet</span></strong><br />
<br />
现在我们就来开发一个简单的HelloWorld portlet。<br />
1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;创建一个名为HelloWorld的web项目，它与通常的servlet项目类似，有一个/WEB-INF/web.xml文件作为项目的部署描述符。<br />
<br />
2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在build path里加入portlet-api-1.0.jar文件，该jar文件是Pluto发行包的一部分。<br />
<br />
3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在Source文件夹中按如下内容创建HelloWorld.java文件：<br />
</span></p>
<pre title="pre code">public class HelloWorld extends GenericPortlet{<br />
&nbsp;&nbsp;protected void doView(RenderRequest request,<br />
&nbsp;&nbsp;RenderResponse response) throws<br />
&nbsp;&nbsp;PortletException, IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.setContentType("text/html");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.getWriter().println("Hello Portlet");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</pre>
<p><br />
<br />
每个portlet都要实现Portlet接口，该接口为portlet定义了生命周期方法。由于不想覆盖所有这些方法，我们只对
GenericPortlet类进行扩展，它是一个实现了Portlet接口的适配器类。GenericPortlet类提供了所有生命周期方法的默认实
现，所以我们只需实现我们所需要的方法。<br />
<br />
我们在 HelloWorld portlet里要做的只是显示&#8220;Hello
Portlet&#8221;，所以我们将覆盖GenericPortlet类的doView()方法，该方法以PortletRequest 和
PortletResponse作为参数。在doView()方法中首先调用response.setContentType()以通知portlet容
器该portlet将要生成何种类型的内容－如果不这样做就会导致IllegalStateException异常。一旦设置了内容的类型，就可以从
response对象中获得PrintWriter并开始写入。<br />
<br />
4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;每个portlet应用在/WEB-INF文件夹中都有一个portlet.xml文件，它是portlet应用的部署描述符。按以下内容创建portlet.xml文件：<br />
</p>
<pre title="pre code">&lt;portlet&gt;<br />
&nbsp;&nbsp;&lt;description&gt;HelloWorldDescription<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/description&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;portlet-name&gt;HelloWorld<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/portlet-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;display-name&gt;Hello World<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/display-name&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;portlet-class&gt;com.test.HelloWorld<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/portlet-class&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;expiration-cache&gt;-1<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/expiration-cache&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;supports&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;mime-type&gt;text/html&lt;/mime-type&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;portlet-mode&gt;VIEW<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/portlet-mode&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/supports&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;supported-locale&gt;en<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/supported-locale&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;portlet-info&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;title&gt;Hello World&lt;/title&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;short-title&gt;Hello World<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/short-title&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;keywords&gt;Hello,pluto&lt;/keywords&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/portlet-info&gt;<br />
&lt;/portlet&gt;</pre>
<p><br />
<br />
&lt;portlet-name&gt;元素声明了portlet的名字，&lt;portlet-class&gt;元素指定了portlet的全
限定类名，&lt;expiration-cache&gt;元素以秒为单位指定了内容超期的时间。这里面有一点需要注意：你在portlet上的某些动
作可能会导致内容刷新，这与缓存时间无关。<br />
&lt;supports&gt;元素指定对于给定的&lt;mime-type&gt;有哪些模
式可供支持。在示例中我们假定HelloWorld只能生成text/html类型的内容，且只有view模式可支持该内容类型。如果要增加对其它内容类
型的支持，需要添加新的&lt;support&gt;元素并指定支持该MIME类型的模式有哪些。通常portlet对于text/html类型有
VIEW、EDIT和HELP模式可供支持，而对于WML MIME类型则只有VIEW模式。<br />
还可以用&lt;supported-
locale&gt;元素来指定portlet支持哪些本地化。&lt;title&gt;元素用来指定portlet的标题。如果要对标题做国际化处
理，可以用元素&lt;resource-bundle&gt;指定资源（比例properties文件）的文件名。在这种情况下，容器将根据用户所在的
地区从适当的properties文件中选择标题。<br />
<br />
5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;每个portlet应用都是一个web应用，因此除了portlet.xml文件之外还需要有web.xml文件。<br />
</p>
<pre title="pre code">&lt;web-app&gt;<br />
&nbsp;&nbsp;&lt;display-name&gt;Hello World Portlet<br />
&nbsp;&nbsp;&lt;/display-name&gt;<br />
&nbsp;&nbsp;&lt;welcome-file-list<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;welcome-file&gt;index.jsp<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/welcome-file&gt;<br />
&nbsp;&nbsp;&lt;/welcome-file-list&gt;<br />
&lt;/web-app&gt;</pre>
<p><br />
<br />
6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;接下来将这些文件进行编译并打包为war文件。你可以自己完成这些工作，或者下载带有build.xml 的示例代码（参见&#8220;资源&#8221;部分）来创建war文件。<br />
在Pluto上部署HelloWorld Portlet<br />
<br />
Pluto尚处于开发阶段的早期，因此还没有一套易于使用的管理工具。为了能使用Pluto服务器，需要将编译和源代码两个版本都下载。需要注意的是以
下说明是针对Windows平台的，Unix用户通过修改斜杠符号和执行sh shell脚本（不是bat批命令文件）会得到类似的结果。<br />
<br />
1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;创建一个文件夹，比如C:"PlutoInstallation。<br />
2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从Pluto的网站下载pluto-1.0.1-rc1.zip和pluto-src-1.0.1-rc1.zip。<br />
3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将pluto-1.0.1-rc1.zip解压到C:"PlutoInstallation.文件夹，它应被解压到C:"PlutoInstallation"pluto-1.0.1-rc1文件夹下。<br />
4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;执行C:"PlutoInstallation"pluto-1.0.1-rc1"bin"startup.bat启动Pluto，现在可以通过地址http://localhost:8080/pluto/portal访问Pluto服务器。<br />
5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将pluto-src-1.0.1-rc1.zip解压到C:"PlutoInstallation"PlutoSrc文件夹。<br />
6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
进入C:"PlutoInstallation"PlutoSrc文件夹，执行maven
distribute:all.，编译并下载运行常规管理任务所必需的相关资源文件。现在可以将HelloWorldPortlet.war作为
portlet进行安装了。<br />
7.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;首先将HelloWorldPortlet.war文件拷贝到C:"PlutoInstallation"portlets目录，如果没这个目录就创建它。<br />
8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将C:"PlutoInstallation"plutosrc"build.properties.sample更名为build.properties。<br />
9.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;编辑build.properties，将maven.tomcat.home指向Pluto编译版的安装位置，在本例中应改为maven.tomcat.home=C:/PlutoInstallation/pluto-1.0.1-rc1。<br />
10.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
为了安装portlet，进入C:"plutoInstallation"plutosrc"deploy文件夹，执行maven deploy
-Ddeploy=c:"PlutoInstallation"portlets"HelloWorldPortlet.war，应能看到&#8220;build
successful&#8221;信息。<br />
11.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在C:"PlutoInstallation"pluto-1.0.1-rc1"webapps文件夹下，应该有一个HelloWorldPortlet文件夹。<br />
12.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;现在进入C:"PlutoInstallation"pluto-1.0.1-rc1"webapps"HelloWorld"WEB-INF" folder文件夹，打开portlet的web.xml文件，你会发现里面自动多了几行，如下所示：<br />
</p>
<pre title="pre code">&lt;servlet&gt;<br />
&nbsp;&nbsp;&lt;servlet-name&gt;HelloWorld&lt;/servlet-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;display-name&gt;HelloWorld Wrapper&lt;/display-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;description&gt;Automated generated<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Portlet Wrapper&lt;/description&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;servlet-class&gt;org.apache.pluto.core.PortletServlet<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/servlet-class&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;portlet-class&lt;/param-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;com.test.HelloWorld<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;init-param&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-name&gt;portlet-guid&lt;/param-name&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;param-value&gt;HelloPluto.HelloWorld<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/param-value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/init-param&gt;<br />
&lt;/servlet&gt;</pre>
<p><br />
13.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
接下来我们将该portlet加到页面里。进入C:"PlutoInstallation"pluto-1.0.1-rc1"webapps"pluto
"WEB-INF"data文件夹，可以看到有两个XML文件：pageregistry.xml和
portletentityregistry.xml。<br />
14.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;portletentityregistry.xml包含了portlet的定义，在该文件中加入以下几行：<br />
</p>
<pre title="pre code"> &lt;application id="5"&gt;<br />
&nbsp;&nbsp; &lt;definition-id&gt;HelloWorld&lt;/definition-id&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;portlet id="1"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;definition-id&gt;HelloWorld.HelloWorld&lt;/definition-id&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/portlet&gt;<br />
&lt;/application&gt;</pre>
<p><br />
应用的&lt;definition-id&gt;应为web应用所在文件夹的名字，portlet的&lt;definition-id&gt;应与web.xml中生成的portlet-guid相一致。<br />
15.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pageregistry.xml定义了页面中包含了哪些portlets，对该文件做如下改动：<br />
</p>
<pre title="pre code">&nbsp;&nbsp;&lt;fragment name="p2" type="portlet"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name="portlet" value="5.1"/&gt;<br />
&lt;/fragment&gt;</pre>
<br />
16.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;执行shutdown命令和startup命令重启Pluto服务器，返回到地址http://localhost:8080/pluto/portal并点击&#8220;Test Link&#8221;－此时页面中将出现我们的<br />
<br />
<span style="color: blue;">HelloWorld portlet。</span><br />
<br />
图3的右侧显示了HelloWorld portlet看上去的样子。<br />
<br />
<img onmouseover="javascript:ImgShowTip(this);" style="display: inline;" onclick="javascript:ImgClick(this);" alt="image" src="http://www.matrix.org.cn/resource/upload/forum/2005_12_05_021757_PvflGMTbcZ.gif" onload="javascript:ImgLoad(this);" border="0" width="600" /><br />
图3 portlet的屏幕截图<br />
<br />
<strong><span style="font-size: 16px;">如何创建Portal页面</span> </strong><br />
<br />
图4显示了portal容器如何将分离的portlets组装为页面。<br />
<br />
<img onmouseover="javascript:ImgShowTip(this);" style="display: inline;" onclick="javascript:ImgClick(this);" alt="image" src="http://www.matrix.org.cn/resource/upload/forum/2005_12_05_021832_mFdIUWtdpN.gif" onload="javascript:ImgLoad(this);" border="0" /><br />
图4 创建Portal页面<br />
<br />
大部分的portal服务器基本上都是部署于应用服务器上的web应用，通过servlet来处理访问portal服务器的请求。查看一下Pluto的
安装目录就会发现Pluto不过是一个部署于Tomcat服务器上的一个普通web应用，再看看C:"PlutoInstallation"pluto-
1.0.1-rc1"webapps"pluto"WEB-INF"web.xml会发现所有发往Pluto服务器的请求都被映射到
org.apache.pluto.portalImpl.Servlet上。<br />
<br />
在本文开始部分&#8220;Portal页面的元素&#8221;中，我们提到portal页面由两部分组成。一部分是由页面中的portlets生成的内容，另一部分是由portal服务器生成的内容。<br />
<br />
在Pluto里，只要用户发出请求，就会由servlet进行控制，根据用户所请求的页面来确定需要显示的portlets的列表。一旦生成了列表，servlet就将控制转给这些portlets线程并收集由它们生成的内容。<br />
<br />
对于由portal服务器生成的内容（像portal网站的观感及每个portlet的外观和控制之类）则取决于C:"
PlutoInstallation"pluto-1.0.1-rc1"webapps"pluto"WEB-INF"aggregation文件夹下的
JSP文件。RootFragment.jsp是主JSP文件，它决定了整体的观感和对齐方式；它还包含了Heads以定义在生成的页面中的&lt;
HEAD&gt;标签里的内容。TabNavigation.jsp用来选择在banner中该显示什么（默认情况下在banner显示列表中也包扩了
pluto.png图片）。TabNavigation.jsp用来确定portal网站的导航方案。这意味着只需改动该文件夹下少量的几个JSP文件，
就能改变整个portal网站的观感。<br />
<br />
Pluto根据pageregistry.xml中的设置确定页面中有多少行，并用
RowFragment.jsp去填充。ColumnFragment.jsp用来填充每个栏目。PortletFragmentHeader.jsp用
来填充每个portlet的页头，像标题条及最大化和最小化控制。footer.jsp用来填充JSP的页脚。如果去看一下portal页面的HTML代
码就会发现每个portlet窗口无非都是嵌入&lt;TD&gt;标签的内容块。<br />
<br />
<strong><span style="font-size: 16px;">结束语</span></strong><br />
<br />
任何一种新技术要想获得成功都应具备以下条件：首先，它能提升现有技术；其次，它能解决现有技术遇到的普遍问题；再次，它能提供多于一个的抽象层（有人说，每抽象出一层，问题就解决一半）。<br />
<br />
由于portlet与现有的应用服务器架构兼容，这对Portlet
API来说是一次发展servlet技术的好机会。你可以从portlet里调用EJB，或者用它启动和参与由应用服务器控制的全局性事务。换句话说，在
以商业逻辑为核心的领域里，portlet完全可以做得和servlet一样好。<br />
<br />
Portlets提供了一个抽象层，现在你不必再担
心客户端使用了什么样的HTTP方法，也不必自己编写程序去捕获像点击按钮这样的客户端事件。最后但绝不是最次要的一点是，portlets以提供像单次
登录、个性化等服务的方式解决了servlets不能解决的大部分问题。
<img src ="http://www.blogjava.net/livery/aggbug/160088.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/livery/" target="_blank">心情经纬</a> 2007-11-13 08:49 <a href="http://www.blogjava.net/livery/articles/160088.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Portlet规范介绍</title><link>http://www.blogjava.net/livery/articles/160087.html</link><dc:creator>心情经纬</dc:creator><author>心情经纬</author><pubDate>Tue, 13 Nov 2007 00:48:00 GMT</pubDate><guid>http://www.blogjava.net/livery/articles/160087.html</guid><wfw:comment>http://www.blogjava.net/livery/comments/160087.html</wfw:comment><comments>http://www.blogjava.net/livery/articles/160087.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/livery/comments/commentRss/160087.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/livery/services/trackbacks/160087.html</trackback:ping><description><![CDATA[<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0="">
Portlet 是基于 java 的 web 组件，由 portlet 容器管理，并由容器处理请求，生产动态内容。 Portals 使用
portlets 作为可插拔用户接口组件，提供信息系统的表示层。作为利用 servlets 进行 web 应用编程的下一步， portlets
实现了 web 应用的模块化和用户中心化。 portlet 规范，即 jsr （ java specification request ）
168 ，是为了实现 portal 和 portlet 的互操作。它定义了 portlet 和 portlet 容器之间的和约，让
portlet 实现个性化、表示和安全的 api 集。规范还定义了怎样在 portlets 应用中打包 portlets 。本系列的 </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0=""> 第一部分描述了 portlet 规范，并解释了其中的根本概念。第二部分中，笔者解释了规范的参考实现和一些 portlet 实例。     </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0="">
随着企业级 portal 的大量涌现，不同提供商创建了不同的 portal 组件 api ，即 portlet 。不同的不兼容给应用服务商，
portal 用户和 portal server 提供商都造成了问题。为了消除这些问题， jsr168 ，即 portlet
规范提出，从而提供 portlet 和 portal 间的互操作性。 jsr168 定义， portlet 是基于 java 的 web
组件， portlet 容器处理 request 并生成动态内容，管理 portlet 。 portal 使用 portletportlet
作为可插入用户接口组件，提供信息系统的表示曾。 </div>
<div 0cm="" 0pt=""><strong normal=""> jsr168 </strong><strong normal=""> 的目标是：     </strong></div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0=""> 定义 portlet 的运行时环境，即 portlet 容器     </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0=""> 定义 portlet 和 portlet 容器之间的 api 集     </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0=""> 提供 portlet 存储易失数据和持久数据的机制     </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0=""> 提供 portlet 包含 servlet 和 jsp 的机制     </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0=""> 定义方便部署的 portlet 打包方法     </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0=""> 提供 jsr168 规范下的 portal 的二进制 portlet 便携性     </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0=""> 通过 WSRP （ web service for remote portlet ）协议运行符合 jsr168 规范的远程 portlet    </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0="">
IT 界已经广泛的接受了 jsr168 规范。所有的 portal 领域主要公司都是 jsr168 专家组的成员：
Apache,AGT,BEA,Boeing,Borland,Broadvision,Citrix,EDS, Fujitsu, Hitachi,
IBM, Novell, Oracle, SAP, SAS Institute, Sun Microsystems, Sybase,
TIBCO, and Vignette 。官方支持列表甚至更长。 </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0=""> 当前， jsr168 正在进行公众审视，最终版本将在 2003 年九月发布。     </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0="">
本文中，首先定义了 portal 和 portlet ，然后解释了 jsr168 的概念，包括 api 的基本对象。接下来，深入到 jsr
的高级功能，比如用户信息，本地化和缓存。然后讲到了扩展，从而使 portal 提供者扩展当前 portlet 规范的函数功能。本文包含了
portlet 应用的打包和部署。 </div>
<h3 13pt="" 0cm=""> 基本定义     </h3>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0=""> 这部分中，讲讲述 portlet 规范中的基础定义，包括 portal 基本构架， portlet 容器和 portal 页面。     </div>
<div 0cm="" 0pt=""><strong normal=""> portal   </strong></div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0="">
portal 是一个基于 web 的应用，它能提供个性化，单点登陆，不同源的内容聚合，和信息系统的表示曾集中。聚合是整合不同 web
页面源数据的过程。为了提供用户定制的内容， portal 可能包含复杂的个性化特征。为不同用户创建内容的 portal 页，可能包含不同的
portlet 集。 </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0="">
图 1 表示了 portal 的基本架构。 portal web 应用处理客户请求，找回用户当前页中的 portlet ，然后调用
portlet 容器，从新获取各个 portlet 的内容。 portlet 容器提供 portlet 的运行时环境，并通过 portlet
api 调用 portlet 。 portal 通过 portlet invoker api 调用 portlet 容器。 portlet
容器通过 portlet provider spi （ service provide interface ）获取 portal 信息。 </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0="">
图 2 表示了基本的 portal 页面组件。 portal 页面本身代表一个完整的标记文档，并且聚集了一些 portlet 窗口。除
portlet 外，页面可能还包含导航区合标志区（ navigation area and banners ）。一个 portlet
窗口包含一个标题栏，装饰，和 portlet 产生的内容。装饰可以包括改变 portlet 窗口状态和模式的按钮（后文将解释这些概念）。 </div>
<div 0cm="" 0pt=""><strong normal=""> portlet   </strong></div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0="">
正如上文所说， portlet 是基于 java 的 web 组件，处理 request 并产生动态内容。 portlet
产生的内容称为片段，即一段遵守中心规则的标记（比如 html, xhtml,wml( 无线标记语言 )
）。如图三所示，多个片段可以聚合成一个完整的文档。多个 portlet 聚合在以期，组成 portal 页。 portlet 容器控制
portlet 的生命周期。 </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0="">
web 客户通过 portal 实现的 request/response 范例与 portlet 交互。通常， portlet 中的动作会被
portal 接受，从而用户与 portlet 中的内容交互（比如点击 portlet 中的链接，提交 form ），提交到 portlet
的目标。 </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0=""> 对不同的用户，根据其配置，同一个 portlet 会产生不同的内容。     </div>
<div 0cm="" 0pt=""><strong normal=""> portlet </strong><strong normal=""> 容器     </strong></div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0="">
portlet 容器提供它们需求的运行时环境并运行 portlet 。它包含 portles 并控制它们的生命周期。容器提供 portlet
参数的持久存储机制，它接受来之 portal 的 request ，并在其持有的 portlet 上执行 request 。容器不负责
portlet 产生内容的聚合， portal 自己处理内容聚合。 </div>
<div 0cm=""  0pt;="" text-indent:=""  30pt;="" 2. 0=""> portal  和 portlet 容器可以作为应用套件构建在一起，也可以做为组件各自单独发布。     </div>
<img src ="http://www.blogjava.net/livery/aggbug/160087.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/livery/" target="_blank">心情经纬</a> 2007-11-13 08:48 <a href="http://www.blogjava.net/livery/articles/160087.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>