概述
IBM Lotus Notes/Domino 8.5为Lotus Domino Web 2.0应用程序开发人员提供了一种新的开发技术— XPage,可以利用它创建Web 2.0应用。
XPage的前端采用JSF(JavaServer 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设计视图
查看原图(大图)
Lotus Domino Designer为程序开发者提供了大量可用的Web 2.0控件,包括核心控件和容器控件。如图1中“控件面板”区所示。但是,在此面板中看不到Dojo控件,那么该如何使用Dojo控件呢?我们可以编辑XPage控件的属性,将其绑定成Dojo控件。如图2所示。
图2. Dojo控件绑定
在某一控件对应的属性框内,将dojoType选择成所需要的Dojo控件类型,这样就可以将该控件绑定成对应的Dojo控件。当然,对于十分熟悉Dojo的开发者,也可以直接通过代码的形式添加Dojo控件。例如,在代码模式内,下列代码代表一个Dojo文本输入框。
清单1.Dojo文本输入框
无论采用设计模式或是代码模式添加Dojo控件,其效果是一样的,都可以在设计模式中进行预览。
在XPage页面中添加两个输入框,一个用于输入用户名,另一个用于输入密码。我们将用户名输入框命名为username,将密码输入框命名为password,在Servlet中,将会根据组件名称进行组件值的获取。另外,再添加一个登录按钮,这样就完成了输入框的设计工作。XPage Dojo登录客户端代码如下。
清单2.客户端代码
UserName: | id="name" /> |
Password: | id="loc" /> |
value="Login"> |
在Lotus Domino Designer中,点击预览图标可以查看该XPage页在浏览器中的预览效果,如下图。
图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透视图,透视图切换选择步骤如下:
在Domino Designer菜单栏中点击Window > Open perspective > Other,弹出如下对话框。图4.透视图选择对话框
在如图4所示的透视图选择对话框中选择Java透视图,即可完成由Domino Designer透视图至Java透视图的切换。
添加Servlet Factory映射文件
在Domino Designer中添加Servlet服务也需要映射文件,并且要求我们构建对应的映射目录。在WebContent/WEB-INF路径下添加名为source的文件夹。然后右键点击项目根目录> Properties > Source > Add Folder …,选择新添加的位于WEB-INF路径下的source文件夹,点击OK确定。如下图5所示。
图5.构建映射路径
查看原图(大图)
点击OK确定后,在source文件夹下添加一个名为META-INF的文件夹,在这里面还需要再添加一个名为services的文件夹。Servlet映射文件将放置在该文件夹内。至此,我们成功完成了映射文件夹的构建工作。在Domino Designer的Package Explorer视图中的项目目录结构如下。
图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!
从上面可以得知,该信息提示输入参数不全,需补充参数username或password。接下来,在浏览器内输入地址http://localhost/servlettest.nsf/xsp/helloworld?username=test&&password=test,我们可以看到Servlet向我们返回信息:
Login Failure
该信息提示我们登录失败,当我们向该Servlet传入值为admin的username和password时,我们可以看到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进行查找,可以找到这样一行代码:
接下来修改loginDialog的信息提交方式,如下所示。
清单9.form信息提交代码
通过这段代码,form使用dominoLogin方法进行登录信息的提交。
连接测试
已经完成所有登录操作的开发工作了,万事俱备,只欠测试了。下面要做的工作就是测试一下我们的代码是否能够正常运行。
打开登录页面:http://localhost/servlettest.nsf/dojoDialog.xsp,输入用户名和密码信息,点击“Login”进行登录操作。但是,服务器端没有信息反馈信息,这是为什么呢?
我们利用MozillaFirefox的FireBug插件进行调试,查看出错信息。在FireBug网络视图中可以查看到如下的错误信息。
图7.FireBug错误提示
从错误信息我们可以了解到,我们采用xhrPost方式进行登录信息的提交,但是Servlet却不支持HTTP method POST。这是什么原因呢?对,因为我们在Servlet类里只实现了doGet方法,却没有实现doPost方法,该Servlet就自然会不支持HTTP method POST了。
问题修正
知道了问题所在以后,要做的就是修正问题了。解决该问题有两个途径:
使用xhrGet方式进行登录数据信息的提交;
在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.登录失败提示信息
当我们输入用户名admin,密码admin进行登录测试时,可以看到成功登录的反馈信息,如下图所示。
图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有更加深层次的掌握,可以查看参考资料中的相关文档。