内容


新型 Web 2.0 应用:XPage 与传统 Servlet 的完美结合

在 XPage 中使用 Ajax

Comments

概述

IBM Lotus Notes/Domino 8.5 为 Lotus Domino Web 2.0 应用程序开发人员提供了一种新的开发技术 — XPage,可以利用它创建 Web 2.0 应用。有关 XPage 的基础介绍,建议读者阅读文章 “XPage 全接触” 和教程“在 Lotus Domino Designer 中利用 XPages 的威力”。

XPage 的前端采用 JSF(Java Server Face)技术实现,并封装了对 Dojo 控件的调用,与传统的 Lotus Domino Web 开发相比较,使用 XPage 开发的 Web 应用界面更加美观。当在 XPage 应用中创建基于 Ajax 的 Web 2.0 应用时,可以采用 XPage 控件及 Dojo 控件构建美观大方的前端界面。但是,还需要一个后端程序来处理业务逻辑,从而实现业务逻辑层及应用显示层的相分离。而 Servlet 在处理业务逻辑上功能强大,是个不错的选择。

接下来,本文将详细介绍如何使用 XPage 和 Servlet 技术来创建 Web 2.0 应用程序,我们将使用一个简单的用户登录应用场景来演示说明。

在 XPage 中使用 Dojo 创建 Ajax 客户端

Lotus Domino Designer 8.5.1 为用户提供了集成 Eclipse IDE 的可视化开发环境,有着强大的 Web 页面设计视图,程序设计人员可以利用它获得“所见即所得”的用户体验,如图 1 所示。

图 1.XPage 设计视图
图 1.XPage 设计视图
图 1.XPage 设计视图

查看图 1 的清晰版本

Lotus Domino Designer 为程序开发者提供了大量可用的 Web 2.0 控件,包括核心控件和容器控件。如图 1 中“控件面板”区所示。但是,在此面板中看不到 Dojo 控件,那么该如何使用 Dojo 控件呢?我们可以编辑 XPage 控件的属性,将其绑定成 Dojo 控件。如图 2 所示。

图 2. Dojo 控件绑定
图 2. Dojo 控件绑定
图 2. Dojo 控件绑定

在某一控件对应的属性框内,将 dojoType 选择成所需要的 Dojo 控件类型,这样就可以将该控件绑定成对应的 Dojo 控件。当然,对于十分熟悉 Dojo 的开发者,也可以直接通过代码的形式添加 Dojo 控件。例如,在代码模式内,下列代码代表一个 Dojo 文本输入框。

清单 1.Dojo 文本输入框
 <input dojoType="dijit.form.TextBox" type="text" name="name" id="name" />

无论采用设计模式或是代码模式添加 Dojo 控件,其效果是一样的,都可以在设计模式中进行预览。

在 XPage 页面中添加两个输入框,一个用于输入用户名,另一个用于输入密码。我们将用户名输入框命名为 username,将密码输入框命名为 password,在 Servlet 中,将会根据组件名称进行组件值的获取。另外,再添加一个登录按钮,这样就完成了输入框的设计工作。XPage Dojo 登录客户端代码如下。

清单 2. 客户端代码
 <div dojoType="dijit.Dialog" id="formDialog" title="System Login Dialog"
    execute="alert('submitted w/args:\n' + dojo.toJson(arguments[0], true));"> 
    <table> 
        <tr> 
            <td> 
                <label for="name">UserName: </label> 
            </td> 
            <td> 
                <input dojoType="dijit.form.TextBox" type="text" name="name"
                    id="name" /> 
            </td> 
        </tr> 
        <tr> 
            <td> 
                <label for="loc">Password: </label> 
            </td> 
            <td> 
                <input dojoType="dijit.form.TextBox" type="text" name="loc"
                    id="loc" /> 
            </td> 
        </tr> 
        <tr> 
            <td colspan="2" align="center"> 
                <xp:button dojoType="dijit.form.Button" type="submit"
                value="Login"></xp:button> 
            </td> 
        </tr> 
    </table> 
 </div>

在 Lotus Domino Designer 中,点击预览图标可以查看该 XPage 页在浏览器中的预览效果,如下图。

图 3. 客户端预览
图 3. 客户端预览
图 3. 客户端预览

在 Domino Designer 中创建 Servlet

