EWS Java API 的基本使用

2018/12/20 更新:

这篇文章的同步方式存在缺陷,在仔细研究Exchange后有不少新的收获,找到了更好的解决方案,请移步这里观看~

Exchange 会议同步入门指南


需求功能

最近公司接到一个需求,将客户的 Exchange 服务器中的会议信息,同步到公司现有的会议管理系统中(MMS),为了实现这个需求,需要做以下几件事:

  1. 从 MMS 预定会议时,需要将会议信息推送到Exchange服务器中。
  2. 从Exchange预定会议时,在MMS系统中需要有一个监听机制(EWS 中称“通知”/Notifications),实时监测会议信息的变化,并将变化后的数据同步到MMS系统。

 

准备工作

获取 EWS Java API ,请移步:https://github.com/OfficeDev/ews-java-api

 

简单实现

1.获得 EWS 服务

传入参数为 Exchange 服务器的版本号,根据实际情况选择。

//在 Notifications 中,ExchangeVersion.Exchange2010 版本不支持流式通知,需要不断的执行 GetEvents 方法达到实时监听。
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010);    
//Exchange服务器的域名,使用ip可能会连接失败,如服务器在本地,没有域名可以在host文件中添加一条域名解析规则
String serverHost = "exchange.server.host"    
//登录的账号和密码,账号一定是可以登录进去的账号,不一定是邮箱地址
ExchangeCredentials credentials = new WebCredentials("emailAddress", "password");    
service.setCredentials(credentials);
//固定写法
service.setUrl(new URI("https://" + serverHost + "/ews/exchange.asmx"));   
service.setCredentials(credentials);
service.setTraceEnabled(true);

 

2. 查询 Exchange 的会议信息

查找距现在24小时以内开始的所有会议邮件(Appoinement)

Date start = new Date();
Date end = new Date(start.getTime() + 1000*3600*24);

CalendarView cView = new CalendarView(start, end);
//指定要查看的邮箱
FolderId folderId = new FolderId(WellKnownFolderName.Calendar, new Mailbox(emailAddress));
FindItemsResults findResults = null;
try {
    findResults = service.findAppointments(folderId, cView);
} catch (Exception e) {
    e.printStackTrace();
}
ArrayList appointmentItems = findResults==null?null:findResults.getItems();

遍历结果,获取会议信息

for(Appointment ap:allAppointment){
  ap.load();

  String subject = ap.getSubject();
  //如邮箱主题以“已取消”开头,说明该会议已经被取消
  if(subject.startsWith("已取消")){
	  continue;
  }

  //得到HTML格式的内容,通过工具类提取body标签的内容
  String html_body = ap.getBody().toString();
  String body = DataUtils.getContentFromHtml(huml_body);
  
  //会议的开始和结束时间
  Date start = ap.getStart();
  Date end = ap.getEnd();
  
  //会议使用的资源
  List resources = ap.getResources().getItems();

  //参加会议的员工
  List RequiredAttendees = ap.getRequiredAttendees().getItems();
  List OptionalAttendees = ap.getOptionalAttendees().getItems();

}

从HTML提取body信息的工具类

public class DataUtils {

    public static String getContentFromHtml(String content){
        content = content.replaceAll("]+>", ""); //剔出的标签
        content = content.replaceAll("\\s*|\t|\r|\n", "");
        content = content.replaceAll(" ", "");
        content = content.replaceAll("\n", "");
        return content;
    }
}

3. 向 Exchange 发送一条会议邮件

Appointment appointment = null;
try {
	appointment = new Appointment(service);
	appointment.setSubject("会议主题");
	appointment.setBody(MessageBody.getMessageBodyFromText("会议消息体"));

	appointment.setStart(new Date());
	appointment.setEnd(new Date().getTime()+1000*3600*24);

	appointment.setLocation("会议位置");
	appointment.getResources().add("会议资源账号,如:[email protected]");

	appointment.getRequiredAttendees().add("必须参加的员工的账号");
	appointment.getOptionalAttendees().add("可选参加的员工的账号");
	
	appointment.save();
	appointment.update(ConflictResolutionMode.AutoResolve);
} catch (Exception e) {
	e.printStackTrace();
}

4. 建立监听,接收会议变化事件的通知

try {
	//将需要监听的事件作为参数传入构造方法
	IAsyncResult asyncresult = service.beginSubscribeToPullNotificationsOnAllFolders(null, null, 5, null, EventType.NewMail, EventType.Created, EventType.Deleted);

	PullSubscription subscription = service.endSubscribeToPullNotifications(asyncresult);
	
	//由于博主Exchange服务器版本限制,只能通过定时调用GetEvent方法达到实时监听
	TimerTask task = new TimerTask() {
		@Override
		public void run() {
			try {
				GetEventsResults events = subscription.getEvents();
				Iterable itemEvents = events.getItemEvents();

				for(ItemEvent itemEvent:itemEvents){
					if(itemEvent.getEventType() == EventType.Created){
						Item item = null;
						try{
							item = Item.bind(service,itemEvent.getItemId());
						}catch (ServiceResponseException e){
							//找不到该邮件
							continue;
						}
						if(item instanceof Appointment){
							Appointment appointment = Appointment.bind(service, item.getId());
							//得到发生变化的会议,执行业务逻辑
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	};

	new Timer().scheduleAtFixedRate(task, delay, 1 * 10 * 1000);

} catch (URISyntaxException e) {
	e.printStackTrace();
} catch (Exception e) {
	e.printStackTrace();
}

 

遗留问题

  • 监听效果不够优雅,使用这种异步订阅方式,在Exchange服务器中创建一个会议,会被触发两次。并且,修改会议或者取消会议,都会被 EventType.Created 响应一次
  • 如果使用同步订阅方式,得到的 itemID 不能和 Appoinement 绑定,即无法获取改动的会议信息

 

 


参考资料:

https://github.com/OfficeDev/ews-java-api/wiki/Getting-Started-Guide#using-pull-notifications-with-the-ews-java-api

https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/notification-subscriptions-mailbox-events-and-ews-in-exchange

你可能感兴趣的:(Office,相关)