接收http请求然后调用mina给客户端发送信息 spring,spring mvc ,
angle_小帅 发表于2年前
接收http请求然后调用mina给客户端发送信息 spring,spring mvc ,
  • 发表于 2年前
  • 阅读 3087
  • 收藏 20
  • 点赞 1
  • 评论 0

聚焦虚拟化和OpenStack、容器、大数据等开源技术的年度大趴!>>> »  

摘要: 过程是这样的你的网站有改动了 想要通知同时登陆的手机端,这个推送是实时的, 还有一种程序关闭 然后收到的推送 这个是第三方的推送 ios的话是服务器发送到苹果服务器 由ios_token确定推送给哪个手机,android则可以用极光推送等。。。 这里只说程序在线时实时通知的实现java哦

这里比较复杂的莫过于spring的配置了那就先上配置applicationContext.xml

mina的配置在最下面

<spring  -- mina >这个 之上的 配置有velocity和memcache还有springjdbc,自动装配,json对象支持(注解@ResponseBody), 切面事务管理 ,  当然这些大家能用的上的 拿走  用不上删掉(跟没说一样)


<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <context:property-placeholder location="classpath:jdbc.properties" />
    
     <bean id="stringConverter" class="org.springframework.http.converter.StringHttpMessageConverter">  
        <property name="supportedMediaTypes">  
            <list>  
                <value>text/plain;charset=UTF-8</value>  
            </list>  
        </property>  
    </bean>  
  
        <bean id="exceptionResolver" class="com.util.ExceptionHandler"/>  
    <!-- 输出对象转JSON支持 -->  
    <bean id="jsonConverter"  
        class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>  
    <bean  
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
        <property name="messageConverters">  
            <list>  
                 <ref bean="stringConverter"/> 
                <ref bean="jsonConverter" />  
            </list>  
        </property>  
    </bean>  
    <!-- 扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入 -->
    <!-- <context:component-scan base-package="com.controller" />
    <context:component-scan base-package="com.service" />
    <context:component-scan base-package="com.dao" /> -->
        <context:component-scan base-package="com" />
    <!-- 配置数据源  destroy-method="close"-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClass">
            <value>${jdbc.driverClassName}</value>
        </property>
        <property name="jdbcUrl">
            <value>${jdbc.url}</value>
        </property>
        <property name="user">
            <value>${jdbc.username}</value>
        </property>
        <property name="password">
            <value>${jdbc.password}</value>
        </property>
        <!--连接池中保留的最小连接数。 -->
        <property name="minPoolSize">
            <value>5</value>
        </property>
        <!--连接池中保留的最大连接数。Default: 15 -->
        <property name="maxPoolSize">
            <value>30</value>
        </property>
        <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
        <property name="initialPoolSize">
            <value>10</value>
        </property>
        <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
        <property name="maxIdleTime">
            <value>60</value>
        </property>
        <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
        <property name="acquireIncrement">
            <value>5</value>
        </property>
        <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。 
            如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 -->
        <property name="maxStatements">
            <value>0</value>
        </property>
        <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
        <property name="idleConnectionTestPeriod">
            <value>60</value>
        </property>
        <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
        <property name="acquireRetryAttempts">
            <value>30</value>
        </property>
        <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试 
            获取连接失败后该数据源将申明已断开并永久关闭。Default: false -->
        <property name="breakAfterAcquireFailure">
            <value>true</value>
        </property>
        <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable 
            等方法来提升连接测试的性能。Default: false -->
        <property name="testConnectionOnCheckout">
            <value>false</value>
        </property>
        
        <property name="automaticTestTable">
            <value>true</value>
        </property>
    </bean>

    <!-- 配置Jdbc模板 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置事务管理器 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
        p:dataSource-ref="dataSource" />

    <!-- 通过AOP配置提供事务增强,让controller包下所有Bean的所有方法拥有事务 -->
    <!-- <aop:config proxy-target-class="true">
        <aop:pointcut id="serviceMethod"
            expression=" execution(* com.controller..*(..))" />
        <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />
    </aop:config>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice> -->

    <!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
    
    
        
    <!-- VM视图解析器 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
        <property name="requestContextAttribute" value="rc"></property>
        <property name="cache" value="true"/>
        <property name="prefix" value=""/>
        <property name="suffix" value=".vm"/>
        <property name="contentType"><value>text/html;charset=UTF-8</value></property>
        <property name="dateToolAttribute"><value>dateTool</value></property>
        <property name="numberToolAttribute"><value>numberTool</value></property>
    </bean>
    
    
    <!-- 指定模板视图存放位置,以及编码格式 -->
    <bean id="velocityConfigurer" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
          <property name="resourceLoaderPath" value="/WEB-INF/velo/"/>
          <property name= "velocityProperties">      
            <props>      
                 <prop key="input.encoding">utf-8</prop>      
                 <prop key="output.encoding">utf-8</prop>          
            </props>      
        </property>               
    </bean>
    
    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
    
    
