Mina与Spring整合
首先需要导入的包
applicationContext-mina.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <!-- 配置地址 --> <bean class="com.sharp.slc.net.common.EncryptPropertyPlaceholderConfigurer"> <property name="order" value="1"/> <property name="ignoreUnresolvablePlaceholders" value="true"/> <property name="locations"> <list> <value>classpath:ssl.properties</value> </list> </property> </bean> <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <!-- spring升级后此配置已失效 会报错 --> <!-- <entry key="java.net.SocketAddress"> --> <!-- <bean class="org.apache.mina.integration.beans.InetSocketAddressEditor" /> --> <!-- </entry> --> <!-- 修改这里 --> <entry key="java.net.SocketAddress" value="org.apache.mina.integration.beans.InetSocketAddressEditor"> </entry> </map> </property> </bean> <!-- 配置业务处理类 --> <bean id="serviceHandler" class="com.sharp.slc.net.core.TCPServerHandler" /> <!-- 配置service --> <bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor" init-method="bind" destroy-method="unbind"> <property name="defaultLocalAddress" value=":2001" /> <property name="handler" ref="serviceHandler" /> <property name="filterChainBuilder" ref="filterChainBuilder" /> </bean> <!-- 配置解码器 --> <bean id="codecFilter" class="org.apache.mina.filter.codec.ProtocolCodecFilter"> <constructor-arg> <bean class="com.sharp.slc.net.core.codec.TextCodecFactory" /> <!-- <bean class="org.apache.mina.filter.codec.textline.TextLineCodecFactory" /> --> </constructor-arg> </bean> <!-- 配置日志拦截器 --> <bean id="loggingFilter" class="org.apache.mina.filter.logging.LoggingFilter" /> <!-- 配置SSL拦截器 --> <bean id="sslFilter" class="org.apache.mina.filter.ssl.SslFilter"> <constructor-arg ref="sslContext" /> <!-- <property name="needClientAuth" value="true" /> --> </bean> <!-- The SSL configuration --> <bean id="keystoreFactory" class="org.apache.mina.filter.ssl.KeyStoreFactory"> <property name="password"> <value>${key_password}</value> </property> <!-- <property name="dataUrl" value="file:/d:/certs/server.jks" /> --> <property name="dataUrl" value="file:/usr/local/tomcat8/certs/server.jks" /> </bean> <bean id="keyStore" factory-bean="keystoreFactory" factory-method="newInstance" /> <!-- SSLContext to be used --> <bean id="sslContextFactory" class="org.apache.mina.filter.ssl.SslContextFactory"> <property name="protocol" value="TLSV1.2" /> <property name="keyManagerFactoryAlgorithm" value="SunX509" /> <property name="keyManagerFactoryKeyStore"> <ref local="keyStore" /> </property> <property name="keyManagerFactoryKeyStorePassword"> <value>${keyManager_password}</value> </property> </bean> <bean id="sslContext" factory-bean="sslContextFactory" factory-method="newInstance" /> <!-- 将日志和解码器添加 --> <bean id="filterChainBuilder" class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder"> <property name="filters"> <map> <entry key="sslFilter" value-ref="sslFilter" /> <entry key="loggingFilter" value-ref="loggingFilter" /> <entry key="codecFilter" value-ref="codecFilter" /> </map> </property> </bean> </beans>
SessionCache.java
public class SessionCache { private final static Log log = LogFactory.getLog(SessionCache.class); private static SessionCache session = null; /** 设备连接信息[sessions] */ private Map<String, IoSession> sessions = new HashMap<String, IoSession>(); private static final String value = KVStoreConfig.getIpAddress(); /** * 获取唯一实例 */ public static SessionCache getInstance() { log.debug(" <<< Session单例获取 <<< "); if (session == null) { session = new SessionCache(); } return session; } /** * 获取设备连接信息[sessions] * * @return 设备连接信息[sessions] */ public Map<String, IoSession> getSessions() { return sessions; } /** * 设置设备连接信息[sessions] * * @param 设备连接信息 * [sessions] */ public void setSessions(Map<String, IoSession> sessions) { this.sessions = sessions; } /** * 增加设备连接信息[sessions] * * @param MAC地址作为键 * [mac] * @param IoSession对象作为值 * [session] */ public void save(String mac, IoSession session) { sessions.put(mac, session); String clientIp = session.getRemoteAddress().toString(); KVStoreUtils.putHashmapField(mac, value); String kvIp = KVStoreUtils.getHashmapField(NetConstants.KV_PORT_KEY, mac); if (StringUtil.isNotBlank(kvIp)) { if (!kvIp.contains(clientIp)) { String ipvalue = kvIp + ";" + clientIp; KVStoreUtils.putHashmapField(NetConstants.KV_PORT_KEY, mac, ipvalue); } } else { KVStoreUtils.putHashmapField(NetConstants.KV_PORT_KEY, mac, clientIp); } } /** * 查找设备连接信息[sessions] * * @param MAC地址作为键 * [key] * @return 连接信息 */ public IoSession isExists(String key) { if (sessions.containsKey(key)) { return sessions.get(key); } return null; } /** * 删除设备连接信息[sessions] * * @param MAC地址作为键 * [mac] */ public void remove(String mac, String clientIp) { sessions.remove(mac); String ipvalue = KVStoreUtils.getHashmapField(NetConstants.KV_PORT_KEY, mac); if (clientIp.equals(ipvalue)) { KVStoreUtils.removeHahmapField(mac); KVStoreUtils.removeHahmapField(NetConstants.KV_PORT_KEY, mac); } else { String ipvalueTemp = ipvalue.replaceAll(clientIp + ";", ""); KVStoreUtils.putHashmapField(NetConstants.KV_PORT_KEY, mac, ipvalueTemp); } } }
TCPServerHandler.java
/** * 服务端业务处理类 * * @author Pactera.He */ public class PurifierTCPServerHandler extends IoHandlerAdapter { private final static Log log = LogFactory.getLog(TCPServerHandler.class); private final static Map<String, String> firstHeartBeatMap = new HashMap<String, String>(); public TCPServerHandler() { } @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { log.error(session.getRemoteAddress().toString() + " : " + cause.toString()); } @Override public void messageReceived(IoSession session, Object message) throws Exception { // 消息内容 String text = message.toString(); // 获取客户端发过来的消息内容 log.info("接收消息内容 : " + text); if (StringUtil.isNotBlank(text)) { // 解析XML文件 readXML(text, session); } else { // 返回错误信息 session.write("error heartbeat"); } } @Override public void messageSent(IoSession session, Object message) throws Exception { log.debug("发送消息内容 : \n" + message.toString()); } @Override public void sessionCreated(IoSession session) throws Exception { log.debug("连接创建 : " + session.getRemoteAddress().toString()); } @Override public void sessionIdle(IoSession session, IdleStatus status) throws Exception { log.info(MessageFormat.format("连接Idle [{0}] from {1} ", status, session.getRemoteAddress())); if (status == IdleStatus.READER_IDLE) { session.close(true); } } @Override public void sessionOpened(IoSession session) throws Exception { if (checkIsBlocked(session)) { session.close(true); return; } log.info("连接打开:" + session.getRemoteAddress().toString()); } @Override public void sessionClosed(IoSession session) throws Exception { if (checkIsBlocked(session)) { return; } log.info("连接关闭 : " + session.getRemoteAddress().toString()); // 关闭通知 if (session.getAttribute("mac") != null) { String mac = session.getAttribute("mac").toString(); firstHeartBeatMap.remove(mac); this.notifyWeChat(mac, session.getRemoteAddress().toString()); } } /** * session关闭通知WeChat */ private void notifyWeChat(String mac, String clientIp) { log.info("连接关闭:" + mac + ",通知微信 . . ."); if (StringUtil.isNotBlank(mac)) { // 清除信息 SessionCache.getInstance().remove(mac, clientIp); } } /** * 解析XML文件 * * @param contents * 解析数据内容 * @param session * 处理对象 */ private void readXML(String contents, IoSession session) throws DocumentException { Document readDoc = DocumentHelper.parseText(contents); Element rootNode = readDoc.getRootElement(); String mac = ""; // 匹配节点:tcp_msg if (NetConstants.NODE_TCP_MSG.equals(rootNode.getName())) { // 匹配节点(msg)内容 if (NetConstants.MSG_VALUE_HEARTBEAT.equals(rootNode.elementTextTrim(NetConstants.NODE_MSG))) { // mac address Element node = rootNode.element(NetConstants.NODE_DATA); mac = node.elementTextTrim(NetConstants.NODE_MAC_ADDRESS); // 生成所需XML文件 createXML(mac, session, wifiVersion); } } } /** * 生成XML文件 * * @param mac * MAC地址 * @param session * 处理对象 */ private void createXML(String mac, IoSession session, String wifiVersion) { log.info("当前处理Mac地址 : " + mac); if (StringUtil.isNotBlank(mac)) { // 保存客户端的会话session SessionCache.getInstance().save(mac, session); // DocumentHelper提供了创建Document对象的方法 Document writeDoc = DocumentHelper.createDocument(); // 添加节点:tcp_msg Element root = writeDoc.addElement(NetConstants.NODE_TCP_MSG); // 添加节点:msg Element msg = root.addElement(NetConstants.NODE_MSG); // 设置节点信息 msg.setText(NetConstants.MSG_VALUE_HEARTBEATRES); // 添加节点:cmd Element cmd = root.addElement(NetConstants.NODE_CMD); // 不再检查每个心跳包 cmd.setText(NetConstants.VALUE_NULL); // 添加节点:data Element data = root.addElement(NetConstants.NODE_DATA); // 添加节点:server_time Element server_time = data.addElement(NetConstants.NODE_SERVER_TIME); // 设置节点信息 server_time.setText(String.valueOf(System.currentTimeMillis())); // 将document文档对象直接转换成字符串 log.debug("发送内容: " + writeDoc.asXML()); session.write(writeDoc.asXML()); } } /** * 检查对面地址是否在黑名单中 * * @param session * 连接session * @return 是:true,否:false */ private boolean checkIsBlocked(IoSession session) { boolean ret = false; String[] blockList = {}; for (String blocked : blockList) { if (session.getRemoteAddress().toString().indexOf(blocked) > 0) { ret = true; break; } } return ret; } }
全心全意做开发