在 Domino Server 上创建可运行的 Servlet 与在传统的 Servlet 容器(例如 Tomcat、Resin)上创建 Servlet 的过程不太一样。接触过 Domino Designer 的开发者都应该清楚,在 Domino Application 中,是没有 web.xml 供我们添加 Servlet 的地址映射的。那么,就没法在 Domino Application 中添加 Servlet 服务了吗?答案是否定的。接下来,将为大家讲述如何在 Domino Application 中添加 Servlet 来作为我们的 Web 2.0 应用的服务器端程序。

透视图选择

在 Domino Application 中添加 Servlet,我们需要将 Domino Designer 切换至 Java 透视图,透视图切换选择步骤如下:

  1. 在 Domino Designer 菜单栏中点击 Window > Open perspective > Other,弹出如下对话框。
    图 4. 透视图选择对话框
    图 4. 透视图选择对话框
    图 4. 透视图选择对话框
  2. 在如图 4 所示的透视图选择对话框中选择 Java透视图,即可完成由 Domino Designer 透视图至 Java 透视图的切换。

添加 Servlet Factory 映射文件

在 Domino Designer 中添加 Servlet 服务也需要映射文件,并且要求我们构建对应的映射目录。在 WebContent/WEB-INF路径下添加名为 source的文件夹。然后右键点击 项目根目录 > Properties > Source > Add Folder …,选择新添加的位于 WEB-INF路径下的 source文件夹,点击 OK 确定。如下图 5 所示。

图 5. 构建映射路径
图 5. 构建映射路径
图 5. 构建映射路径

点击 OK 确定后,在 source文件夹下添加一个名为 META-INF的文件夹,在这里面还需要再添加一个名为 services的文件夹。Servlet 映射文件将放置在该文件夹内。至此,我们成功完成了映射文件夹的构建工作。在 Domino Designer 的 Package Explorer 视图中的项目目录结构如下。

图 6. 目录结构图
图 6. 目录结构图
图 6. 目录结构图

完成项目目录结构的构建后,还需要添加 Servlet 服务映射文件。在 services文件夹下添加一个名为 com.ibm.xsp.adapter.servletFactory 的文本文件,在该文件中标明 Servlet Factory 类的路径。在示例项目中,该 Servlet Factory 的路径为 test.ServletFactory,所以只需要在 Servlet Factory 类映射文件中注明该 Factory 类的路径即可。如代码清单所示。

清单 3.Servlet Factory 映射文件
 test.ServletFactory

至此,已完成 Servlet Factory 映射文件的添加工作。接下来要做的就是构建位于 test 路径下的类名为 ServletFactory 的工厂类,该工厂类将负责所有的 Servlet 映射转换工作。

构建 Servlet Factory

Domino Application 中的 ServletFactory 类需实现 com.ibm.designer.runtime.domino.adapter.IServletFactory接口,并且实现 init方法和 getServletMatch方法。开发人员在此工厂类中实现 Servlet 的映射定义等。

ServletFactory 的示例代码如下列代码清单所示。

清单 4.ServletFactory 示例代码
 package test; 

 import javax.servlet.Servlet; 
 import javax.servlet.ServletException; 

 import com.ibm.designer.runtime.domino.adapter.ComponentModule; 
 import com.ibm.designer.runtime.domino.adapter.IServletFactory; 
 import com.ibm.designer.runtime.domino.adapter.ServletMatch; 

 public class ServletFactory implements IServletFactory { 

    private static final String SERVLET_WIDGET_CLASS    = "test.HelloWorldServlet";
    private static final String SERVLET_WIDGET_NAME     = "Hello World Servlet"; 
    

    private ComponentModule module; 

    public void init(ComponentModule module) { 
        this.module = module; 
    } 

    public ServletMatch getServletMatch(String contextPath, String path) 
        throws ServletException { 
        try { 
            throw new Exception(); 
        } 
        catch (Throwable t) { 
            t.printStackTrace(); 
        } 
        
        String servletPath = ""; 
        
        if( path.contains("/helloworld")) { 
            String pathInfo = path; 
            return new ServletMatch(getWidgetServlet(),servletPath,pathInfo); 
        } 

        return null; 
    } 

    public Servlet getWidgetServlet() throws ServletException { 
        return module.createServlet(SERVLET_WIDGET_CLASS, SERVLET_WIDGET_NAME,null);
    } 
    
 }

如清单代码所示,该 ServletFactory 实现了 IServletFactory 接口,并完成了 init 方法和 getServletMatch 方法。

在此 ServletFactory 工厂类中,定义了一个名为“Hello World Servlet”的 Servlet,该 Servlet 的功能实现类为 test.HelloWorldServlet。那么,该 Servlet 的访问 URL 是什么呢?这需要在 getServletMatch 方法中给予说明。