<!-- 访问数据库前,查询MEMCACHED缓存服务器 -->
    <!-- <bean id="memcachedInterceptor" class="com.interceptor.MemcachedInterceptor"></bean>  
    <aop:config>
        <aop:pointcut expression="execution(* select*(..))"  
                    id="memcachedPointCut"/> 
        <aop:aspect id="memcachedAspect" ref="memcachedInterceptor"> 
             <aop:around    pointcut-ref="memcachedPointCut"   method="aronud"/>
        </aop:aspect>    
        
     </aop:config>   -->
    
    
     
    <!-- 官方文档地址 http://code.google.com/p/xmemcached/wiki/Spring_Integration -->
 
     <bean
        id="memcachedClientBuilder"
        class="net.rubyeye.xmemcached.XMemcachedClientBuilder"
        p:connectionPoolSize="20"
        p:failureMode="true">

        <constructor-arg>
            <list>
                <bean class="java.net.InetSocketAddress">
                
                    <constructor-arg>
                        <value>你的memcache的地址</value>
                    </constructor-arg>
                    <constructor-arg>
                        <value>11211</value>
                    </constructor-arg>
                </bean>
<!--             <bean class="java.net.InetSocketAddress">  -->
<!--                     <constructor-arg> -->
<!--                         <value>192.168.1.2</value> -->
<!--                     </constructor-arg> -->
<!--                     <constructor-arg> -->
<!--                         <value>10002</value> -->
<!--                     </constructor-arg> -->
<!--                 </bean> -->
<!--                 <bean class="java.net.InetSocketAddress"> -->
<!--                     <constructor-arg> -->
<!--                         <value>192.168.1.3</value> -->
<!--                     </constructor-arg> -->
<!--                     <constructor-arg> -->
<!--                         <value>10003</value> -->
<!--                     </constructor-arg> -->
<!--                 </bean> -->
<!--                 <bean class="java.net.InetSocketAddress"> -->
<!--                     <constructor-arg> -->
<!--                         <value>192.168.1.4</value> -->
<!--                     </constructor-arg> -->
<!--                     <constructor-arg> -->
<!--                         <value>4</value> -->
<!--                     </constructor-arg> -->
<!--                 </bean>  -->
                
                
            </list>
        </constructor-arg>
        
        
        <constructor-arg>
            <list>
                <value>1</value>
