文章目录
1.什么是JCR
1.1 JCR 是什么
Java Content Repository API(JSR-170)试图建立一套标准的API去访问内容仓库。
内容仓库可以理解为一个用来存储文本和二进制数据(图片,word文档,PDF等等)的数据存储应用程序。
你不用关心你真正的数据到底存储在什么地方,是关系数据库?是文件系统?还是XML?
通过JSR-170,你开发代码只需要引用 javax.jcr.* 这些类和接口。它适用于任何兼容JSR-170规范的内容仓库。
JSR-170 API对不同的人员提供了不同的好处
- 对于开发者无需了解厂家的仓库特定的API,只要兼容JSR-170就可以通过JSR-170访问其仓库。
- 对于使用CMS的公司则无需花费资金用于在不同种类CMS的内容仓库之间进行转换。
- 对于CMS厂家,无需自己开发内容仓库,而专注于开发CMS应用。
1.2 JCR的内容仓库模型
- JCR的内容仓库是一个树状结构
- 树上的元素(Item)分为两类:节点(node)和属性(property)。
- 1个节点:有且只有一个父亲,有任意数目的孩子(子节点)和任意数目的属性。
- 1个属性:有且只有一个父亲(节点),它没有子节点,由一个名字和一个或多个值组成。
- 属性值的类型可以是:布尔(Boolean)、日期(Date)、双精度(Double)、长整型(Long)、字符串(String)或流(Stream)。
- 属性可以被用来存储信息,节点则被用来创建树内部的“路径”(类似文件系统的结构,节点是目录,属性是实际的文件)
由于JCR的节点和属性具有很多相同的特性,因此它们都实现了Item接口中定义的通用方法,此外它们还添加了各自特有的功能方法。下图是JCR树状数据存储模型的UML结构图
除了 Node 和 Property 之外,API中还有几个重要的对象。Repository 代表整个内容仓库,Credentials 代表一个用户身份,Ticket 代表进入该内容仓库的门票。
2.什么是Jackrabbit
JackRabbit就是一种面向文档的数据库,它和MongoDB,CouchDB的功能十分接近,优势在于JackRabbit遵从JCR标准,日后可以迁移到其他同样兼容JCR的性能更好的商业解决方案上。
Jackrabbit(内容仓库)是一个高级的信息管理系统,该系统是传统的数据仓库的扩展,它提供了诸如版本控制、全文检索、访问控制、内容分类、内容事件监视等内容服务。Jackrabbit里面有一个DataStore类,该类有两个实现,DbDataStore和FileDataStore,可以保存元数据和二进制数据。
3.使用Jackrabbit
3.1 配置Jackrabbit环境
- 引入依赖
<dependencies>
<!-- The JCR API -->
<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
<version>2.0</version>
</dependency>
<!-- Jackrabbit content repository -->
<dependency>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>jackrabbit-core</artifactId>
<version>2.12.1</version>
</dependency>
<!-- Use Log4J for logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.11</version>
</dependency>
</dependencies>
- 配置仓库repository.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<Repository>
<FileSystem
class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
<param name="path" value="${rep.home}/repository"/>
</FileSystem>
<Security appName="Jackrabbit">
<AccessManager
class="org.apache.jackrabbit.core.security.
SimpleAccessManager"/>
</Security>
<Workspaces
rootPath="${rep.home}/workspaces"
defaultWorkspace="default" />
<Workspace name="${wsp.name}">
<FileSystem
class="org.apache.jackrabbit.core.fs.local.
LocalFileSystem">
<param name="path" value="${wsp.home}"/>
</FileSystem>
<PersistenceManager
class="org.apache.jackrabbit.core.state.xml.
XMLPersistenceManager" />
<SearchIndex
class="org.apache.jackrabbit.core.query.lucene.
SearchIndex">
<param name="path" value="${wsp.home}/index" />
</SearchIndex>
</Workspace>
<Versioning rootPath="${rep.home}/versions">
<FileSystem
class="org.apache.jackrabbit.core.fs.local.
LocalFileSystem">
<param name="path" value="${rep.home}/versions"/>
</FileSystem>
<PersistenceManager
class="org.apache.jackrabbit.core.state.xml.
XMLPersistenceManager" />
</Versioning>
</Repository>
- 初始化仓库
String configFile = "repository.xml";
String repHomeDir = "repository";
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.jackrabbit.core.jndi" +
".provider.DummyInitialContextFactory");
env.put(Context.PROVIDER_URL, "localhost");
InitialContext ctx = new InitialContext(env);
RegistryHelper.registerRepository(ctx,
"repo",
configFile,
repHomeDir,
true);
Repository r = (Repository) ctx.lookup("repo");
- 登陆(需要以管理员的身份登陆,否则很多操作都没有权限,默认用户名和密码都是admin)
Session session = repository.login(
new SimpleCredentials("admin", "admin".toCharArray()));
- 注册工作区命名空间(非必须)
// 注册命名空间
Workspace ws = session.getWorkspace();
3.2使用Jackrabbit
- 简单的CRUD操作
public static void main(String[] args) throws Exception {
Repository repository = JcrUtils.getRepository();
Session session = repository.login(
new SimpleCredentials("admin", "admin".toCharArray()));
try {
Node root = session.getRootNode();
// 存储内容
Node hello = root.addNode("hello");
Node world = hello.addNode("world");
world.setProperty("message", "Hello, World!");
session.save();
// 检索内容
Node node = root.getNode("hello/world");
System.out.println(node.getPath());
System.out.println(node.getProperty("message").getString());
// 删除内容
root.getNode("hello").remove();
session.save();
} finally {
session.logout();
}
}
- 将xml文件存入
public static void main(String[] args) throws Exception {
Repository repository = JcrUtils.getRepository();
Session session = repository.login(
new SimpleCredentials("admin", "admin".toCharArray()));
try {
Node root = session.getRootNode();
// 导入XML文件,除非已经导入
if (!root.hasNode("importxml")) {
System.out.print("Importing xml... ");
// 创建一个node在其下导入XML
Node node = root.addNode("importxml", "nt:unstructured");
// 将文件“ test.xml”导入到创建的节点下
FileInputStream xml = new FileInputStream("test.xml");
session.importXML(
node.getPath(), xml, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
xml.close();
session.save();
System.out.println("done.");
}
//输出存储库内容
dump(root);
} finally {
session.logout();
}
}
- 输入存储内容
private static void dump(Node node) throws RepositoryException {
// 首先输出节点路径
System.out.println(node.getPath());
// 跳过这个虚拟子树
if (node.getName().equals("jcr:system")) {
return;
}
// 输出属性
PropertyIterator properties = node.getProperties();
while (properties.hasNext()) {
Property property = properties.nextProperty();
if (property.getDefinition().isMultiple()) {
// 多值属性,打印所有值
Value[] values = property.getValues();
for (int i = 0; i < values.length; i++) {
System.out.println(
property.getPath() + " = " + values[i] .getString());
}
} else {
// 单值属性
System.out.println(
property.getPath() + " = " + property.getString());
}
}
// 最后以递归方式输出所有子节点
NodeIterator nodes = node.getNodes();
while (nodes.hasNext()) {
dump(nodes.nextNode());
}
}
参考文章
Jackrabbit的来源
Apache Jackrabbit学习
Apache Jackrabbit入门
Java Content Repository API 简介
Apache Jackrabbit官方文档