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;
}
}
全心全意做开发
浙公网安备 33010602011771号