XWiki支持通知(又名Observation Events),当一个文档被修改,一个文档对象被修改或者一个wiki被创建时可以做一些动作。查看Observation参考文档了解更多内容。
有几种方法来编写事件侦听器,以应对一些事件:
本教程将在几个不同的例子展示所有的技术。
在页面保存时添加内容
我们的目标是监听DocumentCreatingEvent和DocumentUpdatingEvent事件(注意这些事件会在页面保存之前触发,因此我们代码不需要执行保存操作)。
使用一个wiki组件来实现这个例子。
本例使用{{groovy}}宏,因此需要编程权限。如果是在多租户下的一个wiki,那么意味着需要在main wiki要有编程权限。
按照下列步骤:
- 创建一个页面,例如 EventListeners.DocumentSaveListener
- 在这个页面添加一个XWiki.ComponentClass对象
- Component Role: org.xwiki.observation.EventListener
- Component Role Hint: mytest (你可以使用任何你想要的名字,它是监听器的technical id)
- Component Scope: Current Wiki这意味着监听器只能在当前wiki下是有效。Global这将使得监听器在所有租户下可用(即所有wiki)。对于Current User你不需要任何特殊的权限,但是监听器只会对你的用户可用。
- 添加一个XWiki.ComponentMethodClass对象来实现getEvents()#方法:
- 方法名:getEvents
- 方法体代码:
{{groovy}}
import org.xwiki.bridge.event.*
xcontext.method.output.value = [new DocumentCreatingEvent(), new DocumentUpdatingEvent()]
{{/groovy}}
- 添加另一个XWiki.ComponentMethodClass对象来实现getName()方法:
- 方法名:getName
- 方法体代码:
{{groovy}}
xcontext.method.output.value = "mytest"
{{/groovy}}请注意,mytest应该是你上面使用同样的technical id。
- 添加另一个XWiki.ComponentMethodClass对象来实现onEvent()方法:
- 方法名:onEvent
- 方法体代码:
{{groovy}}
def docSource = xcontext.method.input.get(1)
if (docSource.space != "EventListeners") {
docSource.setContent(docSource.content + "\n\nSome extra content...")
}
{{/groovy}}
- 保存!
当你保存EventListeners.DocumentSaveListener页面,你定义的组件(你的事件监听器)会自动注册和可用
你可以通过创建一个新的页面或者编辑一个现有的页面来验证它的效果,当你保存时,你应该看到一些额外的内容Some extra content...添加到你的页面底部。
当一个文档被修改时输出日志
在这个例子中,我们希望通过添加一个名为Main.Logs的页面来记录所有文件的改变。
通过在一个wiki页面使用Groovy来实现。
本例使用{{groovy}}宏,因此需要编程权限。如果是在多租户下的一个wiki,那么意味着需要在main wiki要有编程权限。
{{groovy}}
import org.xwiki.observation.*
import org.xwiki.observation.event.*
import org.xwiki.bridge.event.*
import org.xwiki.model.reference.*
import org.xwiki.model.*
import com.xpn.xwiki.web.*
import com.xpn.xwiki.*
class LoggingEventListener implements EventListener
{
def logReference = new EntityReference("Logs", EntityType.DOCUMENT,
new EntityReference("Main", EntityType.SPACE))
String getName()
{
// The unique name of this event listener
return "logging"
}
List<Event> getEvents()
{
// The list of events this listener listens to
return [new DocumentUpdatedEvent()]
}
// Called by the Observation Manager when an event matches the list of events returned
// by getEvents()
void onEvent(Event event, Object source, Object context)
{
// Prevent infinite recursion since in this example we log to wiki page which
// triggers a document change... :)
if (source.fullName != "Main.Logs") {
def xwiki = context.getWiki()
def document = xwiki.getDocument(logReference, context)
document.setContent("${document.getContent()}\n* ${source.fullName} has been modified!")
xwiki.saveDocument(document, "Logging event", true, context)
}
}
}
// Register against the Observation Manager
def observation = Utils.getComponent(ObservationManager.class)
observation.removeListener("logging")
def listener = new LoggingEventListener()
observation.addListener(listener)
{{/groovy}}
如果你想监听其他的事件,你可以在getEvents返回列表中添加其他事件,例如:
...
return [new DocumentUpdateEvent(), new DocumentSaveEvent(), new DocumentDeleteEvent()]
...
每当添加评论时发送邮件
我们使用Java来实现这个用例。
注意:我们要监听CommentAddedEvent事件,但是,如果你希望当一个对象被更新时接收通知,那么你应该监听XObjectUpdatedEvent事件(或者希望一个属性被更新时接收通知则监听XObjectPropertyUpdatedEvent事件)。
- 让我们用XWiki Maven Archetype来创建一个骨架项目,通过此教程。
- 请确保在你的pom.xml文件(请注意,下面例子是使用的5.4.5版本,但你可以使用任何你想要的版本)有以下的2依赖关系:
...
<dependency>
<groupId>org.xwiki.platform</groupId>
<artifactId>xwiki-platform-oldcore</artifactId>
<version>5.4.5</version>
</dependency>
<dependency>
<groupId>org.xwiki.platform</groupId>
<artifactId>xwiki-platform-mailsender</artifactId>
<version>5.4.5</version>
</dependency>
... - 在org.xwiki.contrib.internal包(包名由你决定)下创建一个CommentListener类,内容如下:
package org.xwiki.contrib.internal;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.slf4j.Logger;
import org.xwiki.component.annotation.Component;
import org.xwiki.model.EntityType;
import org.xwiki.model.reference.EntityReference;
import org.xwiki.observation.EventListener;
import org.xwiki.observation.event.Event;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.internal.event.XObjectAddedEvent;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.plugin.mailsender.MailSenderPluginApi;
@Component
@Named("CommentEventListener")
@Singleton
public class CommentEventListener implements EventListener
{
@Inject
private Logger logger;
private EntityReference commentClassReference = new EntityReference("XWikiComments", EntityType.DOCUMENT,
new EntityReference("XWiki", EntityType.SPACE));
@Override public String getName()
{
return "CommentEventListener";
}
@Override public List<Event> getEvents()
{
return Arrays.<Event>asList(new XObjectAddedEvent());
}
@Override public void onEvent(Event event, Object source, Object data)
{
XWikiDocument document = (XWikiDocument) source;
BaseObject commentObject = document.getXObject(this.commentClassReference);
if (commentObject != null) {
try {
// Get comment
String comment = commentObject.getStringValue("comment");
// Send email
XWikiContext xcontext = (XWikiContext) data;
MailSenderPluginApi mailSender = (MailSenderPluginApi) xcontext.getWiki().getPluginApi("mailsender", xcontext);
mailSender.sendTextMessage("XWiki <xwiki@no-reply>", "john@doe.com",
"[XWiki] Comment added to " + document.toString(), comment);
} catch (Exception e) {
this.logger.error("Failure in comment listener", e);
}
}
}
} - 别忘了在你项目的META-INF/components.txt文件下注册你的组件:
org.xwiki.contrib.internal.CommentEventListener
- 使用maven编译你的项目:mvn clean install,然后复制生成的JAR到你的XWiki下的WEB-INF/lib目录,然后重启XWiki。
如果你构建遇到一些问题,查看http://dev.xwiki.org/xwiki/bin/view/Community/Building
在测试之前,先确保在你的XWiki管理员后台已经设置Email相关属性。之后,在一个页面添加一条评论,你将会接收到一份邮件!
这个实现不是很好,因为邮件是在页面保存时发送,这是同步的,并且发送一封电子邮件需要一些时间。更好的方式是通过一个单独的线程来异步发送邮件,以便保存可以快速返回而不用等待邮件发送结束。这给我们亲爱的读者当作练习。
旧的通知教程
如果你使用的是旧版本的XWiki(早于2.0版本),那么你可以查看这个旧的通知教程。