Domino中通过servlet上传附件

在B/S开发模式下,Domino表单设计中自带了一个附件上传控件,通过它,可以很方便地将附件上传至文档。这种方式的弊端在于对于某些附件特别多的数据库,容易造成数据库过于庞大,这种情况下,将附件与文档分开存储是比较通用的解决方法。Domino从R5开始就支持servlet了,以下说明摘自IBM官网。

    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"选项,如图:

Domino中通过servlet上传附件 - Kenny - 人 生 海 海

    基本保持默认设置,其中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服务,可以生效了。

    三、设计表单。

Domino中通过servlet上传附件 - Kenny - 人 生 海 海

    这里在单元格里放了一个form,注意这里是标签顺序是</form><form>,若用常规的<form></form>表单将无法提交。因为一个form只能有一个submit生效,这里用了一个button实现上传,用submit实现删除。form默认的method是get,对应servlet里面的doGet方法,用来处理删除请求。上传的时候method置为post,对应servlet里面的doPost方法,用来处理上传的请求,上传按钮的onclick事件为:

Domino中通过servlet上传附件 - Kenny - 人 生 海 海

    由于用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的计算文本来将附件名显示为链接:

Domino中通过servlet上传附件 - Kenny - 人 生 海 海

    四、编写severlet。由于Domino Designer并不支持servlet编写,所以只能借助其它的IDE来生成servlet,这里用eclipse来编写一个FileUpload类,特别说明的是,这个类一定不能用package指明路径,一定要放在default package下,否则在Domino下运行会报错。这个类的结构如下:

Domino中通过servlet上传附件 - Kenny - 人 生 海 海

    需要用到的包是commons-fileupload.jar、javax.servlet.jar和Notes.jar,下面是主要的方法说明。

    servlet初始化方法init():

 public void init() throws ServletException {
dir = "D:\Program Files\IBM\Lotus\Domino\data\domino\icons\attachment";  //(1)
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\data\domino\servlet,然后重启http服务。另外,后续若修改这个文件,替换后仍然需要重启http服务才能生效。

    六、测试。

    上传后:

Domino中通过servlet上传附件 - Kenny - 人 生 海 海

    未选中删除:

Domino中通过servlet上传附件 - Kenny - 人 生 海 海

    删除后:

 

    最后需要说明的是,新建未保存的文档不能通过Database对象的getDocumentByUNID方法获得,因此提交form到servlet后无法重定向回当前文档,所以未保存的文档需要保存后才可以用这个方法上传文件。本例在Domino R8.5下测试通过。

posted @ 2010-10-01 07:57  hannover  阅读(2904)  评论(0编辑  收藏  举报