<!--                 <value>2</value> -->
<!--                 <value>3</value> -->
<!--                 <value>4</value> -->
            </list>
        </constructor-arg>
        
        
        
        <property name="commandFactory">
            <bean class="net.rubyeye.xmemcached.command.TextCommandFactory" />
        </property>
        <property name="sessionLocator">
            <bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator" />
        </property>
        <property name="transcoder">
            <bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" />
        </property>
    </bean>

    <bean
        id="memcachedClient"
        factory-bean="memcachedClientBuilder"
        factory-method="build"
        destroy-method="shutdown" />  
        
    <bean id="multipartResolver" 
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
        p:defaultEncoding="utf-8"/>
        
        
    <mvc:interceptors>
        <!-- 拦截所有请求
         <bean class="com.etoak.util.LoginCheck2"></bean>-->
         <mvc:interceptor>
            <mvc:mapping path="/dashboard"/>
            <mvc:mapping path="/dashboard/**"/>
            <mvc:mapping path="/setting"/>
            <mvc:mapping path="/setting/**"/>
            <bean class="com.interceptor.LoginCheck"></bean>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.interceptor.CityCheck"></bean>
        </mvc:interceptor>
    </mvc:interceptors>
    <!-- spring && mina -->
         <!-- executorFilter多线程处理 -->  
    <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" />-->  
        <!-- 处理对象流时候用ObjectSerializationCodecFactory -->  
        <!-- <bean class="org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory" /> -->  
            <bean class="com.umaiw.socket.ServerCodeFactory" />  
        </constructor-arg>  
    </bean>

    <bean id="loggingFilter" class="org.apache.mina.filter.logging.LoggingFilter" />

    <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>

    <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>

     <!-- session config -->
    <bean id="sessionConfig" factory-bean="ioAcceptor"
        factory-method="getSessionConfig" >       
        <property name="readerIdleTime" value="50"/>
    </bean> 

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


    <bean id="dataHandler" class="com.umaiw.socket.DataHandler">    
    </bean> 
    
        <!--这里是udp的部分 如果想用请下载udp部分的代码 会在最下面有下载-->
 <!-
    <bean id="udpAcceptor" class="org.apache.mina.transport.socket.nio.NioDatagramAcceptor" init-method="bind" destroy-method="unbind">  
        <property name="defaultLocalAddress" value=":10001" />  
        <property name="handler" ref="UdpHandler" />  
        <property name="filterChainBuilder" ref="filterChainBuilder" />           
    </bean>
    <bean id="UdpHandler" class="com.umaiw.socket.UdpHandler">    
    </bean> 
-->
    
</beans>

如果需要数据库连接的话 再src下面再写个jdbc.properties具体怎么写大家都会把 好吧给个例子

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://你的数据库地址哦:3306/umaiwtest?relaxAutoCommit=true&zeroDateTimeBehavior=convertToNull
jdbc.username=test
jdbc.password=test


然后是DataHandler  处理各种事件的地方

其中的messageRecive方法里调用的

String result=constants.getClassName(Long.parseLong(command));

Command cmd = (Command)constants.newCommand(result);
           cmd.action(session, other);

则是吧处理的业务逻辑写成了实现command的接口都有一个action方法

然后动态加载command这个对应名字类的方法

这里是按  :   来分隔参数的

package com.umaiw.socket;

import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.mina.core.future.CloseFuture;
import org.apache.mina.core.future.IoFuture;
import org.apache.mina.core.future.IoFutureListener;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.model.UserSession;
import com.model.umaiw_app_system;
import com.service.GetInitKeyService;
import com.service.implement.GetInitKeyServiceImpl;
import com.umaiw.command.Command;
import com.umaiw.command.Constants;
import com.umaiw.command.SocketModel;
import com.util.DesUtil;

@Component("DataHandler")
public class DataHandler extends IoHandlerAdapter implements Runnable{
     
    @Autowired
    private Constants constants;
    
    private final static Logger log = LoggerFactory.getLogger(DataHandler.class);

        private final Set<IoSession> sessions = Collections.synchronizedSet(new HashSet<IoSession>());
        //private UserSession UserSession;
        @Autowired
        private static  Map<String,IoSession> users = Collections.synchronizedMap(new HashMap<String,IoSession>());

         
    

        @Override

