spring + mina

spring.xml文件中

<!-- MINA                                                            -->
    <!-- =============================================================== -->

    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <entry key="java.net.SocketAddress">
                    <bean class="org.apache.mina.integration.beans.InetSocketAddressEditor" />
                </entry>
            </map>
        </property>
    </bean>

    <bean id="xmppHandler" class="org.androidpn.server.xmpp.net.XmppIoHandler" />

    <bean id="filterChainBuilder"
        class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder">
        <property name="filters">
            <map>
                <entry key="executor">
                    <bean class="org.apache.mina.filter.executor.ExecutorFilter" />
                </entry>
                <entry key="codec">
                    <bean class="org.apache.mina.filter.codec.ProtocolCodecFilter">
                        <constructor-arg>
                            <bean class="org.androidpn.server.xmpp.codec.XmppCodecFactory" />
                        </constructor-arg>
                    </bean>
                </entry>
                <!--
                <entry key="logging">
                    <bean class="org.apache.mina.filter.logging.LoggingFilter" />
                </entry>
                -->
            </map>
        </property>
    </bean>

    <bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor"
        init-method="bind" destroy-method="unbind">
        <property name="defaultLocalAddress" value=":5222" />
        <property name="handler" ref="xmppHandler" />
        <property name="filterChainBuilder" ref="filterChainBuilder" />
        <property name="reuseAddress" value="true" />
    </bean>

spring中会在加载 <bean id="ioAcceptor"  init-method="bind">启动org.apache.mina.transport.socket.nio.NioSocketAcceptor 的bind方法启动监听的程序,同时设置了属性,其作用如同

以下是最简单的MINA例子程序,

public class MinaTimeServer {
    private static final int PORT = 9123;// 定义监听端口

    public static void main(String[] args) throws IOException {
        IoAcceptor acceptor = new NioSocketAcceptor();
        acceptor.getFilterChain().addLast("logger", new LoggingFilter());
        acceptor.getFilterChain().addLast(
                "codec",
                new ProtocolCodecFilter(new TextLineCodecFactory(Charset
                        .forName("UTF-8"))));// 指定编码过滤器
        acceptor.setHandler(new TimeServerHandler());// 指定业务逻辑处理器
        acceptor.setDefaultLocalAddress(new InetSocketAddress(PORT));// 设置端口号
        acceptor.bind();// 启动监听
        System.out.println("Begin************");
    }
}

//业务逻辑处理,当监听到有数据传送过来的时候会调用

public class TimeServerHandler extends IoHandlerAdapter {
    @Override
    public void sessionCreated(IoSession session) {
        // 显示客户端的ip和端口
        System.out.println("sessionCreated"+session.getRemoteAddress().toString());
    }

    @Override
    public void messageReceived(IoSession session, Object message)
            throws Exception {
        String str = message.toString();
        System.out.println("Message written..."+str);

        if (str.trim().equalsIgnoreCase("quit")) {
            session.close();// 结束会话
            return;
        }
        Date date = new Date();
        session.write(date.toString());// 返回当前时间的字符串
    }
}


//指定业务逻辑处理器

 Spring+MINA中这个指定了<property name="handler" ref="xmppHandler" />默认的业务逻辑处理器,

package org.androidpn.server.xmpp.net.XmppIoHandler

package org.androidpn.server.xmpp.net..StanzaHandler

当监听到有数据的时候会执行XmppIoHandler的这个方法,message是客户端发送过来的数据,被封装成xmpp用的对象

中messageReceived(IoSession session, Object message){

.......


StanzaHandler handler = (StanzaHandler) session
                .getAttribute(STANZA_HANDLER);

handler.process((String) message, parser);

.......

//以下是涉及到的构造函数的实现

public StanzaHandler(String serverName, Connection connection) {
        this.serverName = serverName;
        this.connection = connection;
        this.router = new PacketRouter();
    }

public PacketRouter() {
        messageRouter = new MessageRouter();
        presenceRouter = new PresenceRouter();
        iqRouter = new IQRouter();
    }

public IQRouter() {//业务逻辑处理器的分发就是在这个里实现的
        sessionManager = SessionManager.getInstance();
        iqHandlers.add(new IQAuthHandler());
        iqHandlers.add(new IQRegisterHandler());
        iqHandlers.add(new IQRosterHandler());
    }

//StanzaHandler

    public void process(String stanza, XMPPPacketReader reader){

根据判断message包含的字符串

        Element doc = reader.read(new StringReader(stanza)).getRootElement();
String tag = doc.getName();

if ("iq".equals(tag)) {//客户端发送过来包含iq字段,androidpn-client端中代表的是注册用的
            log.debug("iq...");
            processIQ(doc);


private void processIQ(Element doc) {

packet = getIQ(doc);


。。。

packet.setFrom(session.getAddress());
router.route(packet);//业务逻辑处理器分发控制

session.incrementClientPacketCount();

}

//PacketRouter

 public void route(IQ packet) {
        iqRouter.route(packet);//注册业务逻辑的处理器的分发控制
 }

//IQRouter

private Map<String, IQHandler> namespace2Handlers = new ConcurrentHashMap<String, IQHandler>();

public void route(IQ packet) {

判断message包含的字段     是否有iq //代表注册

"jabber:iq:register".equals(packet.getChildElement()
                                .getNamespaceURI())

handle(packet);

}


private void handle(IQ packet) {
        try {
            Element childElement = packet.getChildElement();
            String namespace = null;
            if (childElement != null) {
                namespace = childElement.getNamespaceURI();
            }
            if (namespace == null) {
                if (packet.getType() != IQ.Type.result
                        && packet.getType() != IQ.Type.error) {
                    log.warn("Unknown packet " + packet);
                }
            } else {
            //根据获得的message的命名空间获取对应的IQRegisterHandler 业务逻辑处理器          

                IQHandler handler = getHandler(namespace);

                if (handler == null) {
                    sendErrorPacket(packet,
                            PacketError.Condition.service_unavailable);
                } else {
                     handler.process(packet);
                }



 private IQHandler getHandler(String namespace) {
        IQHandler handler = namespace2Handlers.get(namespace);
        if (handler == null) {
            for (IQHandler handlerCandidate : iqHandlers) {
                if (namespace.equalsIgnoreCase(handlerCandidate.getNamespace())) {
                    handler = handlerCandidate;
                    namespace2Handlers.put(namespace, handler);
                    break;
                }
            }
        }
        return handler;
    }


//handler.process(packet);

 public void process(Packet packet) {
        IQ iq = (IQ) packet;
        try {
            IQ reply = handleIQ(iq); //这个方法是抽象的,在IQRegisterHandler 继承于IQHandler,同时也是继承了process方法
.......

}

到这里服务器端的当客户端连接上服务器的时候注册部分已经解释结束,剩下的同理可以实现了》》》

(好记性不如烂笔头-------)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值