项目结构图如下:
说明: com.test.server包下是mina的服务端程序, MinaServer_Unuse.java 类就是一般的mina服务端主类, 但这里不用它来启动, 而是通过applicationContext-minaServer.xml 来启动.
但这个spring配置文件不会自己启动,所以用到 com.test.action包下的 InitListener.java来调用这个spring配置文件, 达到启动的目的.
com.test.client包是个普通的mina客户端类, 这里主要用来检查与spring结合后的mina服务端运行是否正常.
项目会发布到tomcat进行测试.
注: 本文基本不会讲解mina如何使用, 这种文章很多. 所有代码复制过去即可观察效果
InitListener.java:
package com.test.action;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class InitListener implements ServletContextListener {
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
}
public void contextInitialized(ServletContextEvent sce) {
new ClassPathXmlApplicationContext("applicationContext-minaServer.xml");
//在tomcat的启动过程中,会看到控制台打印此语句.
System.out.println("********mina server 启动完毕*********");
}
}
SomeServer:
package com.test.action;
/** 这个类主要是通过spring注入给MinaServerHandler用的,表示: mina在接收到信息后,该由主要业务类来处理了. 仅作演示用 */
public class SomeServer {
public void doSome(){
System.out.println("someServer todo something!");
}
}
MinaClient:
package com.test.client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
/**
* 客户端
* @author yan
*/
public class MinaClient {
public void start() throws IOException{
NioSocketConnector connector = new NioSocketConnector();
// connector.getFilterChain().addLast( "logger", new LoggingFilter() );
//设置编码过滤器
connector.getFilterChain().addLast( "codec", new ProtocolCodecFilter( new TextLineCodecFactory( Charset.forName( "UTF-8" ))));
connector.setConnectTimeoutMillis(10000);
connector.setHandler(new MinaClientHandler());
ConnectFuture cf = connector.connect(new InetSocketAddress("192.168.1.83",10000));
//等待连接创建完成
cf.awaitUninterruptibly();
IoSession session = cf.getSession();
System.out.println("客户端准备完毕");
//以下是等待控制台的输入
while(true){
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line = in.readLine();
try {
if(!"".equals(line)){
session.write(line);
} else if("quit".equals(line)){
break;
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("服务端关闭了连接");
}
}
session.getCloseFuture().awaitUninterruptibly();
connector.dispose();
}
public static void main(String[] args) {
try {
new MinaClient().start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
MinaClientHandler:
package com.test.client;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
/**
* 客户端事件处理类
* @author yan
*/
public class MinaClientHandler extends IoHandlerAdapter {
@Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
System.out.println("服务端关闭了连接");
}
@Override
public void messageReceived(IoSession session, Object message)throws Exception {
System.out.println("客户端接收到的消息: "+message);
}
@Override
public void sessionCreated(IoSession session) throws Exception {
System.out.println("客户端连接上服务器");
}
}
MinaServerHandler:
package com.test.server;
import java.net.InetSocketAddress;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import com.test.action.SomeServer;
/**
* mina服务端的的事件处理类
* @author yan
*/
public class MinaServerHandler extends IoHandlerAdapter {
private SomeServer someServer;
public void setSomeServer(SomeServer someServer) {
this.someServer = someServer;
}
@Override
public void exceptionCaught(IoSession session, Throwable cause){
try {
System.out.println("客户端 "+session.getRemoteAddress()+" 关闭了连接");
} catch (Exception e) {
// TODO: handle exception
}
}
/**
* 服务端接收消息
*/
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
someServer.doSome();
String msg = message.toString();
if("quit".equals(msg)){
session.close(false);
return;
}
//对客户端做出的响应
for (Iterator<String> it = sessions.keySet().iterator(); it.hasNext();) {
IoSession ss = sessions.get(it.next());
ss.write( "message from server:: "+session.getRemoteAddress()+" 说: " + msg );//返回客户端发送过来的消息
}
}
/**
* 客户端连接的会话创建
*/
@Override
public void sessionCreated(IoSession session) throws Exception {
InetSocketAddress isa = (InetSocketAddress)session.getRemoteAddress();
System.out.println("客户端:"+isa.getAddress().getHostAddress()+":"+isa.getPort()+" 连接进来了");
sessions.put(session.getRemoteAddress().toString(), session);
}
private ConcurrentMap<String, IoSession> sessions=new ConcurrentHashMap<String, IoSession>();
}
MiniServer_Unuse:
package com.test.server;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* mina服务端. 这个类不会用,除非你要手动来启动.
* @author yan
*
*/
public class MiniServer_Unuse {
private static final int port = 10000;
public void start() throws IOException {
// 用于创建服务端的监听
IoAcceptor acceptor = new NioSocketAcceptor();
// acceptor.getFilterChain().addLast("logger", new LoggingFilter() );
// 编码过滤器
// acceptor.getFilterChain().addLast("encode", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
acceptor.getFilterChain().addLast("encode",new ProtocolCodecFilter(new MyCodecFactory()));
// 设置事件处理类\
acceptor.setHandler(new MinaServerHandler());
// 设置地址和端口
acceptor.setDefaultLocalAddress(new InetSocketAddress("192.168.1.100",port));
acceptor.bind();
System.out.println("服务端准备完毕");
}
public static void main(String[] args) {
new ClassPathXmlApplicationContext("applicationContext.xml");
try {
new MiniServer_Unuse().start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
MyCodecFactory:
package com.test.server;
import java.nio.charset.Charset;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
package com.test.server;
import java.nio.charset.Charset;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
/**
* <style type="text/css">body{background:#C7EDCC;}</style>
* 这个类集成自TextLineCodecFactory, 表示对mina的数据的解析方式.
* 本来可以直接用TextLineCodecFactory的, 但这个类的目的是表示我们可以有自己的方式来解析.
* MyCodecFactory.java
* @author yan
*/
public class MyCodecFactory extends TextLineCodecFactory {
public MyCodecFactory(){
super(Charset.forName("UTF-8"));
}
}
public class MyCodecFactory extends TextLineCodecFactory {
public MyCodecFactory(){
super(Charset.forName("UTF-8"));
}
}
applicationContext-minaServer.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 id="someServer" class="com.test.action.SomeServer"></bean>
<!-- 自定义的serverHandler -->
<bean id="serverHandler" class="com.test.server.MinaServerHandler">
<property name="someServer" ref="someServer"></property>
</bean>
<!-- 自定义的编码过滤器 -->
<bean id="myCodecFilter" class="org.apache.mina.filter.codec.ProtocolCodecFilter">
<constructor-arg>
<bean class="com.test.server.MyCodecFactory" />
</constructor-arg>
</bean>
<!-- 指定服务端地址和端口 -->
<bean id="address" class="java.net.InetSocketAddress">
<constructor-arg index="0" value="192.168.1.100"/>
<constructor-arg index="1" value="10000"/>
</bean>
<!-- 日志filter -->
<bean id="loggingFilter" class="org.apache.mina.filter.logging.LoggingFilter" />
<!--
<bean id="executorFilter" class="org.apache.mina.filter.executor.ExecutorFilter" />
<bean id="mdcInjectionFilter" class="org.apache.mina.filter.logging.MdcInjectionFilter">
<constructor-arg value="remoteAddress" />
</bean> -->
<bean id="codecFilter" class="org.apache.mina.filter.codec.ProtocolCodecFilter">
<constructor-arg>
<!-- <bean class="org.apache.mina.filter.codec.textline.TextLineCodecFactory" /> -->
<!-- 自定义的字符编码类 -->
<bean class="com.test.server.MyCodecFactory"></bean>
</constructor-arg>
</bean>
<!-- 过滤器链 -->
<bean id="filterChainBuilder" class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder">
<property name="filters">
<map>
<!--
<entry key="executor" value-ref="executorFilter" />
<entry key="mdcInjectionFilter" value-ref="mdcInjectionFilter" />
-->
<entry key="codecFilter" value-ref="codecFilter" />
<!-- <entry key="loggingFilter" value-ref="loggingFilter" /> -->
</map>
</property>
</bean>
<!-- 开始运行socket服务 -->
<bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor"
init-method="bind" destroy-method="unbind">
<property name="defaultLocalAddress" ref="address" />
<property name="handler" ref="serverHandler" />
<property name="filterChainBuilder" ref="filterChainBuilder" />
<property name="reuseAddress" value="true" />
</bean>
</beans>
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee "
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance "
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd ">
<listener>
<listener-class>com.test.action.InitListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
部署, 启动(如下图):
F11运行MinaClient.java, 并在控制台输入一些话, 会看到服务端的返回信息(如下图).
在切换回tomcat的控制台视图, 观察服务端部分的打印(如下图):