        public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
            log.error(" 有异常发生时被触发exceptionCaught。",cause);
            session.close(true); 
        }


        @Override

        public void sessionCreated(IoSession session) throws Exception {
               log.info("当创建一个新连接时被触发,即当开始一个新的Session时被触发。");
            log.info("创建一个新连接:{}", session.getRemoteAddress());
            /*//50秒无读写操作就触发idele
            session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 50);*/
            sessions.add(session);
            log.info("并发的个数:\t"+sessions.size());
         session.setAttribute("command",1);
              messageSentSingle(session, "创建了一个socket连接哦");

        }


        @Override

        public void messageReceived(IoSession session, Object message) throws Exception {

            log.info("服务器接收到数据: {}", message);
             String[] mes=message.toString().split(":");
            String version=mes[0];//协议版本号
            String ID=mes[1];//包ID(10进制)
            String mark=mes[2];//唯一标识
            String mobile=mes[3];//手机号码
            String command=mes[4];//命令ID(10进制)
            String[] other=new String[mes.length*2];
            if(mes.length>5){
                for(int i=5;i<mes.length;i++){
                    int x=0;
                    other[x]=mes[i];
                    x++;
                }
            }
         
            if(mobile==null){
                mobile="1";
            }
            session.setAttribute("mobile",mobile);
            String result=constants.getClassName(Long.parseLong(command));
            Command cmd = (Command)constants.newCommand(message);
           cmd.action(session, message);
           Object oldpacket_id=session.getAttribute("packet_id");
            if(oldpacket_id!=null){
                 session.setAttribute("oldpacket_id",oldpacket_id);
            }
            String packet_id=new Date().getTime()+"";
            session.setAttribute("packet_id",packet_id);
            session.setAttribute("command",Integer.parseInt(command));
              //   messageSentSingle(session, "业务处理完了");

        }

        public static void messageSentAll( Object message) throws Exception {

            log.info("发送消息时时被触发,即在调用IoSession.write()时被触发,message代表将要发送的消息。=" + message);
         // 向所有客户端发送的数据
            SocketModel socm=new SocketModel(new Date().getTime()+"", "", 5, message);
           String send=socm.toString();
           Collection<IoSession> sessions = users.values();

            for (IoSession sess : sessions) {

                sess.write(send);

            }

        }
        public static void messageSentSingle(IoSession session, Object message) throws Exception {

            log.info("发送消息时时被触发,即在调用IoSession.write()时被触发,message代表将要发送的消息。=" + message);
         // 向所有客户端发送的数据
            Integer command=(Integer) session.getAttribute("command");
            SocketModel socm=new SocketModel(new Date().getTime()+"", "", command, message);
           String send=socm.toString();
           session.write(send);
        }

        public static void messageSentPart( Object message,String city_id) throws Exception {

            log.info("发送消息时时被触发,即在调用IoSession.write()时被触发,message代表将要发送的消息。=" + message);
            Object[] key=users.keySet().toArray();
            for (int i = 0; i < key.length; i++) {
                if(key[i].toString().contains(city_id)){
                    IoSession iosession=users.get(key[i]);
                     SocketModel socm=new SocketModel(new Date().getTime()+"", "", 5, message);
                       String send=socm.toString();
                    iosession.write(send);
                }
            }
         // 向所有客户端发送的数据
           
           
        }

        public static Map<String, IoSession> getUsers() {
            return users;
        }
        

        
        @Override

        public void sessionClosed(IoSession session) throws Exception {

            log.info("关闭当前session:{}#{}", session.getId(), session.getRemoteAddress());

            

            CloseFuture closeFuture = session.close(true);

            closeFuture.addListener(new IoFutureListener<IoFuture>() {

                public void operationComplete(IoFuture future) {

                    if (future instanceof CloseFuture) {

                        ((CloseFuture) future).setClosed();

                        log.info("sessionClosed CloseFuture setClosed-->{},", future.getSession().getId());

                    }

                }

            });
            UserSession userSession=   (UserSession) session.getAttribute("UserSession");
            String  mobile=(String) session.getAttribute("mobile");
            if(null!=mobile&&userSession!=null){
                users.remove(mobile+"+"+userSession.getCity_id());
            }
            sessions.remove(session);
            log.info("关闭的连接的剩余的个数:\t"+sessions.size());
        }

     

     

        @Override

        public void sessionIdle(IoSession session, IdleStatus status) throws Exception {

            // session.close();
            log.info("IDLE " + session.getIdleCount(status)+"次;"+"user个数"+users.size()+"sessions个数"+sessions.size());
            if(session.getIdleCount(status) > 5){
                log.info("连接空闲= " + session.getIdleCount(status)+",触发session关闭");
                session.close(true); 
            }

        }

     

        @Override

        public void sessionOpened(IoSession session) throws Exception {
              log.info("进入当打开一个连接时被触发sessionOpened!");
            log.info("打开一个session:{}#{}", session.getId(), session.getBothIdleCount());
          
            try {
                super.sessionOpened(session);
            } catch (Exception e) {
                log.error("",e);
            }
        }

        @Override

        public void messageSent(IoSession session, Object message) throws Exception {

            log.info("发送消息时时被触发,即在调用IoSession.write()时被触发,message代表将要发送的消息。=" + message);
            try {
                super.messageSent(session, message);
            } catch (Exception e) {
                log.error("",e);
            }

        }
    
       
        }  
}

