package com.sqj.openfire.chat.logs; import java.io.File; import java.util.Date; import java.util.List; import java.util.Map; import java.util.UUID; import org.apache.commons.lang.StringUtils; import org.dom4j.DocumentFactory; import org.dom4j.Element; import org.jivesoftware.openfire.OfflineMessageStore; import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.container.Plugin; import org.jivesoftware.openfire.container.PluginManager; import org.jivesoftware.openfire.interceptor.InterceptorManager; import org.jivesoftware.openfire.interceptor.PacketInterceptor; import org.jivesoftware.openfire.interceptor.PacketRejectedException; import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.user.UserManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xmpp.packet.IQ; import org.xmpp.packet.JID; import org.xmpp.packet.Message; import org.xmpp.packet.Packet; import org.xmpp.packet.Presence; import com.sqj.openfire.chat.logs.entity.Chat; import com.sqj.openfire.chat.logs.entity.XmlToMap; /** <b>function:</b> 聊天记录插件 * @author shm * @createDate 2016-3-14 * @version 1.0 */ public class ChatLogsPlugin implements PacketInterceptor, Plugin { private static final Logger log = LoggerFactory.getLogger(ChatLogsPlugin.class); private static PluginManager pluginManager; private static DbChatLogsManager logsManager; private InterceptorManager interceptorManager; public ChatLogsPlugin() { this.interceptorManager = InterceptorManager.getInstance(); logsManager = DbChatLogsManager.getInstance(); } /** * * <b>function:</b> 拦截消息核心方法,Packet就是拦截消息对象 * * @author shm * * @createDate 2016-3-14 * */ @Override public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed) throws PacketRejectedException { if (session != null) { //debug(packet, incoming, processed, session); } JID recipient = packet.getTo(); if (recipient != null) { String username = recipient.getNode(); // 广播消息或是不存在/没注册的用户. if (username == null || !UserManager.getInstance().isRegisteredUser(recipient)) { return; } else if (!XMPPServer.getInstance().getServerInfo().getXMPPDomain().equals(recipient.getDomain())) { // 非当前openfire服务器信息 return; } else if ("".equals(recipient.getResource())) { } } this.doAction(packet, incoming, processed, session); } /** * <b>function:</b> 执行保存/分析聊天记录动作 * @author shm * @createDate 2016-3-14 * @param packet 数据包 * @param incoming true表示发送方 * @param session 当前用户session */ private void doAction(Packet packet, boolean incoming, boolean processed, Session session) { Packet copyPacket = packet.createCopy(); if (packet instanceof Message) { Message message = (Message) copyPacket; // 一对一聊天,单人模式 if (message.getType() == Message.Type.chat) { log.info("单人聊天信息:{}", message.toXML()); //debug("单人聊天信息:" + message.toXML()); // 程序执行中;是否为结束或返回状态(是否是当前session用户发送消息) if (processed || !incoming) { return; } java.sql.Timestamp date = new java.sql.Timestamp(new Date().getTime()); //在原有的扩展xml中添加发送日期子节点 Element chatInfoElement = message.getElement().element("chatinfo"); Element timeElement = DocumentFactory.getInstance().createDocument().addElement("sendtime"); timeElement.setText(String.valueOf(date.getTime())); chatInfoElement.add(timeElement); //logsManager.add(this.get(packet, incoming, session)); logsManager.addByMap(this.getMsgInfo(packet, incoming, session, date)); //保存到离线消息表,客户端收到后调用删除离线消息功能,这样可确保即使网络突然掉线或不好的情况下消息丢失的问题 OfflineMessageStore offlineMessageStore = new OfflineMessageStore(); offlineMessageStore.addMessage(message); //消息回执 Message receiptMessage = new Message(); receiptMessage.setTo(message.getFrom()); receiptMessage.setType(Message.Type.normal); Element received = receiptMessage.addChildElement("received", "urn:xmpp:receipts"); received.addAttribute("id", message.getID()); received.addAttribute("type", "normal"); log.info("回执内容:" + receiptMessage); // 判断接受者是否在线,2代表离线状态,1代表在线状态,0代表用戶不存在 //注意一定要修改Constant类中的url,否则url错误或导致消息发送很慢,因为url不对时查找用户是否在线会浪费很多时间 /*if (IsOnLineUtils.IsUserOnLine(message.getTo()) == 1) { received.addAttribute("status", "1"); } else if (IsOnLineUtils.IsUserOnLine(message.getTo()) == 0) { received.addAttribute("status", "0"); } else if (IsOnLineUtils.IsUserOnLine(message.getTo()) == 2) { received.addAttribute("status", "2"); }*/ try { XMPPServer.getInstance().getPacketDeliverer().deliver(receiptMessage); log.info("服务端回执成功!"); } catch (Exception e) { e.printStackTrace(); } // 群聊天,多人模式 } else if (message.getType() == Message.Type.groupchat) { List<?> els = message.getElement().elements("x"); if (els != null && !els.isEmpty()) { log.info("群聊天信息:{}", message.toXML()); debug("群聊天信息:" + message.toXML()); } else { log.info("群系统信息:{}", message.toXML()); debug("群系统信息:" + message.toXML()); } // 其他信息 }else { log.info("其他信息:{}", message.toXML()); //debug("其他信息:" + message.toXML()); } } else if (packet instanceof IQ) { IQ iq = (IQ) copyPacket; if (iq.getType() == IQ.Type.set && iq.getChildElement() != null && "session".equals(iq.getChildElement().getName())) { log.info("用户登录成功:{}", iq.toXML()); //debug("用户登录成功:" + iq.toXML()); } } else if (packet instanceof Presence) { Presence presence = (Presence) copyPacket; if (presence.getType() == Presence.Type.unavailable) { log.info("用户退出服务器成功:{}", presence.toXML()); //debug("用户退出服务器成功:" + presence.toXML()); } } } /** * <b>function:</b> 创建一个聊天记录实体对象,并设置相关数据 * @author shm * @createDate 2016-3-14 * @param packet 数据包 * @param incoming 如果为ture就表明是发送者 * @param session 当前用户session * @return 聊天实体 */ @SuppressWarnings("unchecked") private Chat get(Packet packet, boolean incoming, Session session) { Message message = (Message) packet; JID jid = session.getAddress(); Map<String, Object> map = XmlToMap.xmlToHashMap(message.toXML()); Chat chat = new Chat(); if(map.containsKey("zid") && !"null".equals(map.get("zid")) && !StringUtils.isEmpty(map.get("zid")+"")){ chat.setId(map.get("zid")+""); }else{ chat.setId(UUID.randomUUID().toString().replace("-", "")); } chat.setCaseId(map.get("caseid")+""); chat.setContent(message.getBody()); chat.setCreator(jid.getNode()); chat.setSender(jid.getNode()); chat.setModifier(jid.getNode()); chat.setSendee(message.getTo().getNode()); chat.setIdentity(map.get("identity")+""); chat.setzType(map.get("ztype")+""); chat.setSenderId(map.get("senderid")+""); chat.setSendeeId(map.get("sendeeid")+""); if(map.get("msglength") != null && !"".equals(map.get("msglength"))) { chat.setMsgLength(Integer.parseInt(map.get("msglength")+"")); } return chat; } @SuppressWarnings({ "unchecked", "rawtypes" }) private Map getMsgInfo(Packet packet, boolean incoming, Session session, java.sql.Timestamp date) { Message message = (Message) packet; Map<String, Object> map = XmlToMap.xmlToHashMap(message.toXML()); map.put("content", message.getBody()); map.put("sendtime", date); log.info("tag:{}", map.get("tag")); //debug("tag:" + map.get("tag")); return map; } /** * * <b>function:</b> 调试信息 * @author shm * @createDate 2016-3-14 * @param packet 数据包 * @param incoming 如果为ture就表明是发送者 * @param processed 执行 * @param session 当前用户session */ private void debug(Packet packet, boolean incoming, boolean processed, Session session) { //String info = "[ packetID: " + packet.getID() + ", to: " + packet.getTo() + ", from: " + packet.getFrom() + ", incoming: " + incoming + ", processed: " + processed + " ]"; StringBuilder info = new StringBuilder(); info.append("[ packetID: ").append(packet.getID()).append(", to: ").append(packet.getTo()).append(", from: ").append(packet.getFrom()).append(", incoming: ").append(incoming).append(", processed: ").append(processed).append(" ]"); long timed = System.currentTimeMillis(); debug("################### start ###################" + timed); debug("id:" + session.getStreamID() + ", address: " + session.getAddress()); debug("info: " + info); debug("xml: " + packet.toXML()); debug("################### end #####################" + timed); log.info("id:" + session.getStreamID() + ", address: " + session.getAddress()); log.info("info: {}", info); log.info("plugin Name: " + pluginManager.getName(this) + ", xml: " + packet.toXML()); } private void debug(Object message) { if (true) { System.out.println(message); } } @Override public void destroyPlugin() { interceptorManager.removeInterceptor(this); debug("销毁聊天记录插件成功!"); } @Override public void initializePlugin(PluginManager manager, File pluginDirectory) { interceptorManager.addInterceptor(this); pluginManager = manager; debug("安装聊天记录插件成功!"); } /* // 判断接受者是否在线,2代表离线状态,1代表在线状态,0代表用戶不存在 if (IsOnLineUtils.IsUserOnLine(message.getTo()) == 2) { // 离线時,向offline表写数据 OfflineMessageStore offlineMessageStore = new OfflineMessageStore(); offlineMessageStore.addMessage(message); // 向客户端发回执 Message receiptMessage = new Message(); receiptMessage.setTo(message.getFrom()); receiptMessage.setType(Message.Type.normal); Element received = receiptMessage.addChildElement("received", "urn:xmpp:receipts"); received.setAttributeValue("id", message.getID()); System.out.println("0000000000回执内容" + receiptMessage); try { XMPPServer.getInstance().getPacketDeliverer().deliver(receiptMessage); System.out.println("服务端回执成功!"); } catch (Exception e) { e.printStackTrace(); } }*/ }