Servlet特点以及与Agent的区别:
Servlet是运行在服务器上的Java程序,提供类似于CGI应用和Domino Agent的功能。Servlet的主要优点是只装载入内存一次,而Agent和CGI程序是每次调用时都需装载入内存。Sservlet一次装载入内存后,以后所有调用都使用该实例。例如,针对连接数据库的任务,您可以选择Servlet来保持一个永久连接传输数据,提高运行效率。
尽管Agent和Servlet提供类似功能,但它们的实现差别很大。Agent存在于Domino数据库而Servlet在文件系统下。这立即带来了两个问题:分布和安全。Agent可以充分利用它所在的数据库,因此,可通过复制分布到其它服务器。同样,Domino安全模式控制Agent的访问。相反,Servlet存在于文件系统,因此由服务器、文件和目录安全来控制Servlet的访问。Servlet缺省是以服务器安全权限来运行,但也可以某一特定Internet用户名字和口令来运行。最后,除非使用WinNT目录复制,否则您必须拷贝或安装Servlet到其它需要的服务器。
现在来实践下,利用一个开源的java附件上传工具:commons-fileupload,编写一个servlet实现将客户机选择的附件上传至Domino服务器磁盘的功能,以达到文档与附件分开存储的目的。
一、要使用Domino服务器能够运行管理servlet,必须先对服务器进行servlet管理设置。打开服务器文档切换至"Internet Protocol"->"Domino Web Engine"选项,如图:
基本保持默认设置,其中Servlet file extensions是指servlet扩展名,例如可以通过url:http://yourserver/servlet/servletname或者http://yourserver/servlet/servletname?svl来访问servlet。另外url也对servlet名的大小写敏感。
二、引入所用的jar包,配置notes.ini的JavaUserClasses参数。servlet用commons-fileupload上载附件,所以要把commons-fileupload.jar和javax.servlet.jar放到服务器上,当然Notes.jar也是必须的。另外配置JavaUserClasses可以用通配符*,例如把所有的jar都放在服务器安装目录的Lotus\Domino\jvm\lib\ext下,那么就可以直接用JavaUserClasses=D:Program Files\IBM\Lotus\Domino\jvm\lib\ext\*;而无需一个一个jar添加。且后续若有新的jar加入,只需将jar文件放到这个目录下,然后重启下http服务,可以生效了。
三、设计表单。
这里在单元格里放了一个form,注意这里是标签顺序是</form><form>,若用常规的<form></form>表单将无法提交。因为一个form只能有一个submit生效,这里用了一个button实现上传,用submit实现删除。form默认的method是get,对应servlet里面的doGet方法,用来处理删除请求。上传的时候method置为post,对应servlet里面的doPost方法,用来处理上传的请求,上传按钮的on
由于用submit提交form后,servlet里面request只能获取form上input元素的值,而用button提交form后,servlet里面request只能获取url传递的参数,因此,这里这里所需要的参数既要体现在input元素上也要体现在url参数中。本例中所需的4个参数是:
svr:服务器的简称,用公式@Name([CN];@ServerName)获得
db:数据库路径,用公式@WebDbName获得
uid:当前文档的ID,用公式@DocumentUniqueID获得
filenameitem:用来存放附件名称的多值域
有了svr、db、uid这3个参数,就可以在servlet中定位到当前打开的文档,在servlet处理上传或删除后将页面重定向回原始打开的页面。另外还需要在表单上创建一个多值域files,用来存放上传的附件名称,域名作为filenameitem参数的值传递给servlet。
最后用一个内置HTML的计算文本来将附件名显示为链接:
四、编写severlet。由于Domino Designer并不支持servlet编写,所以只能借助其它的IDE来生成servlet,这里用eclipse来编写一个FileUpload类,特别说明的是,这个类一定不能用package指明路径,一定要放在default package下,否则在Domino下运行会报错。这个类的结构如下:
需要用到的包是commons-fileupload.jar、javax.servlet.jar和Notes.jar,下面是主要的方法说明。
servlet初始化方法init():
public void init() throws ServletException {
dir = "D:\Program Files\IBM\Lotus\Domino\da
domain = ""; //(2)
ss = null;
db = null;
doc = null;
item = null;
}
删除附件doGet():
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
getParameters(request); //(3)
String atts[] = request.getParameterValues("atts"); //(4)
try{
NotesThread.sinitThread();
ss = NotesFactory.createSession();
db = ss.getDatabase(svrname, dbname);
doc = db.getDocumentByUNID(uid);
item = doc.getFirstItem(filenameitem); //(5)
for(int i = 0;i<atts.length;i++){
String att = new String(atts[i].getBytes("ISO-8859-1"),"UTF-8"); //(6)
File del = new File(dir + "\\" + att);
if(del.delete()){ //(7)
Vector v = item.getValues();
for(int k = 0;k < v.size();k++){
String f = (String)v.get(k);
if(f.equals(att)){
v.removeElementAt(k); //(7)
break;
}
}
item.setValues(v);
}
}
doc.save(true, false);
url = "http://" + "localhost" + domain + "/" + dbname + "/0/" + doc.getUniversalID() + "?EditDocument";
recycleDominoObj(); //(8)
}catch(NotesException e){
System.out.println("Servlet FileUpload method doGet domino object error:" + e.getMessage());
e.printStackTrace();
}finally{
NotesThread.stermThread();
}
response.sendRedirect(url); //(9)
}
上传附件doPost():
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
getParameters(request);
try{
NotesThread.sinitThread();
Session ss = NotesFactory.createSession();
Database db = ss.getDatabase(svrname, dbname);
Document doc = db.getDocumentByUNID(uid);
Item item = doc.getFirstItem(filenameitem);
List filenames = uploadFiles(request); //(10)
for(Iterator it = filenames.iterator();it.hasNext();){
item.appendToTextList((String)it.next()); //(11)
}
doc.save(true, false);
url = "http://" + "localhost" + domain + "/" + dbname + "/0/" + doc.getUniversalID() + "?EditDocument";
recycleDominoObj();
}catch(NotesException e){
System.out.println("Servlet FileUpload method doPost domino object error:" + e.getMessage());
e.printStackTrace();
}finally{
NotesThread.stermThread();
}
response.sendRedirect(url);
}
获取request中所需的参数getParameters():
private void getParameters(HttpServletRequest request){
svrname = request.getParameter("svr");
dbname = request.getParameter("db");
uid = request.getParameter("uid");
filenameitem = request.getParameter("filenameitem");
}
回收Domino对象recycleDominoObj():
private void recycleDominoObj(){
try {
if(item != null) item.recycle();
if(doc != null) doc.recycle();
if(db != null) db.recycle();
if(ss != null) ss.recycle();
} catch (NotesException e) {
System.out.println("Recycle domino object error:" + e.getMessage());
e.printStackTrace();
}
}
实现附件上传uploadFiles:
private List uploadFiles(HttpServletRequest request){
List<String> filenames = new ArrayList<String>();
Date now = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); //(12)
String nowString = format.format(now);
try{
DiskFileUpload fu = new DiskFileUpload();
fu.setSizeMax(1024 * 1024 * 20); //(13)
fu.setSizeThreshold(1024 * 1024 * 5); //(14)
fu.setRepositoryPath(System.getProperty("java.io.tmpdir")); //(15)
fu.setHeaderEncoding("UTF-8");
try {
List files = fu.parseRequest(request);
for(Iterator it = files.iterator();it.hasNext();){
FileItem file = (FileItem)it.next();
if(!file.isFormField() && null != file.getName() && 0 != file.getName().trim().length()) {
String clientPath = file.getName();
String fileName = new File(clientPath).getName();
fileName = nowString + "." + fileName;
File destDir = new File(dir);
File load = new File(destDir, fileName);
file.write(load);
filenames.add(fileName);
}
}
}catch(Exception e){
System.out.println("Servlet FileUpload method uploadFiles upload file error:" + e.getMessage());
e.printStackTrace();
}
}catch(Exception e){
System.out.println("Servlet FileUpload.uploadFiles:" + e.toString());
e.printStackTrace();
}
return filenames;
}
(1)附件上传到Domino服务器上的绝对路径,这里之所以要用Domino数据目录下的icons文件夹,是因为该路径在Domino映射管理下,可以直接通过url访问到此路径下的文件。
(2)初始化域名,例如.IBM.COM.CN,本例是在本机测试,故初始为空。
(3)获取form或者url传递的参数。
(4)获取checkbox选中的附件。
(5)得到文档上存储附件名称列表的域。
(6)解决附件名称带中文会乱码的问题。
(7)删除文件,并将文件名从存储附件名称的域里剔除。
(8)回收Domino对象,这是必需的。
(9)将url重定向回打开的文档。
(10)上传附件,并返回附件的名称列表。
(11)将附件名称添加到文档上存储附件名称的域里。
(12)附件保存到服务器磁盘前,在文件名前添加一个时间参数,防止覆盖同名文件。
(13)上传附件的最大值。
(14)分配的内存大小。
(15)上传的附件大小大于分配的内存大小时的临时文件存储路径。
五、发布servlet。将编译好的servlet文件FileUpload.class放到服务器上配置的servlet路径,本例的路径为D:\Program Files\IBM\Lotus\Domino\da
六、测试。
上传后:
未选中删除:
删除后:
最后需要说明的是,新建未保存的文档不能通过Database对象的getDocumentByUNID方法获得,因此提交form到servlet后无法重定向回当前文档,所以未保存的文档需要保存后才可以用这个方法上传文件。本例在Domino R8.5下测试通过。