然后是处理业务逻辑的command接口 和实现它的类(这里就举1个例子,多写业务处理 就再多些点实现类就行)

command.java

package com.umaiw.command;

import org.apache.mina.core.session.IoSession;

public interface  Command {
public void action(IoSession session,String[] other) ;
}

UMMSG_TCP_SENDINFORMATIONTOSERVER.java(业务逻辑处理)

package com.umaiw.command;

import org.apache.mina.core.session.IoSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

import com.model.UserSession;
import com.service.LoginService;
import com.service.implement.LoginServiceImpl;
import com.umaiw.socket.DataHandler;
@Component("UMMSG_TCP_SENDINFORMATIONTOSERVER")
public class UMMSG_TCP_SENDINFORMATIONTOSERVER implements Command {
    @Autowired
private  LoginService loginService ;
    @Override
    public void action(IoSession session, String[] param) {
        
        
        String mobile=(String) session.getAttribute("mobile");
        UserSession user= loginService.getUserSession(mobile);
        session.setAttribute("UserSession",user);
        DataHandler.getUsers().put(mobile+"+"+user.getCity_id(), session);
        
        
//        DataHandler.messageSentSingle(session, s);
    }

}

接下来是根据传过来的command来找是哪个处理类的类

Constants.java

这里注册了三个类(上面给了一个类UMMSG_TCP_SENDINFORMATIONTOSERVER的例子,别的照着写就行啦)

package com.umaiw.command;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("Constants")
public class Constants {
    @Autowired
    private UMMSG_TCP_CHECKCLIENT uMMSG_TCP_CHECKCLIENT;
    @Autowired
    private UMMSG_TCP_MAKESURECEIVE uMMSG_TCP_MAKESURECEIVE;
    @Autowired
    private UMMSG_TCP_SENDINFORMATIONTOSERVER uMMSG_TCP_SENDINFORMATIONTOSERVER;
    @Autowired
    private Map<String, Object> registry = new HashMap<String, Object>();

    @Autowired
    private void res() {
        // 2、客户端发送口令供服务器端验证
        registry.put(UMMSG_TCP_CHECKCLIENT_name, uMMSG_TCP_CHECKCLIENT);
        // 3、客户端发送身份信息给服务器
        registry.put(UMMSG_TCP_SENDINFORMATIONTOSERVER_name,
                uMMSG_TCP_SENDINFORMATIONTOSERVER);
        // 4、客户端发送回执给服务器
        registry.put(UMMSG_TCP_MAKESURECEIVE_name, uMMSG_TCP_MAKESURECEIVE);
    }

    // 方法对应值与类名
    // 2、客户端发送口令供服务器端验证
    public static final int UMMSG_TCP_CHECKCLIENT_code = 0x00000002;
    public static final String UMMSG_TCP_CHECKCLIENT_name = "UMMSG_TCP_CHECKCLIENT";
    // 3、客户端发送身份信息给服务器
    public static final int UMMSG_TCP_SENDINFORMATIONTOSERVER_code = 0x00000003;
    public static final String UMMSG_TCP_SENDINFORMATIONTOSERVER_name = "UMMSG_TCP_SENDINFORMATIONTOSERVER";
    // 4、客户端发送回执给服务器
    public static final int UMMSG_TCP_MAKESURECEIVE_code = 0x00000004;
    public static final String UMMSG_TCP_MAKESURECEIVE_name = "UMMSG_TCP_MAKESURECEIVE";

    // 注册到registry集合里好使用

    public String getClassName(long code) {

        if (code == UMMSG_TCP_SENDINFORMATIONTOSERVER_code) {
            return UMMSG_TCP_SENDINFORMATIONTOSERVER_name;
        } else if (code == UMMSG_TCP_SENDINFORMATIONTOSERVER_code) {
            return UMMSG_TCP_SENDINFORMATIONTOSERVER_name;
        } else if (code == UMMSG_TCP_MAKESURECEIVE_code) {
            return UMMSG_TCP_MAKESURECEIVE_name;
        } else if (code == UMMSG_TCP_CHECKCLIENT_code) {
            return UMMSG_TCP_CHECKCLIENT_name;
        }

        return null;

    }

