最近在研发一个JIRA的插件,具体场景如下:
当测试人员提交一个问题时,需要通过QQ通知到开发人员,并且当问题属于SIT测试BUG时,需要自动的打开SVN上对应主干源代码的写权限。当开发人员修复并关闭问题时,需要自动的关闭SVN上对应主干源代码的写权限。
基本实现思路如下:
实际上实现JIRA插件这一端的程序并不困难,关键是查阅JIRA SDK相关手册,基本上没什么难度,下一篇文章,我们就来看看如何实现这个JIRA插件。这篇文章主要是关注如何实现与QQ的通讯,着实花费了不少心思。通过Google,发现目前网上大部分是基于WebQQ实现的,然后下载了一个什么iQQ的实现代码,没什么设计思想,基本上就是代码的堆叠,不过可读性还算好,基本能看懂,于是乎就有了想搞一个WebQQ客户端API库的冲动,方便今后的使用和扩展。经过几天的整理和重构终于把WebQQ核心部分抽出来并形成一个API库,以下为API接口定义:
/**
* WebQQ客户端接口
* @author Administrator
* @version $Id: WebQQClient.java, v 0.1 2013-1-21 下午2:58:32 Administrator Exp $
*/
public interface WebQQClient {
/**
* QQ登录
*
* QQ完成登录需要经过三次服务调用:
*
* - 检查QQ账户,是否需要验证码输入;
*
- 正式登录;
*
- 渠道登录;
*
*
* @param member 需要提供QQ号码和登录密码
* @return true 登录成功 false 登录失败
*/
boolean login(Member member);
/**
* 加载QQ好友详情
*
* 前置条件: 必须已经成功登录
*
* @param account 需要加载的好友QQ号码(QQ系统内部还有一个uin标识)
* @return QQ会员详情
*/
Member loadFriend(String account);
/**
* 加载QQ好友的个性化签名
*
* 前置条件: 必须已经成功登录
*
* @param account 需要加载的好友QQ号码(QQ系统内部还有一个uin标识)
* @return
*/
Member loadFriendSignature(String account);
/**
* 加载QQ好友的等级
*
* 前置条件: 必须已经成功登录
*
* @param account 需要加载的好友QQ号码(QQ系统内部还有一个uin标识)
* @return
*/
Member loadFriendLevel(String account);
/**
* 改变当前已登录QQ会员的状态
*
* 前置条件: 必须已经成功登录
*
* @param newStatus 当前的新状态
*/
void changeStatus(Status newStatus);
/**
* 向指定的QQ好友发送消息
*
* 前置条件:
*
* - 必须已经成功登录;
*
- 已经成功加载了好友列表,因为发送QQ消息需要好友的uin字段(一个内部的标识,每次登录该字段值都不一样),而非QQ号码;
*
- 已经成功启动QQ心跳检测任务,否则无法发送QQ消息;
*
*
* @param account 发送消息的好友的QQ号码
* @param message 发送的消息内容
* @return true 发送成功 false 发送失败
*/
boolean sendMessageToFriend(String account, String message);
/**
* 向指定的QQ群发送消息
*
* 前置条件:
*
* - 必须已经成功登录;
*
- 已经成功加载了好友群列表,因为发送QQ消息需要好友群的uin字段(一个内部的标识,每次登录该字段值都不一样),而非群号码;
*
- 已经成功启动QQ心跳检测任务,否则无法发送QQ消息;
*
*
* @param account 发送消息的QQ群号
* @param message 发送的消息内容
* @return
*/
boolean sendMessageToGroup(String account, String message);
/**
* QQ登出
*
* 前置条件: 必须已经成功登录
*
* @return true 登出成功 false 登出失败
*/
boolean logout();
/**
* 查询好友列表
*
* 前置条件: 必须已经成功登录
*
* @return 好友列表
*/
List findFriends();
/**
* 查询在线的好友列表
*
* 前置条件: 必须已经成功登录
*
* @return 在线好友列表
*/
List findOnlineFriends();
/**
* 查询QQ群列表
*
* 前置条件: 必须已经成功登录
*
* @return
*/
List findGroups();
}
该API库的主要功能有:
当然因为是一个API库,所以和UI相关的功能基本上都没有实现,有待感兴趣的同学继续完善。
该API库的依赖库如下:
如果是使用maven管理依赖的话,那就简单了,可以看我项目源代码中提供的pom.xml文件。
以下介绍使用的方法,由于该API是依赖Spring框架的,所以要做的就是配置几个Bean,以下假设您使用Maven工具以及Spring进行开发:
1. 在pom.xml中配置如下依赖:
org.storevm
webqq-client
1.0.0
当然,这个Jar在Maven中央库是没有的,所以需要在pom.xml中添加上我的Maven私有库地址:
StoreVM-repo
StoreVM Maven Repository
http://mvn.storevm.org:8081/mvn/content/groups/public
true
true
OK,最后执行
mvn eclipse:eclipse
回到Eclipse上,刷新一下自己的项目,就能看到新加入的库了。
2. 接着在您项目的Spring配置文件中定义如下的 Bean:
WebQQClientContainer类实现了InitializingBean和DisposableBean接口,所以在Bean加载的时候会执行QQ登录相关的操作,而在Bean卸载的时候会执行了QQ登出的操作,部分源代码如下:
/**
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
Member member = new Member();
member.getAccount().setAccount(qqNumber);
member.getAccount().setPassword(qqPassword);
member.setStatus(Status.ONLINE);
//登录WebQQ,登录之后就可以发送消息了
boolean success = webQQClient.login(member);
if (success) {
//如果登录成功,则加载在线好友列表和QQ群列表
List olineFriends = webQQClient.findOnlineFriends();
List groups = webQQClient.findGroups();
//启动心跳检测任务
heartbeatTaskExecutor.startup();
LogUtils.info(LOGGER, "启动WebQQ客户端容器完成. 在线好友数=[{0}], QQ群数=[{1}]", olineFriends.size(),
groups.size());
} else {
LogUtils.warn(LOGGER, "启动WebQQ客户端失败, account={0}", qqNumber);
}
}
/**
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
@Override
public void destroy() throws Exception {
//当Bean销毁时,关闭WebQQ客户端管理容器
heartbeatTaskExecutor.shutdown();
boolean success = webQQClient.logout();
if (success) {
LogUtils.warn(LOGGER, "关闭WebQQ客户端完成, account={0}", qqNumber);
} else {
LogUtils.warn(LOGGER, "关闭WebQQ客户端失败, account={0}", qqNumber);
}
}
如果您的应用程序是Web程序,我也写了一个ServletContextListener接口用于在Web容器启动时初始化WebQQ客户端:
1. 在web.xml中添加如下配置:
account
您的QQ号码
password
您的QQ登录密码
org.storevm.im.WebQQClinetListener
通过上述配置,当web容器启动时会执行QQ登录操作,然后您就可以在应用程序的运行过程中发送QQ消息,当然在容器关闭时会执行QQ登出的操作。
/**
* 接收QQ消息的监听器实现
* @author Administrator
* @version $Id: ReceiveFriendMessageListener.java, v 0.1 2013-1-24 下午3:28:15 Administrator Exp $
*/
public class ReceiveMessageListener implements WebQQEventListener, InitializingBean, DisposableBean {
/* logger */
private static final Logger LOGGER = Logger.getLogger(ReceiveMessageListener.class);
/* 事件发布器 */
private WebQQEventPublisher eventPublisher;
/**
* 构造函数
*/
public ReceiveMessageListener() {
}
/**
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
@Override
public void destroy() throws Exception {
eventPublisher.unregister(this); //注销
}
/**
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
eventPublisher.register(this); //注册监听器
}
/**
* @see org.storevm.im.core.event.WebQQEventListener#onWebQQEvent(org.storevm.im.core.event.WebQQEvent)
*/
@Override
public void onWebQQEvent(WebQQEvent event) {
LogUtils.info(LOGGER, "接收到QQ事件, event.code={0}, body={1}", event.getEventCode(),
event.getBody());
}
/**
* Setter method for property eventPublisher.
*
* @param eventPublisher value to be assigned to property eventPublisher
*/
public void setEventPublisher(WebQQEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
}
以上代码的关键点是注册监听器和onWebQQEvent方法的实现。你也可以注册多个监听器,用于监听多个事件。更多的单元测试请下载源代码查看。
以下提供SVN源代码地址:
http://svn.storevm.org/svn/webqqclient/trunk
用户名和密码均为:reader
项目使用Maven进行管理,关于maven的使用请自行参考网上其他文章。最后希望对此有兴趣的同学可以相互交流经验技术。