清单 5. Servlet URL 映射代码
 if( path.contains("/helloworld")) { 
    String pathInfo = path; 
    return new ServletMatch(getWidgetServlet(),servletPath,pathInfo); 
 }

清单 5 中的代码给出了 Servlet 映射定义的实例。当需要往 Domino Application 添加一个访问 URL 为“/helloworld”的 Servlet 时,就需要在 getServletMatch 方法中添加这样的一段代码。ServletFactory 通过用户自定义的 getWidgetServlet 方法来实现一个 ServletMatch,从而完成一个 Servlet 映射的定义。

此时,有经验的开发人员应该能够想象的到 Domino Application 中一个 Servlet 工作的流程。当用户访问一个路径为“/helloworld”的 Servlet 时,Domino Server 根据 Servlet Factory 映射文件找到 Servlet Factory 工厂类,并在工厂类的 getServletMatch 方法中查找是否有“/helloworld”的 Servlet 处理方法。如果有,则用该方法构建一个 ServletMatch,向客户端返回,成功完成 Servlet 的访问操作;如果没有,则向客户端返回失败错误信息。

构建 Servlet 类

至此,已完成了 Servlet 映射文件的配置工作,接下来 Servlet 类实现的这部分工作大家应该都比较熟悉了。在 test包下面添加一个名为 HelloWorldServlet 的 Java 类,该类必须继承于抽象类 javax.servlet.http.HttpServlet,并且应该完成 doGet等方法的实现。该方法中就是 Servlet 服务器端的具体操作。示例代码如下。

清单 6.Servlet 类示例代码
 package test; 

 import java.io.IOException; 
 import java.io.PrintWriter; 

 import javax.servlet.ServletException; 
 import javax.servlet.http.HttpServlet; 
 import javax.servlet.http.HttpServletRequest; 
 import javax.servlet.http.HttpServletResponse; 

 public class HelloWorldServlet extends HttpServlet { 
    /** 
     * Domino Application Servlet Demo code 
     */ 
    private static final long serialVersionUID = 1L; 

    public void doGet(HttpServletRequest req, HttpServletResponse res) 
            throws ServletException, IOException { 
        PrintWriter out = res.getWriter(); 
        String username = req.getParameter("username"); 
        String password = req.getParameter("password"); 
        if (username == null || password == null) { 
            out.println("Miss parameter username or password!"); 
        } else { 
            if (username.trim().equals("admin") 
                    && password.trim().equals("admin")) { 
                out.println("Login Success"); 
            } else 
                out.println("Login Failure"); 
        } 

        out.close(); 
    } 

 }

此 Servlet 类实现了 doGet 方法,并完成了一个简单的登录操作,当用户名为 admin、密码为 admin 时,向客户端返回登录成功的提示信息。否则,提示登录失败。这与传统的 Servlet 类并无二样,只是需要注意的是,在 Domino Application Servlet 中,Servlet 可以取得 Notes 登录用户的相关信息。例如下列代码即可以取得当前操作用户的 Notes 用户名信息,更加高级的功能读者可以查阅 XPage 资料进一步学习。

清单 7.Servlet 取 Notes 用户信息
 try { 
    Session session=NotesContext.getCurrent().getCurrentSession(); 
    out.print("Operator Username:" + session.getCommonUserName()); 
 } catch (Throwable t) { 
    t.printStackTrace(out); 
 }

Servlet 运行测试

我们已经成功完成了在 Domino Application 中添加一个 Servlet 的开发工作,接下来测试一下这个 Servlet 是否能够正常工作。

在浏览器地址栏内输入该 Servlet 的 URL 地址 http://localhost/servlettest.nsf/xsp/helloworld,可以看到以下信息:

 Miss parameter username or password!

从上面可以得知,该信息提示输入参数不全,需补充参数 usernamepassword。接下来,在浏览器内输入地址 http://localhost/servlettest.nsf/xsp/helloworld?username=test&&password=test,我们可以看到 Servlet 向我们返回信息:

 Login Failure

该信息提示我们登录失败,当我们向该 Servlet 传入值为 admin 的 usernamepassword时,我们可以看到 Login Success的提示信息。

Servlet 工作一切正常!

XPage Dojo 客户端与 Servlet 的连接

前面我们已经利用 Doji 完成了客户端登录界面的设计工作,并且完成了 Login Servlet 的开发工作,要利用 Ajax 技术完成整个登录流程,接下来要做的就是把整个流程串起来。

