产品里需要包含一个文档(内容)管理的功能,找了一些开源的:
KnowledgeTree,Alfresco,OpenKM。
经过试用,相中了OpenKM的各种功能。
但是--公司的产品前台是swing(已经好多年了,不是我能改变的),而OpenKM是web的,如果直接嵌入(把浏览器嵌入swing中),登陆、权限控制等是个大问题,而且以后扩展起来也比较麻烦,后患无穷啊。。。
看了下介绍,OpenKM是基本Apache Jackrabbit引擎实现的,那我们能不能直接用Jackrabbit来做后台,swing做前台呢?
贴一段Apache Jackrabbit的简介,来自http://www.oschina.net/p/jackrabbit
Apache Jackrabbit 是由 Apache Foundation 提供的 JSR-170 的开放源码实现..
随着内容管理应用程序的日益普及,对用于内容仓库的普通、标准化 API 的需求已凸现出来。Content Repository for Java Technology API (JSR-170) 的目标就是提供这样一个接口。JSR-170 的一个主要优点是,它不绑定到任何特定的底层架构。例如,JSR-170 实现的后端数据存储可以是文件系统、WebDAV 仓库、支持 XML 的系统,甚至还可以是 SQL 数据库。此外,JSR-170 的导出和导入功能允许一个集成器在内容后端与 JCR 实现之间无缝地切换。
----------------------------------------------------------------------
注:上面说的JSR-170指jcr1.0,而现在已经是jsr283了--jcr2.0了
官方主页:
http://jackrabbit.apache.org/
Jackrabbit的资料相对比较少,就找到这么一篇比较详细的,但时间是2006年的,当时还是jcr1.0
http://www.ibm.com/developerworks/cn/java/j-jcr/
不管怎么样,试试吧。
下载2.4的源代码,maven2编译一下。
把jar包导入到新建的工程中。
然后根据文章说的,照猫画虎,折腾2个小时,终于搞定了。
过程:
1.初始化仓库。
// 初始化 String configFile = "F:\\jackrabbit_repository\\repository.xml"; String repHomeDir = "F:\\jackrabbit_repository\\repository"; Hashtable<String, Object> env = new Hashtable<String, Object>(); env.put(Context.INITIAL_CONTEXT_FACTORY, DummyInitialContextFactory.class.getName()); env.put(Context.PROVIDER_URL, "localhost"); InitialContext ctx = new InitialContext(env); RegistryHelper.registerRepository(ctx, "repo", configFile, repHomeDir, true); Repository r = (Repository) ctx.lookup("repo");
2.登陆,这里注意一点,需要以管理员的身份登陆,否则很多操作都没有权限,默认用户名和密码都是admin
Repository r = (Repository) ctx.lookup("repo"); // 登陆 SimpleCredentials cred = new SimpleCredentials("admin", "admin".toCharArray()); Session session = r.login(cred, null);
3.注册工作区命名空间
// 根节点 Node rn = session.getRootNode(); // 注册命名空间 Workspace ws = session.getWorkspace(); ws.getNamespaceRegistry().registerNamespace("wiki", "http://localhost/wiki/1.0");
4.增加内容。
Node encyclopedia = rn.addNode("wiki:encyclopedia"); Node p = encyclopedia.addNode("wiki:entry"); p.setProperty("wiki:title", toStringValue("rose")); p.setProperty("wiki:content", toStringValue("A rose is a flowering shrub.")); p.setProperty("wiki:category", new Value[] { toStringValue("flower"), toStringValue("plant"), toStringValue("rose") }); Node n = encyclopedia.addNode("wiki:entry"); n.setProperty("wiki:title", toStringValue("Shakespeare")); n.setProperty("wiki:content", toStringValue("A famous poet who likes roses.")); n.setProperty("wiki:category", toStringValue("poet")); // 保存 session.save();
可以看出,里面是以属性结构存储的,可以想象出修改和删除的操作了吧。
无非是root.getNode(),然后修改或者删除就可以了,当然,最后别忘了保存
5.看个查找的例子吧
// 查找 QueryManager qm = ws.getQueryManager(); Query q = qm.createQuery( "//wiki:encyclopedia/wiki:entry[@wiki:title = 'rose']", Query.XPATH);// deprecated QueryResult result = q.execute();// 执行查询 NodeIterator it = result.getNodes(); // 然后就可以了遍历了 while (it.hasNext()) { Node entry = it.nextNode(); // 简单的输出,后面会有输出详细内容的方法 System.out.println(entry.toString()); }
6。前面都是字符串的,如果想存文件怎么办?
大家注意到,setProperty有个String,InputStream参数的,对,就是它了。
// 加入文件 File file = new File("f:\\2012-03-07_111233.png"); MimeTable mt = MimeTable.getDefaultTable(); String mimeType = mt.getContentTypeFor(file.getName()); if (mimeType == null) { mimeType = "application/octet-stream"; } Node fileNode = rn.addNode(file.getName(), "nt:file"); Node resNode = fileNode.addNode("jcr:content", "nt:resource"); resNode.setProperty("jcr:mimeType", mimeType); resNode.setProperty("jcr:encoding", ""); // 这里--用流加入 resNode.setProperty("jcr:data", new FileInputStream(file)); Calendar lastModified = Calendar.getInstance(); lastModified.setTimeInMillis(file.lastModified()); resNode.setProperty("jcr:lastModified", lastModified); // 保存 session.save();
写完后,可以运行,但编译器警告:deprecated
那用什么代替呢?
查看了jcr2.0,使用setPropery(String,Binary)代替
Binary fileBinary = new BinaryImpl(new FileInputStream(file)); resNode.setProperty("jcr:data", fileBinary);
7.由于是树形结构,我们可以递归打出所有的信息:
private static void printAll(Node node) throws RepositoryException { printFormat(node.toString()); PropertyIterator propertys = node.getProperties(); while (propertys.hasNext()) { Property entry = propertys.nextProperty(); if (entry.isMultiple()) { Value[] values = entry.getValues(); if (values == null) { continue; } for (Value v : values) { printFormat(v.getString()); } } else { printFormat(entry.getValue().getString()); } } NodeIterator entries = node.getNodes(); while (entries.hasNext()) { Node entry = entries.nextNode(); printAll(entry); } }
完整代码见附件
另外附件中的jcr2.0.jar就是jcr2.0的规范接口,编译后的 jackrabbit 是不带的(我找了好几个地方才找到)
由于目前最新版本已经使用了jcr2.0,所以有必要看一下2.0与1.0的区别:
API Differences between jcr-1.0 and jcr-2.0
http://www.day.com/maven/jdiff-jcr1-jcr2/changes.html