Mina airQQ聊天 服务端篇

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mina airQQ聊天 服务端篇相关的知识,希望对你有一定的参考价值。

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

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

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

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

包体:JSON字符串

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

ChatServerDecode和ChatServerEncode

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

/*
Navicat mysql Data Transfer

Source Server         : bufoon
Source Server Version : 50527
Source Host           : localhost:3306
Source Database       : chat

Target Server Type    : MYSQL
Target Server Version : 50527
File Encoding         : 65001

Date: 2014-06-29 23:30:28
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for category
-- ----------------------------
DROP TABLE IF EXISTS `category`;
CREATE TABLE `category` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `name` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_CATEGOFY_USER_ID` (`user_id`),
  CONSTRAINT `FK_CATEGOFY_USER_ID` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

-- ----------------------------
-- Records of category
-- ----------------------------
INSERT INTO `category` VALUES ('1', '1', '我的好友', '2014-06-29 19:00:25');
INSERT INTO `category` VALUES ('3', '2', '我的好友', '2014-06-29 19:00:55');
INSERT INTO `category` VALUES ('4', '3', '我的好友', '2014-06-29 19:01:00');
INSERT INTO `category` VALUES ('5', '1', '同学', '2014-06-29 20:39:04');

-- ----------------------------
-- Table structure for friends
-- ----------------------------
DROP TABLE IF EXISTS `friends`;
CREATE TABLE `friends` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `friend_id` int(11) DEFAULT NULL,
  `category_id` int(11) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_FRIENDS_USER_ID` (`user_id`),
  KEY `FK_FRIENDS_CATEGORY_ID` (`category_id`),
  KEY `FK_FRIENDS_FUSER_ID` (`friend_id`),
  CONSTRAINT `FK_FRIENDS_CATEGORY_ID` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`) ON DELETE CASCADE,
  CONSTRAINT `FK_FRIENDS_FUSER_ID` FOREIGN KEY (`friend_id`) REFERENCES `user` (`id`) ON DELETE CASCADE,
  CONSTRAINT `FK_FRIENDS_USER_ID` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

-- ----------------------------
-- Records of friends
-- ----------------------------
INSERT INTO `friends` VALUES ('1', '1', '2', '1', '2014-06-21 23:35:16');
INSERT INTO `friends` VALUES ('2', '1', '3', '1', '2014-06-21 23:35:22');
INSERT INTO `friends` VALUES ('3', '2', '1', '3', '2014-06-22 02:09:24');
INSERT INTO `friends` VALUES ('4', '3', '1', '4', '2014-06-22 02:09:29');

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
  `user_num` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL,
  `password` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
  `regist_time` datetime DEFAULT NULL,
  `sex` varchar(2) COLLATE utf8_unicode_ci DEFAULT NULL,
  `signature` varchar(300) COLLATE utf8_unicode_ci DEFAULT NULL,
  `head_pic_path` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL,
  `is_online` varchar(1) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', '张三', '12345', '12345', '2014-06-20 23:32:26', '男', null, null, '0');
INSERT INTO `user` VALUES ('2', '李四', '123456', '123456', '2014-06-20 23:32:31', '女', null, null, '1');
INSERT INTO `user` VALUES ('3', '王二', '1234567', '1234567', '2014-06-21 11:29:41', '男', null, null, '1');

项目文件夹结构:

技术分享

须要的jar包:

技术分享

ChatServer.java

package com.bufoon.main;

import java.io.IOException;
import java.net.InetSocketAddress;

import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.keepalive.KeepAliveFilter;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
import org.apache.mina.filter.keepalive.KeepAliveRequestTimeoutHandler;
import org.apache.mina.filter.logging.LogLevel;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

import com.bufoon.codeFactory.ChatServerCodecFactory;
import com.bufoon.handle.ChatServerHandle;
import com.bufoon.handle.KeepAliveMessageFactoryImpl;
import com.bufoon.handle.KeepAliveRequestTimeoutHandlerImpl;

public class ChatServer {
	private static final int PORT = 7073;  
	//30秒后超时 
    private static final int IDELTIMEOUT = 30;
    //15秒发送一次心跳包
    private static final int HEARTBEATRATE = 15;
    
    private static SocketAcceptor acceptor;
    public static SocketAcceptor getAcceptor(){
    	if(null==acceptor){
    		// 创建非堵塞的server端的Socket连接
    		acceptor = new NioSocketAcceptor();
    	}
    	return acceptor;
    }

    public static boolean serverStart() {
        DefaultIoFilterChainBuilder filterChain = getAcceptor().getFilterChain();
        // 加入编码过滤器 处理乱码、编码问题
        filterChain.addLast("codec", new ProtocolCodecFilter(new ChatServerCodecFactory()));
        LoggingFilter loggingFilter = new LoggingFilter();
        loggingFilter.setMessageReceivedLogLevel(LogLevel.INFO);
        loggingFilter.setMessageSentLogLevel(LogLevel.INFO);
        // 加入日志过滤器
        filterChain.addLast("loger", loggingFilter);
        // 设置核心消息业务处理器
        getAcceptor().setHandler(new ChatServerHandle());
        KeepAliveMessageFactory heartBeatFactory = new KeepAliveMessageFactoryImpl();
        KeepAliveRequestTimeoutHandler heartBeatHandler = new KeepAliveRequestTimeoutHandlerImpl();
        KeepAliveFilter heartBeat = new KeepAliveFilter(heartBeatFactory,IdleStatus.BOTH_IDLE, heartBeatHandler);
        // 是否回发 
        heartBeat.setForwardEvent(true);
        // 发送频率 
        heartBeat.setRequestInterval(HEARTBEATRATE);
       // getAcceptor().getFilterChain().addLast("heartbeat", heartBeat);
        getAcceptor().getSessionConfig().setBothIdleTime(30);
        // 设置session配置,30秒内无操作进入空暇状态
        getAcceptor().getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, IDELTIMEOUT);
        try {
            // 绑定端口7033
        	getAcceptor().bind(new InetSocketAddress(PORT));
        	return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
    public static void main(String[] args) {
    	ChatServer.serverStart();
		System.out.println("服务器启动...");
	}
}

ChatServerHandle.java

package com.bufoon.handle;

import java.sql.ResultSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.example.chat.ChatProtocolHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.bufoon.model.CategoryModel;
import com.bufoon.model.FriendsModel;
import com.bufoon.model.LoginModel;
import com.bufoon.model.PackageHead;
import com.bufoon.model.SendModel;
import com.bufoon.model.UserModel;
import com.bufoon.util.BaseDAO;
import com.bufoon.util.DBUtil;
import com.bufoon.util.MessageType;

public class ChatServerHandle extends IoHandlerAdapter {
	private final static Logger logger = LoggerFactory.getLogger(ChatProtocolHandler.class);
	
	public static Map<String, IoSession> sessionMap = new HashMap<String, IoSession>();
	@Override
	public void sessionCreated(IoSession session) throws Exception {
		logger.info("创建连接");
	}

	@Override
	public void sessionOpened(IoSession session) throws Exception {
		logger.info("打开连接");
	}

	@Override
	public void sessionClosed(IoSession session) throws Exception {
		logger.info("关闭连接");
		String userNum = (String) session.getAttribute("userNum");
		String sql = "update user set is_online=1 where user_num like'" + userNum + "'";
		DBUtil.getInstance().executeUpdate(sql);
		sessionMap.remove(userNum);
		//改动下线。通知
		String userSql = "select * from user where user_num like '" + userNum + "'";
		UserModel userModel = BaseDAO.getInstance().findUserModel(userSql);
		String friendListSql = "select * from friends where user_id=" + userModel.getId();
		List<FriendsModel> list = BaseDAO.getInstance().findFriendsList(friendListSql);
		for (FriendsModel friendsModel : list) {
			String fUserSql = "select * from user where id=" + friendsModel.getFriendId();
			UserModel userModel2 = BaseDAO.getInstance().findUserModel(fUserSql);
			IoSession is = sessionMap.get(userModel2.getUserNum());
			if (is != null) {
				PackageHead ph = new PackageHead();
				Map<String, Object> object = new HashMap<String, Object>();
		        object.put("userNum", userModel2.getUserNum());
		        object.put("status", 1); //下线
		        String content = JSONObject.fromObject(object).toString();
		        ph.setPackageHeadLength(10);
		        ph.setMessageCommand(MessageType.USER_ON_OFF_LINE_NOTICE);
		        ph.setContentType(MessageType.CONTENT_TYPE_OBJECT);
		        ph.setMessageType(MessageType.MESSAGE_TYPE_PUSH);
		        ph.setPackageBodyLength(content.getBytes().length);
		        ph.setPackageBodyContent(content);
				is.write(ph);
			}
		}
	}

	@Override
	public void sessionIdle(IoSession session, IdleStatus status)
			throws Exception {
		logger.info("进入空暇");
	}

	@Override
	public void exceptionCaught(IoSession session, Throwable cause)
			throws Exception {
		logger.warn("异常.", cause);
	    session.close(true);
	}

	@Override
	public void messageReceived(IoSession session, Object message)
			throws Exception {
		System.out.println(message);
		PackageHead ph = (PackageHead) message;
		System.out.println("还有没有这个session:" + sessionMap.size());
		switch (ph.getMessageCommand()) {
			case MessageType.LOGIN_VERIFY: //登录请求
				LoginModel loginModel = (LoginModel)JSONObject.toBean(JSONObject.fromObject(ph.getPackageBodyContent()), LoginModel.class);
				String username = loginModel.getUsername();
				IoSession is = sessionMap.get(username);
				Map<String, Object> map = new HashMap<String, Object>();
				if (!DBUtil.getInstance().isExit("user", "user_num", username)) {
					System.out.println("用户不存在");
					map.put("status", 1);
					map.put("info", "用户不存在");
					map.put("username", username);
				} else if (is != null && is.isConnected()) {
					System.out.println("用户已登录");
					map.put("status", 2);
					map.put("info", "用户已登录");
					map.put("username", username);
				} else if (!DBUtil.getInstance().isExit("user", new String[]{"user_num", "password"}, new Object[]{username, loginModel.getPassword()})) {
					System.out.println("用户密码错误");
					map.put("status", 3);
					map.put("info", "用户密码错误");
					map.put("username", username);
				} else if (DBUtil.getInstance().isExit("user", new String[]{"user_num", "password"}, new Object[]{username, loginModel.getPassword()})) {
					String sql = "select * from user where user_num like '" + username + "'";
					ResultSet rs = DBUtil.getInstance().executeQuery(sql);
					UserModel vo = null;
					while (rs.next()) {
						vo = new UserModel();
						vo.setId(rs.getInt("id"));
						vo.setUsername(rs.getString("name"));
						vo.setUserNum(rs.getString("user_num"));
						vo.setPassword(rs.getString("password"));
						vo.setSex(rs.getString("sex"));
						vo.setSignature(rs.getString("signature"));
						vo.setIsOnline(rs.getInt("is_online"));
						break;
					} 
					if (vo != null) {
						map.put("username", vo.getUsername());
					}
					map.put("status", 0);
					map.put("info", "成功");
					map.put("userNum", username);
					map.put("userVO", vo);
					session.setAttribute("userNum", username);
					sessionMap.put(username, session);
				}
				String onLinesql = "update user set is_online=0 where user_num like'" + username + "'";
				DBUtil.getInstance().executeUpdate(onLinesql);
				String content = JSONObject.fromObject(map).toString();
	            ph.setMessageCommand(MessageType.LOGIN_VERIFY_ACK);
	            ph.setContentType(MessageType.CONTENT_TYPE_OBJECT);
	            ph.setMessageType(MessageType.MESSAGE_TYPE_REQUEST);
	            ph.setPackageBodyLength(content.getBytes().length);
	            ph.setPackageBodyContent(content);
	            session.write(ph);
	            String friendSql = "select * from user where user_num like '" + username + "'";
	            ResultSet rs1 = DBUtil.getInstance().executeQuery(friendSql);
	            Map<String, Object> object = new HashMap<String, Object>();
	            object.put("userNum", username);
	            object.put("status", 0);
	            content = JSONObject.fromObject(object).toString();
	            ph.setMessageCommand(MessageType.USER_ON_OFF_LINE_NOTICE);
	            ph.setContentType(MessageType.CONTENT_TYPE_OBJECT);
	            ph.setMessageType(MessageType.MESSAGE_TYPE_PUSH);
	            ph.setPackageBodyLength(content.getBytes().length);
	            ph.setPackageBodyContent(content);
	            while (rs1.next()) {
	            	String sql1 = "select * from friends where user_id=" + rs1.getInt("id");
	            	 ResultSet rs2 = DBUtil.getInstance().executeQuery(sql1);
	            	 while(rs2.next()){
	            		 String sql2 = "select * from user where id=" + rs2.getInt("friend_id");
	            		 ResultSet rs3 = DBUtil.getInstance().executeQuery(sql2);
	            		 while(rs3.next()){
	            			IoSession iso = sessionMap.get(rs3.getString("user_num"));
	            			if(iso != null){
	            				iso.write(ph);
	            			}
	            		 }
	            	 }
	            }
				break;
			case MessageType.FRIEND_LIST: //好友列表请求
				JSONObject  obj = JSONObject.fromObject(ph.getPackageBodyContent());
				String userId = obj.getString("userId");
				String friendListSql = "select * from friends where user_id=" + userId;
				List<FriendsModel> friendList = BaseDAO.getInstance().findFriendsList(friendListSql);
				String categorySql = "select * from category where user_id=" + userId;
				List<CategoryModel> categoryList = BaseDAO.getInstance().findCategoryList(categorySql);
				for (CategoryModel categoryModel : categoryList) {
					for (FriendsModel friendModel : friendList) {
						if (categoryModel.getId() == friendModel.getCategoryId()) {
							String userSql = "select * from user where id=" + friendModel.getFriendId();
							categoryModel.getList().add(BaseDAO.getInstance().findUserModel(userSql));
						}
					}
				}
				
				String friends = JSONArray.fromObject(categoryList).toString();
				System.out.println("frends:" + friends);
	            ph.setMessageCommand(MessageType.FRIEND_LIST_ACK);
	            ph.setContentType(MessageType.CONTENT_TYPE_ARRAY);
	            ph.setMessageType(MessageType.MESSAGE_TYPE_REQUEST);
	            ph.setPackageBodyLength(friends.getBytes().length);
	            ph.setPackageBodyContent(friends);
	            session.write(ph);
				break;
			case MessageType.SEND_MESSAGE: //消息发送
				SendModel sendModel = (SendModel)JSONObject.toBean(JSONObject.fromObject(ph.getPackageBodyContent()), SendModel.class);
				ph.setMessageType(MessageType.SEND_MESSAGE_ACK);
				session.write(ph);
				ph.setMessageCommand(MessageType.SEND_MESSAGE_ACK_NOTICE);
				String sendStr = JSONObject.fromObject(sendModel).toString();
				ph.setPackageBodyLength(sendStr.getBytes().length);
				ph.setPackageBodyContent(sendStr);
				ph.setMessageType(MessageType.MESSAGE_TYPE_PUSH);
				ph.setContentType(MessageType.CONTENT_TYPE_OBJECT);
				sessionMap.get(sendModel.getReceiverNum()).write(ph);
				break;
			//查找好友
			//注冊
			//加入好友
		}
	}

	@Override
	public void messageSent(IoSession session, Object message) throws Exception {
		logger.info("发送消息: " + message);
	}
	
}

ChatServerCodecFactory.java

package com.bufoon.codeFactory;

import java.nio.charset.Charset;

import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolEncoder;

public class ChatServerCodecFactory implements ProtocolCodecFactory{
	private static final Charset charset = Charset.forName("UTF-8");
	@Override
	public ProtocolEncoder getEncoder(IoSession session) throws Exception {
		return new ChatServerEncode(charset);
	}

	@Override
	public ProtocolDecoder getDecoder(IoSession session) throws Exception {
		return new ChatServerDecode(charset);
	}

}
ChatServerDecode.java
package com.bufoon.codeFactory;

import java.nio.ByteOrder;
import java.nio.charset.Charset;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;

import com.bufoon.model.PackageHead;

public class ChatServerDecode implements ProtocolDecoder {

	private final AttributeKey CONTEXT = new AttributeKey(getClass(), "context");
	private final Charset charset;
	private int maxPackLength = 100;

	public ChatServerDecode() {
		this(Charset.defaultCharset());
	}

	public ChatServerDecode(Charset charset) {
		this.charset = charset;
	}

	public int getMaxLineLength() {
		return maxPackLength;
	}

	public void setMaxLineLength(int maxLineLength) {
		if (maxLineLength <= 0) {
			throw new IllegalArgumentException("maxLineLength: "
					+ maxLineLength);
		}
		this.maxPackLength = maxLineLength;
	}

	private ChatContext getContext(IoSession session) {
		ChatContext ctx;
		ctx = (ChatContext) session.getAttribute(CONTEXT);
		if (ctx == null) {
			ctx = new ChatContext(charset);
			session.setAttribute(CONTEXT, ctx);
		}
		return ctx;
	}
	@Override
	public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out)
			throws Exception {
		final int packHeadLength = 10;
		// 先获取上次的处理上下文,其中可能有未处理完的数据
		in.order(ByteOrder.LITTLE_ENDIAN);
		ChatContext ctx = getContext(session);
		// 先把当前buffer中的数据追加到Context的buffer其中
		ctx.append(in);
		// 把position指向0位置。把limit指向原来的position位置
		IoBuffer buf = ctx.getBuffer();
		buf.flip();
		// 然后按数据包的协议进行读取
		if (buf.remaining() >= packHeadLength) {
			buf.mark();
			// 读取消息头部分
			PackageHead message = new PackageHead();
			message.setPackageHeadLength(buf.getShort());
			message.setMessageType(buf.get());
			message.setContentType(buf.get());
			message.setMessageCommand(buf.getShort());
			int bodyLen = buf.getInt();
			message.setPackageBodyLength(bodyLen);
			// 读取正常的消息包。并写入输出流中,以便IoHandler进行处理
			if (bodyLen > 0 && buf.remaining() >= bodyLen) {
	              message.setPackageBodyContent(buf.getString(bodyLen, charset.newDecoder()));
			} else {
				//buf.clear();
			}
			out.write(message);
		}
		if (buf.hasRemaining()) {
			// 将数据移到buffer的最前面
			IoBuffer temp = IoBuffer.allocate(maxPackLength)
					.setAutoExpand(true);
			temp.put(buf);
			temp.flip();
			buf.clear();
			buf.put(temp);

		} else {// 假设数据已经处理完成,进行清空
			buf.clear();
		}
		
	}

	@Override
	public void finishDecode(IoSession session, ProtocolDecoderOutput out)
			throws Exception {
		
	}

	@Override
	public void dispose(IoSession session) throws Exception {
		ChatContext ctx = (ChatContext) session.getAttribute(CONTEXT);
		if (ctx != null) {
			session.removeAttribute(CONTEXT);
		}
		
	}

}

ChatServerEncode.java

package com.bufoon.codeFactory;

import java.nio.ByteOrder;
import java.nio.charset.Charset;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;

import com.bufoon.model.PackageHead;

public class ChatServerEncode extends ProtocolEncoderAdapter {
	private Charset charset = null;

	public ChatServerEncode(Charset charset) {
		this.charset = charset;
	}

	@Override
	public void encode(IoSession session, Object message,
			ProtocolEncoderOutput out) throws Exception {
		if (message instanceof PackageHead) {
			PackageHead ph = (PackageHead) message;
			IoBuffer buf = IoBuffer.allocate(ph.getPackageHeadLength() + ph.getPackageBodyLength());
			buf.order(ByteOrder.LITTLE_ENDIAN);
			//buf.setAutoExpand(true);
			buf.putShort((short) ph.getPackageHeadLength());
			buf.put((byte) ph.getMessageType());
			buf.put((byte) ph.getContentType());
			buf.putShort((short) ph.getMessageCommand());
			buf.putInt((int) ph.getPackageBodyLength());
			if (ph.getPackageBodyLength() > 0) {
				buf.putString(ph.getPackageBodyContent(), charset.newEncoder());
			}
			buf.flip();
			out.write(buf);
			out.flush();
			buf.free();
		}
	}

}
ChatContext.java

package com.bufoon.codeFactory;

import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

import org.apache.mina.core.buffer.IoBuffer;

public class ChatContext {

	private final CharsetDecoder decoder;
	private IoBuffer buf;
	private int matchCount = 0;
	private int overflowPosition = 0;
	
	public ChatContext(Charset charset) {
		decoder = charset.newDecoder();
		buf = IoBuffer.allocate(80).setAutoExpand(true);
		buf.order(ByteOrder.LITTLE_ENDIAN);
	}

	public CharsetDecoder getDecoder() {
		return decoder;
	}

	public IoBuffer getBuffer() {
		return buf;
	}

	public int getOverflowPosition() {
		return overflowPosition;
	}

	public int getMatchCount() {
		return matchCount;
	}

	public void setMatchCount(int matchCount) {
		this.matchCount = matchCount;
	}

	public void reset() {
		overflowPosition = 0;
		matchCount = 0;
		decoder.reset();
	}

	public void append(IoBuffer in) {
		getBuffer().put(in);
	}

}

MessageType.java

package com.bufoon.util;

public class MessageType {
	/**登录验证请求消息类型**/
	public final static int LOGIN_VERIFY = 0x0000;
	/**登录验证响应消息类型**/
	public final static int LOGIN_VERIFY_ACK = 0x0001;
	/**心跳请求消息类型**/
	public final static int HEART_BEAT = 0x0002;
	/**心跳响应消息类型**/
	public final static int HEART_BEAT_ACK = 0x0003;
	/**好友列表请求消息类型**/
	public final static int FRIEND_LIST = 0x0004;
	/**好友列表响应消息类型**/
	public final static int FRIEND_LIST_ACK = 0x0005;
	/**发送消息请求**/
	public final static int SEND_MESSAGE = 0x0006;
	/**发送消息响应**/
	public final static int SEND_MESSAGE_ACK = 0x0007;
	/**发送消息通知响应**/
	public final static int SEND_MESSAGE_ACK_NOTICE = 0x1000;
	/**通知用户上下线**/
	public final static int USER_ON_OFF_LINE_NOTICE = 0X1001;
	
	/**包头大小**/
	public final static int HEAD_LENGTH = 10;
	/**返回的消息类型 0服务端推送**/
	public final static int MESSAGE_TYPE_PUSH = 0;
	/**返回的消息类型 1请求响应**/
	public final static int MESSAGE_TYPE_REQUEST = 1;
	/**返回的内容类型 0 JsonObject**/
	public final static int CONTENT_TYPE_OBJECT = 0;
	/**返回的内容类型 1 JsonArray**/
	public final static int CONTENT_TYPE_ARRAY = 1;
}
DBUtil.java