添加数据提交函数

当用户填写完登录用户名和密码信息,点击“Login”按钮进行登录操作时,需要使用 JavaScript 脚本来实现信息的收集,并通过 XmlHttpRequest 向 Servlet 发送用户信息,以完成登录操作。

打开 Lotus Domino Designer 的 Domino Designer 透视图,在项目目录下选择 code > Script Libraries,右建选择 New Script Libraries,添加一个名为 login的客户端 JavaScript 脚本,如下。

清单 8.login JavaScript 角本
 function dominoLogin(dialogFields){ 
    dojo.xhrPost({ 
        url: 'xsp/helloworld', 
        content: dialogFields, 
        load: function (data) { 
            alert(data); 
        }, 
        error: function (error) { 
            console.error ('Error: ', error); 
        } 
    }); 
 }

我们采用 xhrPost 方式向 Servlet 提交用户登录信息,并用 alert 函数完成登录返回信息的显示。

另外,我们还需要修正 Dojo 登录框的表单信息提交的代码。选择 XPage 登录页面,在 Properties 视图中选择 Resources > Add Script Library > login(client),点击“OK”完成添加确认。这样,就把登录 JavaScript 脚本成功添加至 XPage 页面,如果打开该页面的 Source进行查找,可以找到这样一行代码:

 <xp:script src="/login.js" clientSide="true"></xp:script>

接下来修改 loginDialog 的信息提交方式,如下所示。

清单 9.form 信息提交代码
 <div dojoType="dijit.Dialog" id="loginDialog" execute="dominoLogin(arguments[0]);">

通过这段代码,form 使用 dominoLogin 方法进行登录信息的提交。

连接测试

已经完成所有登录操作的开发工作了,万事俱备,只欠测试了。下面要做的工作就是测试一下我们的代码是否能够正常运行。

打开登录页面:http://localhost/servlettest.nsf/dojoDialog.xsp,输入用户名和密码信息,点击“Login”进行登录操作。但是,服务器端没有信息反馈信息,这是为什么呢?

我们利用 Mozilla Firefox 的 FireBug 插件进行调试,查看出错信息。在 FireBug 网络视图中可以查看到如下的错误信息。

图 7.FireBug 错误提示
图 7.FireBug 错误提示
图 7.FireBug 错误提示

从错误信息我们可以了解到,我们采用 xhrPost 方式进行登录信息的提交,但是 Servlet 却不支持 HTTP method POST。这是什么原因呢?对,因为我们在 Servlet 类里只实现了 doGet方法,却没有实现 doPost方法,该 Servlet 就自然会不支持 HTTP method POST了。

问题修正

知道了问题所在以后,要做的就是修正问题了。解决该问题有两个途径:

  1. 使用 xhrGet 方式进行登录数据信息的提交;
  2. 在 Servlet 中添加 doPost 方法,实现对 HTTP method POST请求的处理操作。

我们采用第二种方式来解决该问题,在 Servlet 类中添加如下代码。

清单 10.Servlet doPost 方法代码
 public void doPost(HttpServletRequest req, HttpServletResponse res) 
    throws ServletException, IOException { 
        this.doGet(req, res); 
 }

在完成修改以后,再次进行登录测试。在登录 XPage 页面中输入用户名 test,密码 test,点击“OK”进行登录后,即可看到“Login Failure”提示信息。

图 8. 登录失败提示信息
图 8. 登录失败提示信息
图 8. 登录失败提示信息

当我们输入用户名 admin,密码 admin 进行登录测试时,可以看到成功登录的反馈信息,如下图所示。

图 9. 登录成功提示信息
图 9. 登录成功提示信息
图 9. 登录成功提示信息

至此,我们已经成功使用 XPage Dojo 和 Servlet 技术完成了登录功能的 Web 2.0 实现。

总结

本文对 XPage 应用程序的基本开发环境、在 XPage 中如何使用 Dojo 组件、在 Domino Application 中如何创建 Servlet 应用以及如何在 XPage 中使用 Ajax 技术进行 Web 2.0 开发进行了讲述。相信大家已经对整个流程有了基本的了解,可以使用 XPage 和 Servlet 进行整合开发,创建功能简单的 XPage Web 2.0 应用程序。如果读者希望进一步的学习,对 XPage 有更加深层次的掌握,可以查看参考资料中的相关文档。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Lotus, Web development
ArticleID=470417
ArticleTitle=新型 Web 2.0 应用:XPage 与传统 Servlet 的完美结合
publish-date=03042010