Mina聊天服务端实现思路:在用户登录的时候。连接服务端而且验证登录用户,假设成功,则将IoSession保存到map<账号,IoSession>中,而且通知该用户的好友上线,然

后再请求好友列表;若不成功,则断开连接。

自己定义协议格式:包头+包体

包头(10字节):包头长度(short)+ 消息类型(byte)+ 内容类型(byte) +  消息命令(short)+ 包体长度(int)

包体:JSON字符串

自己定义编码解码:因为数据在网络传输过程中都是以二进制传输的,所以我们能够自己定义自己的编码解码格式。具体实现代码能够看以下的

ChatServerDecode和ChatServerEncode

数据库(chat):三张表 用户表(user)。好友表(friends),分类表(category)

  1. /*
  2. Navicat MySQL Data Transfer
  3.  
  4. Source Server : bufoon
  5. Source Server Version : 50527
  6. Source Host : localhost:3306
  7. Source Database : chat
  8.  
  9. Target Server Type : MYSQL
  10. Target Server Version : 50527
  11. File Encoding : 65001
  12.  
  13. Date: 2014-06-29 23:30:28
  14. */
  15.  
  16. SET FOREIGN_KEY_CHECKS=0;
  17.  
  18. -- ----------------------------
  19. -- Table structure for category
  20. -- ----------------------------
  21. DROP TABLE IF EXISTS `category`;
  22. CREATE TABLE `category` (
  23. `id` int(11) NOT NULL AUTO_INCREMENT,
  24. `user_id` int(11) DEFAULT NULL,
  25. `name` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
  26. `create_time` datetime DEFAULT NULL,
  27. PRIMARY KEY (`id`),
  28. KEY `FK_CATEGOFY_USER_ID` (`user_id`),
  29. CONSTRAINT `FK_CATEGOFY_USER_ID` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE
  30. ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
  31.  
  32. -- ----------------------------
  33. -- Records of category
  34. -- ----------------------------
  35. INSERT INTO `category` VALUES ('1', '1', '我的好友', '2014-06-29 19:00:25');
  36. INSERT INTO `category` VALUES ('3', '2', '我的好友', '2014-06-29 19:00:55');
  37. INSERT INTO `category` VALUES ('4', '3', '我的好友', '2014-06-29 19:01:00');
  38. INSERT INTO `category` VALUES ('5', '1', '同学', '2014-06-29 20:39:04');
  39.  
  40. -- ----------------------------
  41. -- Table structure for friends
  42. -- ----------------------------
  43. DROP TABLE IF EXISTS `friends`;
  44. CREATE TABLE `friends` (
  45. `id` int(11) NOT NULL AUTO_INCREMENT,
  46. `user_id` int(11) DEFAULT NULL,
  47. `friend_id` int(11) DEFAULT NULL,
  48. `category_id` int(11) DEFAULT NULL,
  49. `create_time` datetime DEFAULT NULL,
  50. PRIMARY KEY (`id`),
  51. KEY `FK_FRIENDS_USER_ID` (`user_id`),
  52. KEY `FK_FRIENDS_CATEGORY_ID` (`category_id`),
  53. KEY `FK_FRIENDS_FUSER_ID` (`friend_id`),
  54. CONSTRAINT `FK_FRIENDS_CATEGORY_ID` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`) ON DELETE CASCADE,
  55. CONSTRAINT `FK_FRIENDS_FUSER_ID` FOREIGN KEY (`friend_id`) REFERENCES `user` (`id`) ON DELETE CASCADE,
  56. CONSTRAINT `FK_FRIENDS_USER_ID` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE
  57. ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
  58.  
  59. -- ----------------------------
  60. -- Records of friends
  61. -- ----------------------------
  62. INSERT INTO `friends` VALUES ('1', '1', '2', '1', '2014-06-21 23:35:16');
  63. INSERT INTO `friends` VALUES ('2', '1', '3', '1', '2014-06-21 23:35:22');
  64. INSERT INTO `friends` VALUES ('3', '2', '1', '3', '2014-06-22 02:09:24');
  65. INSERT INTO `friends` VALUES ('4', '3', '1', '4', '2014-06-22 02:09:29');
  66.  
  67. -- ----------------------------
  68. -- Table structure for user
  69. -- ----------------------------
  70. DROP TABLE IF EXISTS `user`;
  71. CREATE TABLE `user` (
  72. `id` int(11) NOT NULL AUTO_INCREMENT,
  73. `name` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
  74. `user_num` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL,
  75. `password` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
  76. `regist_time` datetime DEFAULT NULL,
  77. `sex` varchar(2) COLLATE utf8_unicode_ci DEFAULT NULL,
  78. `signature` varchar(300) COLLATE utf8_unicode_ci DEFAULT NULL,
  79. `head_pic_path` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL,
  80. `is_online` varchar(1) COLLATE utf8_unicode_ci DEFAULT NULL,
  81. PRIMARY KEY (`id`)
  82. ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
  83.  
  84. -- ----------------------------
  85. -- Records of user
  86. -- ----------------------------
  87. INSERT INTO `user` VALUES ('1', '张三', '12345', '12345', '2014-06-20 23:32:26', '男', null, null, '0');
  88. INSERT INTO `user` VALUES ('2', '李四', '123456', '123456', '2014-06-20 23:32:31', '女', null, null, '1');
  89. INSERT INTO `user` VALUES ('3', '王二', '1234567', '1234567', '2014-06-21 11:29:41', '男', null, null, '1');

项目文件夹结构:

须要的jar包:

ChatServer.java

  1. package com.bufoon.main;
  2.  
  3. import java.io.IOException;
  4. import java.net.InetSocketAddress;
  5.  
  6. import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
  7. import org.apache.mina.core.session.IdleStatus;
  8. import org.apache.mina.filter.codec.ProtocolCodecFilter;
  9. import org.apache.mina.filter.keepalive.KeepAliveFilter;
  10. import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
  11. import org.apache.mina.filter.keepalive.KeepAliveRequestTimeoutHandler;
  12. import org.apache.mina.filter.logging.LogLevel;
  13. import org.apache.mina.filter.logging.LoggingFilter;
  14. import org.apache.mina.transport.socket.SocketAcceptor;
  15. import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
  16.  
  17. import com.bufoon.codeFactory.ChatServerCodecFactory;
  18. import com.bufoon.handle.ChatServerHandle;
  19. import com.bufoon.handle.KeepAliveMessageFactoryImpl;
  20. import com.bufoon.handle.KeepAliveRequestTimeoutHandlerImpl;
  21.  
  22. public class ChatServer {
  23. private static final int PORT = 7073;
  24. //30秒后超时
  25. private static final int IDELTIMEOUT = 30;
  26. //15秒发送一次心跳包
  27. private static final int HEARTBEATRATE = 15;
  28.  
  29. private static SocketAcceptor acceptor;
  30. public static SocketAcceptor getAcceptor(){
  31. if(null==acceptor){
  32. // 创建非堵塞的server端的Socket连接
  33. acceptor = new NioSocketAcceptor();
  34. }
  35. return acceptor;
  36. }
  37.  
  38. public static boolean serverStart() {
  39. DefaultIoFilterChainBuilder filterChain = getAcceptor().getFilterChain();
  40. // 加入编码过滤器 处理乱码、编码问题
  41. filterChain.addLast("codec", new ProtocolCodecFilter(new ChatServerCodecFactory()));
  42. LoggingFilter loggingFilter = new LoggingFilter();
  43. loggingFilter.setMessageReceivedLogLevel(LogLevel.INFO);
  44. loggingFilter.setMessageSentLogLevel(LogLevel.INFO);
  45. // 加入日志过滤器
  46. filterChain.addLast("loger", loggingFilter);
  47. // 设置核心消息业务处理器
  48. getAcceptor().setHandler(new ChatServerHandle());
  49. KeepAliveMessageFactory heartBeatFactory = new KeepAliveMessageFactoryImpl();
  50. KeepAliveRequestTimeoutHandler heartBeatHandler = new KeepAliveRequestTimeoutHandlerImpl();
  51. KeepAliveFilter heartBeat = new KeepAliveFilter(heartBeatFactory,IdleStatus.BOTH_IDLE, heartBeatHandler);
  52. // 是否回发
  53. heartBeat.setForwardEvent(true);
  54. // 发送频率
  55. heartBeat.setRequestInterval(HEARTBEATRATE);
  56. // getAcceptor().getFilterChain().addLast("heartbeat", heartBeat);
  57. getAcceptor().getSessionConfig().setBothIdleTime(30);
  58. // 设置session配置,30秒内无操作进入空暇状态
  59. getAcceptor().getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, IDELTIMEOUT);
  60. try {
  61. // 绑定端口7033
  62. getAcceptor().bind(new InetSocketAddress(PORT));
  63. return true;
  64. } catch (IOException e) {
  65. e.printStackTrace();
  66. }
  67. return false;
  68. }
  69. public static void main(String[] args) {
  70. ChatServer.serverStart();
  71. System.out.println("服务器启动...");
  72. }
  73. }

ChatServerHandle.java

  1. package com.bufoon.handle;
  2.  
  3. import java.sql.ResultSet;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import java.util.Map;
  7.  
  8. import net.sf.json.JSONArray;
  9. import net.sf.json.JSONObject;
  10.  
  11. import org.apache.mina.core.service.IoHandlerAdapter;
  12. import org.apache.mina.core.session.IdleStatus;
  13. import org.apache.mina.core.session.IoSession;
  14. import org.apache.mina.example.chat.ChatProtocolHandler;
  15. import org.slf4j.Logger;
  16. import org.slf4j.LoggerFactory;
  17.  
  18. import com.bufoon.model.CategoryModel;
  19. import com.bufoon.model.FriendsModel;
  20. import com.bufoon.model.LoginModel;
  21. import com.bufoon.model.PackageHead;
  22. import com.bufoon.model.SendModel;
  23. import com.bufoon.model.UserModel;
  24. import com.bufoon.util.BaseDAO;
  25. import com.bufoon.util.DBUtil;
  26. import com.bufoon.util.MessageType;
  27.  
  28. public class ChatServerHandle extends IoHandlerAdapter {
  29. private final static Logger logger = LoggerFactory.getLogger(ChatProtocolHandler.class);
  30.  
  31. public static Map<String, IoSession> sessionMap = new HashMap<String, IoSession>();
  32. @Override
  33. public void sessionCreated(IoSession session) throws Exception {
  34. logger.info("创建连接");
  35. }
  36.  
  37. @Override
  38. public void sessionOpened(IoSession session) throws Exception {
  39. logger.info("打开连接");
  40. }
  41.  
  42. @Override
  43. public void sessionClosed(IoSession session) throws Exception {
  44. logger.info("关闭连接");
  45. String userNum = (String) session.getAttribute("userNum");
  46. String sql = "update user set is_online=1 where user_num like'" + userNum + "'";
  47. DBUtil.getInstance().executeUpdate(sql);
  48. sessionMap.remove(userNum);
  49. //改动下线。通知
  50. String userSql = "select * from user where user_num like '" + userNum + "'";
  51. UserModel userModel = BaseDAO.getInstance().findUserModel(userSql);
  52. String friendListSql = "select * from friends where user_id=" + userModel.getId();
  53. List<FriendsModel> list = BaseDAO.getInstance().findFriendsList(friendListSql);
  54. for (FriendsModel friendsModel : list) {
  55. String fUserSql = "select * from user where id=" + friendsModel.getFriendId();
  56. UserModel userModel2 = BaseDAO.getInstance().findUserModel(fUserSql);
  57. IoSession is = sessionMap.get(userModel2.getUserNum());
  58. if (is != null) {
  59. PackageHead ph = new PackageHead();
  60. Map<String, Object> object = new HashMap<String, Object>();
  61. object.put("userNum", userModel2.getUserNum());
  62. object.put("status", 1); //下线
  63. String content = JSONObject.fromObject(object).toString();
  64. ph.setPackageHeadLength(10);
  65. ph.setMessageCommand(MessageType.USER_ON_OFF_LINE_NOTICE);
  66. ph.setContentType(MessageType.CONTENT_TYPE_OBJECT);
  67. ph.setMessageType(MessageType.MESSAGE_TYPE_PUSH);
  68. ph.setPackageBodyLength(content.getBytes().length);
  69. ph.setPackageBodyContent(content);
  70. is.write(ph);
  71. }
  72. }
  73. }
  74.  
  75. @Override
  76. public void sessionIdle(IoSession session, IdleStatus status)
  77. throws Exception {
  78. logger.info("进入空暇");
  79. }
  80.  
  81. @Override
  82. public void exceptionCaught(IoSession session, Throwable cause)
  83. throws Exception {
  84. logger.warn("异常.", cause);
  85. session.close(true);
  86. }
  87.  
  88. @Override
  89. public void messageReceived(IoSession session, Object message)
  90. throws Exception {
  91. System.out.println(message);
  92. PackageHead ph = (PackageHead) message;
  93. System.out.println("还有没有这个session:" + sessionMap.size());
  94. switch (ph.getMessageCommand()) {
  95. case MessageType.LOGIN_VERIFY: //登录请求
  96. LoginModel loginModel = (LoginModel)JSONObject.toBean(JSONObject.fromObject(ph.getPackageBodyContent()), LoginModel.class);
  97. String username = loginModel.getUsername();
  98. IoSession is = sessionMap.get(username);
  99. Map<String, Object> map = new HashMap<String, Object>();
  100. if (!DBUtil.getInstance().isExit("user", "user_num", username)) {
  101. System.out.println("用户不存在");
  102. map.put("status", 1);
  103. map.put("info", "用户不存在");
  104. map.put("username", username);
  105. } else if (is != null && is.isConnected()) {
  106. System.out.println("用户已登录");
  107. map.put("status", 2);
  108. map.put("info", "用户已登录");
  109. map.put("username", username);
  110. } else if (!DBUtil.getInstance().isExit("user", new String[]{"user_num", "password"}, new Object[]{username, loginModel.getPassword()})) {
  111. System.out.println("用户密码错误");
  112. map.put("status", 3);
  113. map.put("info", "用户密码错误");
  114. map.put("username", username);
  115. } else if (DBUtil.getInstance().isExit("user", new String[]{"user_num", "password"}, new Object[]{username, loginModel.getPassword()})) {
  116. String sql = "select * from user where user_num like '" + username + "'";
  117. ResultSet rs = DBUtil.getInstance().executeQuery(sql);
  118. UserModel vo = null;
  119. while (rs.next()) {
  120. vo = new UserModel();
  121. vo.setId(rs.getInt("id"));
  122. vo.setUsername(rs.getString("name"));
  123. vo.setUserNum(rs.getString("user_num"));
  124. vo.setPassword(rs.getString("password"));
  125. vo.setSex(rs.getString("sex"));
  126. vo.setSignature(rs.getString("signature"));
  127. vo.setIsOnline(rs.getInt("is_online"));
  128. break;
  129. }
  130. if (vo != null) {
  131. map.put("username", vo.getUsername());
  132. }
  133. map.put("status", 0);
  134. map.put("info", "成功");
  135. map.put("userNum", username);
  136. map.put("userVO", vo);
  137. session.setAttribute("userNum", username);
  138. sessionMap.put(username, session);
  139. }
  140. String onLinesql = "update user set is_online=0 where user_num like'" + username + "'";
  141. DBUtil.getInstance().executeUpdate(onLinesql);
  142. String content = JSONObject.fromObject(map).toString();
  143. ph.setMessageCommand(MessageType.LOGIN_VERIFY_ACK);
  144. ph.setContentType(MessageType.CONTENT_TYPE_OBJECT);
  145. ph.setMessageType(MessageType.MESSAGE_TYPE_REQUEST);
  146. ph.setPackageBodyLength(content.getBytes().length);
  147. ph.setPackageBodyContent(content);
  148. session.write(ph);
  149. String friendSql = "select * from user where user_num like '" + username + "'";
  150. ResultSet rs1 = DBUtil.getInstance().executeQuery(friendSql);
  151. Map<String, Object> object = new HashMap<String, Object>();
  152. object.put("userNum", username);
  153. object.put("status", 0);
  154. content = JSONObject.fromObject(object).toString();
  155. ph.setMessageCommand(MessageType.USER_ON_OFF_LINE_NOTICE);
  156. ph.setContentType(MessageType.CONTENT_TYPE_OBJECT);
  157. ph.setMessageType(MessageType.MESSAGE_TYPE_PUSH);
  158. ph.setPackageBodyLength(content.getBytes().length);
  159. ph.setPackageBodyContent(content);
  160. while (rs1.next()) {
  161. String sql1 = "select * from friends where user_id=" + rs1.getInt("id");
  162. ResultSet rs2 = DBUtil.getInstance().executeQuery(sql1);
  163. while(rs2.next()){
  164. String sql2 = "select * from user where id=" + rs2.getInt("friend_id");
  165. ResultSet rs3 = DBUtil.getInstance().executeQuery(sql2);
  166. while(rs3.next()){
  167. IoSession iso = sessionMap.get(rs3.getString("user_num"));
  168. if(iso != null){
  169. iso.write(ph);
  170. }
  171. }
  172. }
  173. }
  174. break;
  175. case MessageType.FRIEND_LIST: //好友列表请求
  176. JSONObject obj = JSONObject.fromObject(ph.getPackageBodyContent());
  177. String userId = obj.getString("userId");
  178. String friendListSql = "select * from friends where user_id=" + userId;
  179. List<FriendsModel> friendList = BaseDAO.getInstance().findFriendsList(friendListSql);
  180. String categorySql = "select * from category where user_id=" + userId;
  181. List<CategoryModel> categoryList = BaseDAO.getInstance().findCategoryList(categorySql);
  182. for (CategoryModel categoryModel : categoryList) {
  183. for (FriendsModel friendModel : friendList) {
  184. if (categoryModel.getId() == friendModel.getCategoryId()) {
  185. String userSql = "select * from user where id=" + friendModel.getFriendId();
  186. categoryModel.getList().add(BaseDAO.getInstance().findUserModel(userSql));
  187. }
  188. }
  189. }
  190.  
  191. String friends = JSONArray.fromObject(categoryList).toString();
  192. System.out.println("frends:" + friends);
  193. ph.setMessageCommand(MessageType.FRIEND_LIST_ACK);
  194. ph.setContentType(MessageType.CONTENT_TYPE_ARRAY);
  195. ph.setMessageType(MessageType.MESSAGE_TYPE_REQUEST);
  196. ph.setPackageBodyLength(friends.getBytes().length);
  197. ph.setPackageBodyContent(friends);
  198. session.write(ph);
  199. break;
  200. case MessageType.SEND_MESSAGE: //消息发送
  201. SendModel sendModel = (SendModel)JSONObject.toBean(JSONObject.fromObject(ph.getPackageBodyContent()), SendModel.class);
  202. ph.setMessageType(MessageType.SEND_MESSAGE_ACK);
  203. session.write(ph);
  204. ph.setMessageCommand(MessageType.SEND_MESSAGE_ACK_NOTICE);
  205. String sendStr = JSONObject.fromObject(sendModel).toString();
  206. ph.setPackageBodyLength(sendStr.getBytes().length);
  207. ph.setPackageBodyContent(sendStr);
  208. ph.setMessageType(MessageType.MESSAGE_TYPE_PUSH);
  209. ph.setContentType(MessageType.CONTENT_TYPE_OBJECT);
  210. sessionMap.get(sendModel.getReceiverNum()).write(ph);
  211. break;
  212. //查找好友
  213. //注冊
  214. //加入好友
  215. }
  216. }
  217.  
  218. @Override
  219. public void messageSent(IoSession session, Object message) throws Exception {
  220. logger.info("发送消息: " + message);
  221. }
  222.  
  223. }

ChatServerCodecFactory.java

  1. package com.bufoon.codeFactory;
  2.  
  3. import java.nio.charset.Charset;
  4.  
  5. import org.apache.mina.core.session.IoSession;
  6. import org.apache.mina.filter.codec.ProtocolCodecFactory;
  7. import org.apache.mina.filter.codec.ProtocolDecoder;
  8. import org.apache.mina.filter.codec.ProtocolEncoder;
  9.  
  10. public class ChatServerCodecFactory implements ProtocolCodecFactory{
  11. private static final Charset charset = Charset.forName("UTF-8");
  12. @Override
  13. public ProtocolEncoder getEncoder(IoSession session) throws Exception {
  14. return new ChatServerEncode(charset);
  15. }
  16.  
  17. @Override
  18. public ProtocolDecoder getDecoder(IoSession session) throws Exception {
  19. return new ChatServerDecode(charset);
  20. }
  21.  
  22. }

ChatServerDecode.java

  1. package com.bufoon.codeFactory;
  2.  
  3. import java.nio.ByteOrder;
  4. import java.nio.charset.Charset;
  5.  
  6. import org.apache.mina.core.buffer.IoBuffer;
  7. import org.apache.mina.core.session.AttributeKey;
  8. import org.apache.mina.core.session.IoSession;
  9. import org.apache.mina.filter.codec.ProtocolDecoder;
  10. import org.apache.mina.filter.codec.ProtocolDecoderOutput;
  11.  
  12. import com.bufoon.model.PackageHead;
  13.  
  14. public class ChatServerDecode implements ProtocolDecoder {
  15.  
  16. private final AttributeKey CONTEXT = new AttributeKey(getClass(), "context");
  17. private final Charset charset;
  18. private int maxPackLength = 100;
  19.  
  20. public ChatServerDecode() {
  21. this(Charset.defaultCharset());
  22. }
  23.  
  24. public ChatServerDecode(Charset charset) {
  25. this.charset = charset;
  26. }
  27.  
  28. public int getMaxLineLength() {
  29. return maxPackLength;
  30. }
  31.  
  32. public void setMaxLineLength(int maxLineLength) {
  33. if (maxLineLength <= 0) {
  34. throw new IllegalArgumentException("maxLineLength: "
  35. + maxLineLength);
  36. }
  37. this.maxPackLength = maxLineLength;
  38. }
  39.  
  40. private ChatContext getContext(IoSession session) {
  41. ChatContext ctx;
  42. ctx = (ChatContext) session.getAttribute(CONTEXT);
  43. if (ctx == null) {
  44. ctx = new ChatContext(charset);
  45. session.setAttribute(CONTEXT, ctx);
  46. }
  47. return ctx;
  48. }
  49. @Override
  50. public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
  51. throws Exception {
  52. final int packHeadLength = 10;
  53. // 先获取上次的处理上下文,其中可能有未处理完的数据
  54. in.order(ByteOrder.LITTLE_ENDIAN);
  55. ChatContext ctx = getContext(session);
  56. // 先把当前buffer中的数据追加到Context的buffer其中
  57. ctx.append(in);
  58. // 把position指向0位置。把limit指向原来的position位置
  59. IoBuffer buf = ctx.getBuffer();
  60. buf.flip();
  61. // 然后按数据包的协议进行读取
  62. if (buf.remaining() >= packHeadLength) {
  63. buf.mark();
  64. // 读取消息头部分
  65. PackageHead message = new PackageHead();
  66. message.setPackageHeadLength(buf.getShort());
  67. message.setMessageType(buf.get());
  68. message.setContentType(buf.get());
  69. message.setMessageCommand(buf.getShort());
  70. int bodyLen = buf.getInt();
  71. message.setPackageBodyLength(bodyLen);
  72. // 读取正常的消息包。并写入输出流中,以便IoHandler进行处理
  73. if (bodyLen > 0 && buf.remaining() >= bodyLen) {
  74. message.setPackageBodyContent(buf.getString(bodyLen, charset.newDecoder()));
  75. } else {
  76. //buf.clear();
  77. }
  78. out.write(message);
  79. }
  80. if (buf.hasRemaining()) {
  81. // 将数据移到buffer的最前面
  82. IoBuffer temp = IoBuffer.allocate(maxPackLength)
  83. .setAutoExpand(true);
  84. temp.put(buf);
  85. temp.flip();
  86. buf.clear();
  87. buf.put(temp);
  88.  
  89. } else {// 假设数据已经处理完成,进行清空
  90. buf.clear();
  91. }
  92.  
  93. }
  94.  
  95. @Override
  96. public void finishDecode(IoSession session, ProtocolDecoderOutput out)
  97. throws Exception {
  98.  
  99. }
  100.  
  101. @Override
  102. public void dispose(IoSession session) throws Exception {
  103. ChatContext ctx = (ChatContext) session.getAttribute(CONTEXT);
  104. if (ctx != null) {
  105. session.removeAttribute(CONTEXT);
  106. }
  107.  
  108. }
  109.  
  110. }

ChatServerEncode.java

  1. package com.bufoon.codeFactory;
  2.  
  3. import java.nio.ByteOrder;
  4. import java.nio.charset.Charset;
  5.  
  6. import org.apache.mina.core.buffer.IoBuffer;
  7. import org.apache.mina.core.session.IoSession;
  8. import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
  9. import org.apache.mina.filter.codec.ProtocolEncoderOutput;
  10.  
  11. import com.bufoon.model.PackageHead;
  12.  
  13. public class ChatServerEncode extends ProtocolEncoderAdapter {
  14. private Charset charset = null;
  15.  
  16. public ChatServerEncode(Charset charset) {
  17. this.charset = charset;
  18. }
  19.  
  20. @Override
  21. public void encode(IoSession session, Object message,
  22. ProtocolEncoderOutput out) throws Exception {
  23. if (message instanceof PackageHead) {
  24. PackageHead ph = (PackageHead) message;
  25. IoBuffer buf = IoBuffer.allocate(ph.getPackageHeadLength() + ph.getPackageBodyLength());
  26. buf.order(ByteOrder.LITTLE_ENDIAN);
  27. //buf.setAutoExpand(true);
  28. buf.putShort((short) ph.getPackageHeadLength());
  29. buf.put((byte) ph.getMessageType());
  30. buf.put((byte) ph.getContentType());
  31. buf.putShort((short) ph.getMessageCommand());
  32. buf.putInt((int) ph.getPackageBodyLength());
  33. if (ph.getPackageBodyLength() > 0) {
  34. buf.putString(ph.getPackageBodyContent(), charset.newEncoder());
  35. }
  36. buf.flip();
  37. out.write(buf);
  38. out.flush();
  39. buf.free();
  40. }
  41. }
  42.  
  43. }

ChatContext.java

  1. package com.bufoon.codeFactory;
  2.  
  3. import java.nio.ByteOrder;
  4. import java.nio.charset.Charset;
  5. import java.nio.charset.CharsetDecoder;
  6.  
  7. import org.apache.mina.core.buffer.IoBuffer;
  8.  
  9. public class ChatContext {
  10.  
  11. private final CharsetDecoder decoder;
  12. private IoBuffer buf;
  13. private int matchCount = 0;
  14. private int overflowPosition = 0;
  15.  
  16. public ChatContext(Charset charset) {
  17. decoder = charset.newDecoder();
  18. buf = IoBuffer.allocate(80).setAutoExpand(true);
  19. buf.order(ByteOrder.LITTLE_ENDIAN);
  20. }
  21.  
  22. public CharsetDecoder getDecoder() {
  23. return decoder;
  24. }
  25.  
  26. public IoBuffer getBuffer() {
  27. return buf;
  28. }
  29.  
  30. public int getOverflowPosition() {
  31. return overflowPosition;
  32. }
  33.  
  34. public int getMatchCount() {
  35. return matchCount;
  36. }
  37.  
  38. public void setMatchCount(int matchCount) {
  39. this.matchCount = matchCount;
  40. }
  41.  
  42. public void reset() {
  43. overflowPosition = 0;
  44. matchCount = 0;
  45. decoder.reset();
  46. }
  47.  
  48. public void append(IoBuffer in) {
  49. getBuffer().put(in);
  50. }
  51.  
  52. }

MessageType.java

  1. package com.bufoon.util;
  2.  
  3. public class MessageType {
  4. /**登录验证请求消息类型**/
  5. public final static int LOGIN_VERIFY = 0x0000;
  6. /**登录验证响应消息类型**/
  7. public final static int LOGIN_VERIFY_ACK = 0x0001;
  8. /**心跳请求消息类型**/
  9. public final static int HEART_BEAT = 0x0002;
  10. /**心跳响应消息类型**/
  11. public final static int HEART_BEAT_ACK = 0x0003;
  12. /**好友列表请求消息类型**/
  13. public final static int FRIEND_LIST = 0x0004;
  14. /**好友列表响应消息类型**/
  15. public final static int FRIEND_LIST_ACK = 0x0005;
  16. /**发送消息请求**/
  17. public final static int SEND_MESSAGE = 0x0006;
  18. /**发送消息响应**/
  19. public final static int SEND_MESSAGE_ACK = 0x0007;
  20. /**发送消息通知响应**/
  21. public final static int SEND_MESSAGE_ACK_NOTICE = 0x1000;
  22. /**通知用户上下线**/
  23. public final static int USER_ON_OFF_LINE_NOTICE = 0X1001;
  24.  
  25. /**包头大小**/
  26. public final static int HEAD_LENGTH = 10;
  27. /**返回的消息类型 0服务端推送**/
  28. public final static int MESSAGE_TYPE_PUSH = 0;
  29. /**返回的消息类型 1请求响应**/
  30. public final static int MESSAGE_TYPE_REQUEST = 1;
  31. /**返回的内容类型 0 JsonObject**/
  32. public final static int CONTENT_TYPE_OBJECT = 0;
  33. /**返回的内容类型 1 JsonArray**/
  34. public final static int CONTENT_TYPE_ARRAY = 1;
  35. }

DBUtil.java

  1. package com.bufoon.util;
  2.  
  3. import java.sql.Connection;
  4. import java.sql.DriverManager;
  5. import java.sql.PreparedStatement;
  6. import java.sql.ResultSet;
  7. import java.sql.SQLException;
  8. import java.sql.Statement;
  9.  
  10. /**
  11. * 数据库 连接类
  12. * @author AllenYe
  13. *
  14. */
  15. public class DBUtil
  16. {
  17.  
  18. private static final DBUtil uniqueInstance = new DBUtil();
  19. private DBUtil(){
  20. //载入mysql-jdbc桥接器:
  21. try{
  22. Class.forName("com.mysql.jdbc.Driver");
  23. }catch(ClassNotFoundException e){}
  24. }
  25. public static DBUtil getInstance() {
  26. return uniqueInstance;
  27. }
  28. //公共的connection
  29. private Connection conn=null;
  30.  
  31. private Connection getConnection() throws Exception
  32. {
  33. if(conn == null)
  34. {
  35. //设置connection的url,账号,password
  36. conn=DriverManager.getConnection(
  37. "jdbc:mysql://localhost:3306/chat?
  38.  
  39. useUnicode=true&characterEncoding=UTF-8"
  40. ,"root"
  41. ,"root");
  42. }
  43. return conn;
  44. }
  45.  
  46. public ResultSet executeQuery(String sql)
  47. {
  48. try
  49. {
  50. Statement statement = getConnection().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
  51. ResultSet rs = statement.executeQuery(sql);
  52. return rs;
  53. } catch (SQLException e) {
  54. e.printStackTrace();
  55. } catch (Exception e) {
  56. e.printStackTrace();
  57. }
  58.  
  59. return null;
  60. }
  61.  
  62. public int executeUpdate(String sql)
  63. {
  64. try
  65. {
  66. PreparedStatement statement = getConnection().prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
  67. int result = statement.executeUpdate();
  68. return result;
  69. } catch (SQLException e) {
  70. e.printStackTrace();
  71. } catch (Exception e) {
  72. e.printStackTrace();
  73. }
  74. return -1;
  75. }
  76.  
  77. public boolean isExit(String table, String column, String value){
  78. String sql = "select * from " + table + " where " + column + " like '" + value + "'";
  79. ResultSet rs = this.executeQuery(sql);
  80. boolean flag = false;
  81. try {
  82. while (rs.next()) {
  83. flag = true;
  84. break;
  85. }
  86. } catch (SQLException e) {
  87. e.printStackTrace();
  88. }
  89. return flag;
  90. }
  91.  
  92. public boolean isExit(String table, String column[], Object value[]){
  93. StringBuffer sb = new StringBuffer("select * from " + table + " where 1=1");
  94. for(int i = 0; i < column.length; i++){
  95. sb.append(" and " + column[i] + " like '" + value[i] + "'");
  96. }
  97. ResultSet rs = this.executeQuery(sb.toString());
  98. boolean flag = false;
  99. try {
  100. while (rs.next()) {
  101. flag = true;
  102. break;
  103. }
  104. } catch (SQLException e) {
  105. e.printStackTrace();
  106. }
  107. return flag;
  108. }
  109.  
  110. }

BaseDAO.java

  1. package com.bufoon.util;
  2.  
  3. import java.sql.ResultSet;
  4. import java.sql.SQLException;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7.  
  8. import com.bufoon.model.CategoryModel;
  9. import com.bufoon.model.FriendsModel;
  10. import com.bufoon.model.UserModel;
  11.  
  12. public class BaseDAO {
  13. private static final BaseDAO uniqueInstance = new BaseDAO();
  14. private BaseDAO(){
  15.  
  16. }
  17. public static BaseDAO getInstance() {
  18. return uniqueInstance;
  19. }
  20.  
  21. public UserModel findUserModel(String sql){
  22. UserModel vo = null;
  23. try {
  24. ResultSet rs = DBUtil.getInstance().executeQuery(sql);
  25. while(rs.next()){
  26. vo = new UserModel();
  27. vo.setId(rs.getInt("id"));
  28. vo.setUsername(rs.getString("name"));
  29. vo.setUserNum(rs.getString("user_num"));
  30. vo.setPassword(rs.getString("password"));
  31. vo.setIsOnline(rs.getInt("is_online"));
  32. vo.setSignature(rs.getString("signature"));
  33. vo.setSex(rs.getString("sex"));
  34. }
  35. } catch (SQLException e) {
  36. e.printStackTrace();
  37. }
  38. return vo;
  39. }
  40.  
  41. public List<FriendsModel> findFriendsList(String sql){
  42. List<FriendsModel> list = new ArrayList<FriendsModel>();
  43. try {
  44. ResultSet rs = DBUtil.getInstance().executeQuery(sql);
  45. FriendsModel vo = null;
  46. while(rs.next()){
  47. vo = new FriendsModel();
  48. vo.setId(rs.getInt("id"));
  49. vo.setUserId(rs.getInt("user_id"));
  50. vo.setFriendId(rs.getInt("friend_id"));
  51. vo.setCategoryId(rs.getInt("category_id"));
  52. vo.setCreateTime(Util.formatTime(rs.getDate("create_time")));
  53. list.add(vo);
  54. }
  55. } catch (SQLException e) {
  56. e.printStackTrace();
  57. }
  58. return list;
  59. }
  60.  
  61. public List<CategoryModel> findCategoryList(String sql){
  62. List<CategoryModel> list = new ArrayList<CategoryModel>();
  63. CategoryModel vo = null;
  64. ResultSet rs = DBUtil.getInstance().executeQuery(sql);
  65. try {
  66. while(rs.next()){
  67. vo = new CategoryModel();
  68. vo.setId(rs.getInt("id"));
  69. vo.setUserId(rs.getInt("user_id"));
  70. vo.setName(rs.getString("name"));
  71. vo.setCreateTime(Util.formatTime(rs.getDate("create_time")));
  72. list.add(vo);
  73. }
  74. } catch (SQLException e) {
  75. e.printStackTrace();
  76. }
  77. return list;
  78. }
  79. }

PackageHead.java

  1. package com.bufoon.model;
  2.  
  3. import java.io.Serializable;
  4.  
  5. public class PackageHead implements Serializable {
  6.  
  7. private static final long serialVersionUID = 3965541808116510722L;
  8. private int id; //id
  9. private int packageHeadLength; //包头长度 short 2个字节 长度为10
  10. private int messageType; //消息类型 byte 1字节
  11. private int contentType; //内容类型 1字节
  12. private int messageCommand; //消息命令 short 2字节
  13. private int packageBodyLength; //包体长度 消息int 4字节
  14. private String packageBodyContent; //包体内容 大小 为packageBodyLength
  15.  
  16. public int getId() {
  17. return id;
  18. }
  19.  
  20. public void setId(int id) {
  21. this.id = id;
  22. }
  23.  
  24. public int getPackageHeadLength() {
  25. return packageHeadLength;
  26. }
  27.  
  28. public void setPackageHeadLength(int packageHeadLength) {
  29. this.packageHeadLength = packageHeadLength;
  30. }
  31.  
  32. public int getMessageType() {
  33. return messageType;
  34. }
  35.  
  36. public void setMessageType(int messageType) {
  37. this.messageType = messageType;
  38. }
  39.  
  40. public int getContentType() {
  41. return contentType;
  42. }
  43.  
  44. public void setContentType(int contentType) {
  45. this.contentType = contentType;
  46. }
  47.  
  48. public int getMessageCommand() {
  49. return messageCommand;
  50. }
  51.  
  52. public void setMessageCommand(int messageCommand) {
  53. this.messageCommand = messageCommand;
  54. }
  55.  
  56. public int getPackageBodyLength() {
  57. return packageBodyLength;
  58. }
  59.  
  60. public void setPackageBodyLength(int packageBodyLength) {
  61. this.packageBodyLength = packageBodyLength;
  62. }
  63.  
  64. public String getPackageBodyContent() {
  65. return packageBodyContent;
  66. }
  67.  
  68. public void setPackageBodyContent(String packageBodyContent) {
  69. this.packageBodyContent = packageBodyContent;
  70. }
  71.  
  72. @Override
  73. public String toString() {
  74. return "Messeage is: command=" + getMessageCommand() + ", type=" + getMessageType() + ", contentLength=" + getPackageBodyLength() + ", content=" + getPackageBodyContent();
  75. }
  76.  
  77. }

Mina airQQ聊天 服务端篇(二)的更多相关文章

  1. Mina airQQ聊天开门见山篇(一)

    Mina airQQ聊天开门见山篇(一) 近期项目可能要用到Mina,这个礼拜就在看这个框架,所以想写个小小的聊天的demo来巩固下,打算用几篇博客来记录下相关的知识 client用的是Flex Ai ...

  2. 基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)

    1.前言 本文要分享的消息推送指的是当iOS端APP被关闭或者处于后台时,还能收到消息/信息/指令的能力. 这种在APP处于后台或关闭情况下的消息推送能力,通常在以下场景下非常有用: 1)IM即时通讯 ...

  3. Netty入门之客户端与服务端通信(二)

    Netty入门之客户端与服务端通信(二) 一.简介 在上一篇博文中笔者写了关于Netty入门级的Hello World程序.书接上回,本博文是关于客户端与服务端的通信,感觉也没什么好说的了,直接上代码 ...

  4. 使用Apache MINA框架搭建服务端

    使用MINA框架搭建服务端步骤: 1.定义一个启动服务的类MinaServer,并实现接口ServletContextListener 2.定义一个处理业务逻辑的类MinaServerHandler, ...

  5. Swift3.0服务端开发(二) 静态文件添加、路由配置以及表单提交

    今天博客中就来聊一下Perfect框架的静态文件的添加与访问,路由的配置以及表单的提交.虽然官网上有聊静态文件的访问的部分,但是在使用Perfect框架来访问静态文件时还是有些点需要注意的,这些关键点 ...

  6. 从零开始开发IM(即时通讯)服务端(二)

    好消息:IM1.0.0版本已经上线啦,支持特性: 私聊发送文本/文件 已发送/已送达/已读回执 支持使用ldap登录 支持接入外部的登录认证系统 提供客户端jar包,方便客户端开发 github链接: ...

  7. 通过C#实现OPC-UA服务端(二)

    前言 通过我前面的一篇文件,我们已经能够搭建一个OPC-UA服务端了,并且也拥有了一些基础功能.这一次咱们就来了解一下OPC-UA的服务注册与发现,如果对服务注册与发现这个概念不理解的朋友,可以先百度 ...

  8. 轻易实现基于linux或win运行的聊天服务端程序

    对于不了解网络编程的开发人员来说,编写一个良好的服务端通讯程序是一件比较麻烦的事情.然而通过EC这个免费组件你可以非常简单地构建一个基于linux或win部署运行的网络服务程序.这种便利性完全得益于m ...

  9. C# 服务端篇之实现RestFul Service开发(简单实用)

    一.RestFul简介 REST(Representational State Transfer 通常被翻译为“表述性状态传输”或者“表述性状态转移”)是RoyFielding提出的一个描述互联系统架 ...

随机推荐

  1. 结构体struct和联合体union以及enum枚举体5的区别

    下面来自wikipedia: In computer science, a union is a value that may have any of several representations ...

  2. lines(最大区间和)

    lines Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  3. Zend Studio 10.6.0汉化教程(图文)

      来源于:http://www.pw88.com/teach/bangong/32.html 此汉化方法适用于所有的zend studio版本.整个汉化思路是:在线或者离线官方下载汉化包,本地安装即 ...

  4. 异常语句:try(尝试)-catch(抓取)-finally 跳转语句:break

    跳转语句: 1.break:跳出的意思,如果在循环语句中使用则是跳出循环2.default,--默认语句通常与 switch case 配合使用3.continue--跳过一个,继续下一个继续retu ...

  5. java笔记之数据类型

    java中一句连续的字符不能分开在两行中书写,如国太长可用“+”将这两个字符串连起来 文档注释是以“/**”开头,并在注释内容末尾以“*/”结束. 文档注释是对代码的解释说明,可以使用javadoc命 ...

  6. c++设置输出精度

    float类型的精度6-7位,double类型的变量15-16位,但是float占四个字节,double占八个字节, 但能用float类型不要用double因为double占的字节数多,而且运算速度要 ...

  7. Ubuntu网络频繁掉线解决方案

    年底了,实验室终于给配了个电脑(Ubuntu系统),博主欣喜若狂啊,然而装好后发现无线网频繁掉线,重启网络后能正常上网2~3分钟然后又掉线,再重启又能上网2~3分钟然后再掉线,博主那个不爽啊,于是各种 ...

  8. ASP.NET MVC 5 学习教程:添加模型

    原文 ASP.NET MVC 5 学习教程:添加模型 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连接字符串 通过控 ...

  9. java 访问 mysql 数据库的字符集设置

    mysql是在linux下,java代码通过jdbc访问总是中文乱码.做过如下尝试: 1)修改 mysql的 my.cnf文件,设置 default-character-set等参数 2) 利用alt ...

  10. hbase安装配置(整合到hadoop)

    hbase安装配置(整合到hadoop) 如果想详细了解hbase的安装:http://abloz.com/hbase/book.html 和官网http://hbase.apache.org/ 1. ...