package com.bufoon.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 数据库 连接类
 * @author AllenYe
 *
 */
public class DBUtil 
{
	
	private static final DBUtil uniqueInstance = new DBUtil();  
	private DBUtil(){
		//载入mysql-jdbc桥接器:
				try{
					Class.forName("com.mysql.jdbc.Driver");
				}catch(ClassNotFoundException e){}
	}
	public static DBUtil getInstance() {  
	        return uniqueInstance;  
	}
	//公共的connection
	private Connection conn=null;

	private Connection getConnection() throws Exception
	{
		if(conn == null)
		{
			//设置connection的url,账号,password
			conn=DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/chat?

useUnicode=true&characterEncoding=UTF-8" ,"root" ,"root"); } return conn; } public ResultSet executeQuery(String sql) { try { Statement statement = getConnection().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); ResultSet rs = statement.executeQuery(sql); return rs; } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null; } public int executeUpdate(String sql) { try { PreparedStatement statement = getConnection().prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); int result = statement.executeUpdate(); return result; } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return -1; } public boolean isExit(String table, String column, String value){ String sql = "select * from " + table + " where " + column + " like '" + value + "'"; ResultSet rs = this.executeQuery(sql); boolean flag = false; try { while (rs.next()) { flag = true; break; } } catch (SQLException e) { e.printStackTrace(); } return flag; } public boolean isExit(String table, String column[], Object value[]){ StringBuffer sb = new StringBuffer("select * from " + table + " where 1=1"); for(int i = 0; i < column.length; i++){ sb.append(" and " + column[i] + " like '" + value[i] + "'"); } ResultSet rs = this.executeQuery(sb.toString()); boolean flag = false; try { while (rs.next()) { flag = true; break; } } catch (SQLException e) { e.printStackTrace(); } return flag; } }


BaseDAO.java

package com.bufoon.util;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.bufoon.model.CategoryModel;
import com.bufoon.model.FriendsModel;
import com.bufoon.model.UserModel;

public class BaseDAO {
	private static final BaseDAO uniqueInstance = new BaseDAO();  
	private BaseDAO(){
		
	}
	public static BaseDAO getInstance() {  
	        return uniqueInstance;  
	}
	
	public UserModel findUserModel(String sql){
		UserModel vo = null;
		try {
			ResultSet rs = DBUtil.getInstance().executeQuery(sql);
			while(rs.next()){
				vo = new UserModel();
				vo.setId(rs.getInt("id"));
				vo.setUsername(rs.getString("name"));
				vo.setUserNum(rs.getString("user_num"));
				vo.setPassword(rs.getString("password"));
				vo.setIsOnline(rs.getInt("is_online"));
				vo.setSignature(rs.getString("signature"));
				vo.setSex(rs.getString("sex"));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return vo;
	}
	
	public List<FriendsModel> findFriendsList(String sql){
		List<FriendsModel> list = new ArrayList<FriendsModel>();
		try {
			ResultSet rs = DBUtil.getInstance().executeQuery(sql);
			FriendsModel vo = null;
			while(rs.next()){
				vo = new FriendsModel();
				vo.setId(rs.getInt("id"));
				vo.setUserId(rs.getInt("user_id"));
				vo.setFriendId(rs.getInt("friend_id"));
				vo.setCategoryId(rs.getInt("category_id"));
				vo.setCreateTime(Util.formatTime(rs.getDate("create_time")));
				list.add(vo);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return list;
	}
	
	public List<CategoryModel> findCategoryList(String sql){
		List<CategoryModel> list = new ArrayList<CategoryModel>();
		CategoryModel vo = null;
		ResultSet rs = DBUtil.getInstance().executeQuery(sql);
		try {
			while(rs.next()){
				vo = new CategoryModel();
				vo.setId(rs.getInt("id"));
				vo.setUserId(rs.getInt("user_id"));
				vo.setName(rs.getString("name"));
				vo.setCreateTime(Util.formatTime(rs.getDate("create_time")));
				list.add(vo);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return list;
	}
}

PackageHead.java

package com.bufoon.model;

import java.io.Serializable;

public class PackageHead implements Serializable {

	private static final long serialVersionUID = 3965541808116510722L;
	private int id; //id
	private int packageHeadLength; //包头长度  short 2个字节  长度为10
	private int messageType; //消息类型  byte 1字节
	private int contentType; //内容类型  1字节 
	private int messageCommand;  //消息命令 short 2字节
	private int packageBodyLength;  //包体长度 消息int 4字节
	private String packageBodyContent; //包体内容   大小 为packageBodyLength
	
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public int getPackageHeadLength() {
		return packageHeadLength;
	}

	public void setPackageHeadLength(int packageHeadLength) {
		this.packageHeadLength = packageHeadLength;
	}

	public int getMessageType() {
		return messageType;
	}

	public void setMessageType(int messageType) {
		this.messageType = messageType;
	}

	public int getContentType() {
		return contentType;
	}

	public void setContentType(int contentType) {
		this.contentType = contentType;
	}

	public int getMessageCommand() {
		return messageCommand;
	}

	public void setMessageCommand(int messageCommand) {
		this.messageCommand = messageCommand;
	}

	public int getPackageBodyLength() {
		return packageBodyLength;
	}

	public void setPackageBodyLength(int packageBodyLength) {
		this.packageBodyLength = packageBodyLength;
	}

	public String getPackageBodyContent() {
		return packageBodyContent;
	}

	public void setPackageBodyContent(String packageBodyContent) {
		this.packageBodyContent = packageBodyContent;
	}

	@Override
	public String toString() {
		return "Messeage is: command=" + getMessageCommand() + ", type=" + getMessageType() + ", contentLength=" + getPackageBodyLength() + ", content=" + getPackageBodyContent();
	}
	
}












以上是关于Mina airQQ聊天 服务端篇的主要内容,如果未能解决你的问题,请参考以下文章

3D寻路系统NavMesh-服务端篇

3D寻路系统NavMesh-服务端篇

3D寻路系统NavMesh-服务端篇

Mina TCP服务端客户端 示例

C# 服务端篇之实现RestFul Service开发

java socket 多线程通讯 使用mina作为服务端