Mina2和Spring(2.5)在web项目中的结合使用
项目结构图如下:
?
说明: 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" ref="someServer"></property>
?</bean>
?<!-- 自定义的编码过滤器 -->
?<bean id="myCodecFilter" />
??</constructor-arg>
?</bean>
?<!-- 指定服务端地址和端口 -->
?<bean id="address" value="192.168.1.100"/>
??<constructor-arg index="1" value="10000"/>
?</bean>
?<!-- 日志filter -->
?<bean id="loggingFilter" />
?<!--
?<bean id="executorFilter" />
?<bean id="mdcInjectionFilter" />
?</bean> -->
?
?<bean id="codecFilter" /> -->
???<!-- 自定义的字符编码类 -->
???<bean 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"
??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的控制台视图, 观察服务端部分的打印(如下图):
?OK, that's all.