    public Object newCommand(String name) {

        return registry.get(name);
        

    }

    // 获得无符号值
    public static int getUnsignedValue(byte bt) {
        int i = bt;
        if (bt < 0) {
            i = 257 + i;
        }
        return i;
    }

    // 获得无符号值
    public static long getLongValue(byte[] bt) {
        long l = 0;
        for (int i = 0; i < bt.length; i++) {
            l = (l << 8) | (bt[i] & 0xff);
        }
        return l;
    }

    public String getClassName(byte[] bt) {
        return getClassName(getLongValue(bt));
    }

    /**
     * @since Integer转换byte[]
     * @param len
     * @return
     */
    public static byte[] getByteByInt(Integer len, int buffer) {
        byte[] b = new byte[buffer];
        for (int i = b.length - 1; i > -1; i--) {
            b[i] = new Integer(len & 0xff).byteValue();// 将最高位保存在最低位
            len = len >> 8; // 向右移8位
        }
        return b;
    }

    public static byte[] getByteByStr(String len, int buffer) {
        byte[] bt = new byte[buffer];

        System.arraycopy(len.getBytes(), 0, bt, 0, len.getBytes().length);
        return bt;
    }

    public static void main(String[] args) {
        // getByteByStr("123", 6);
        // byte[] bt = new byte[4];
        // bt[0] = (byte) 0x00;
        // bt[1] = (byte) 0x00;
        // bt[2] = (byte) 0x00;
        // bt[3] = (byte) 0x01;
        // System.out.println(Constants.getLongValue(bt));
        // System.out.println(Constants.getLongValue(Constants
        // .getByteByInt(110, 4)));
        // getByteByInt(0x10000001, 4);
        System.err.println(Integer.MAX_VALUE);

    }
}

接下来是socketmodel 就是用来整理发送消息的格式的

SocketModel.java

package com.umaiw.command;

public class SocketModel {
private String version="UM";
private String id;
private String mark="";
private String mobile;
private Object other;
private Integer command;
public SocketModel(  String id, String mobile,
         Integer command,Object other) {

    this.id = id;
    this.mobile = mobile;
    this.other = other;
    this.command = command;
    
}
public String toString() {
    return version+":"+id+":"+mark+":"+mobile+":"+command+":"+other+(char)7;
}

public String getVersion() {
    return version;
}
public void setVersion(String version) {
    this.version = version;
}

public String getId() {
    return id;
}
public void setId(String id) {
    this.id = id;
}
public String getMark() {
    return mark;
}
public void setMark(String mark) {
    this.mark = mark;
}
public String getMobile() {
    return mobile;
}
public void setMobile(String mobile) {
    this.mobile = mobile;
}
public Object getOther() {
    return other;
}
public void setOther(Object other) {
    this.other = other;
}
public Integer getCommand() {
    return command;
}
public void setCommand(Integer command) {
    this.command = command;
}


}

最后是mina必备的codefactory和decode,encode

ServerCodeFactory.java

package com.umaiw.socket;

import java.nio.charset.Charset;  
  
import org.apache.mina.core.session.IoSession;  
import org.apache.mina.filter.codec.ProtocolCodecFactory;  
import org.apache.mina.filter.codec.ProtocolDecoder;  
import org.apache.mina.filter.codec.ProtocolEncoder;  
import org.apache.mina.filter.codec.textline.LineDelimiter;  
import org.apache.mina.filter.codec.textline.TextLineDecoder;  
import org.apache.mina.filter.codec.textline.TextLineEncoder;  
  
public  class ServerCodeFactory implements ProtocolCodecFactory {  
  
        private final ProtocolEncoder encoder;  
        private final ProtocolDecoder decoder;  
        /*final static char endchar = 0x1a;*/  
        final static char endchar = 0x0d;  
        
        public ServerCodeFactory() {             
            this(Charset.forName("utf-8"));  
        }  
        
        public ServerCodeFactory(Charset charset) {  
             encoder = new CharsetEncoder();     
             decoder = new CharsetDecoder();     
             }  
  
        @Override  
        public ProtocolDecoder getDecoder(IoSession session) throws Exception {  
            // TODO Auto-generated method stub  
            return decoder;  
        }  
        @Override  
        public ProtocolEncoder getEncoder(IoSession session) throws Exception {  
            // TODO Auto-generated method stub  
            return encoder;  
        }

        public ProtocolEncoder getEncoder() {
            return encoder;
        }

        public ProtocolDecoder getDecoder() {
            return decoder;
        }  
        
  
}

CharsetDecoder.java  (这里用(char)7当结束标志)

package com.umaiw.socket;

 

import java.nio.charset.Charset;

import org.apache.log4j.Logger;

import org.apache.mina.core.buffer.IoBuffer;

import org.apache.mina.core.session.IoSession;

import org.apache.mina.filter.codec.ProtocolDecoder;

import org.apache.mina.filter.codec.ProtocolDecoderOutput;

 

/**

 * <b>function:</b> 字符解码

 * @author hoojo

 * @createDate 2012-6-26 上午11:14:18

 * @file CharsetDecoder.java

 * @package com.hoo.mina.code

 * @project ApacheMiNa

 * @blog http://blog.csdn.net/IBM_hoojo

 * @email hoojo_@126.com

 * @version 1.0

 */

public class CharsetDecoder implements ProtocolDecoder {

 

    private final static Logger log = Logger.getLogger(CharsetDecoder.class);

    

    private final static Charset charset = Charset.forName("UTF-8");    

    // 可变的IoBuffer数据缓冲区

    private IoBuffer buff = IoBuffer.allocate(100).setAutoExpand(true);

    

    @Override

    public void decode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {

        log.info("#########decode#########");

        

        // 如果有消息

        while (in.hasRemaining()) {

            // 判断消息是否是结束符,不同平台的结束符也不一样;

            // windows换行符(\r\n)就认为是一个完整消息的结束符了; UNIX 是\n;MAC 是\r

            byte b = in.get();

            if (b == (char)7) {

                buff.flip();

                byte[] bytes = new byte[buff.limit()];

                buff.get(bytes);

                String message = new String(bytes, charset);

                

                buff = IoBuffer.allocate(100).setAutoExpand(true);

                

                // 如果结束了,就写入转码后的数据

                out.write(message);

                log.info("message: " + message);

            } else {

                buff.put(b);

            }

        }

    }

 

    @Override

    public void dispose(IoSession session) throws Exception {

        log.info("#########dispose#########");

        log.info(session.getCurrentWriteMessage());

    }

 

    @Override

    public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception {

        log.info("#########完成解码#########");

    }

}

CharsetEncoder.java

package com.umaiw.socket;

 

import java.nio.charset.Charset;

import org.apache.log4j.Logger;

import org.apache.mina.core.buffer.IoBuffer;

import org.apache.mina.core.session.IoSession;

import org.apache.mina.filter.codec.ProtocolEncoder;

import org.apache.mina.filter.codec.ProtocolEncoderOutput;

import org.apache.mina.filter.codec.textline.LineDelimiter;

 

/**

 * <b>function:</b> 字符编码

 * @author hoojo

 * @createDate 2012-6-26 上午11:32:05

 * @file CharsetEncoder.java

 * @package com.hoo.mina.code

 * @project ApacheMiNa

 * @blog http://blog.csdn.net/IBM_hoojo

 * @email hoojo_@126.com

 * @version 1.0

 */

public class CharsetEncoder implements ProtocolEncoder {

    private final static Logger log = Logger.getLogger(CharsetEncoder.class);

    private final static Charset charset = Charset.forName("UTF-8");

    

    @Override

    public void dispose(IoSession session) throws Exception {

        log.info("#############dispose############");

    }

 

    @Override

    public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {

        log.info("#############字符编码############");

        IoBuffer buff = IoBuffer.allocate(100).setAutoExpand(true);

        buff.putString(message.toString(), charset.newEncoder());

        // put 当前系统默认换行符

      //  buff.putString(LineDelimiter.DEFAULT.getValue(), charset.newEncoder());

        // 为下一次读取数据做准备

        buff.flip();

        

        out.write(buff);

    }

}

部分代码(直接拷贝到java web项目下)

共有 人打赏支持
粉丝 10
博文 29
码字总数 22265
×
angle_小帅
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: