采集项目总结

 

 

 

采集项目总结

 

一、项目简介

本采集系统的基本功能是通过TCP/IP协议长连接基站,将基站上传的字节流根据协议解析为相应的基站和定位卡信息,过滤后进行持久化,提供访问页面供用户查询定位信息;用户可通过采集系统须对基站、位置、卡等相关实体进行管理。

系统用户分为两类,应用系统用户和管理员。

 

二、项目架构图

  

 

 

三、Ehcache在项目中的应用

Ehcache缓存数据,在Mina handler类中收到卡定位信息后直接放到缓存中,不直接与数据库交互,与数据库的交互放在缓存监听器类中。这里有一个问题是ehcacheSpring 的整合中没有提供缓存与监听器的绑定。只能手工实现,例:

A、

<cache name="alarmrecordCache" maxElementsInMemory="200"   
       eternal="false"
       timeToIdleSeconds="30" overflowToDisk="false"
       memoryStoreEvictionPolicy="LFU">
      <cacheEventListenerFactory  
              class="com.**.listener.CacheEventListenerFactory" 
              properties="bean=alarmRecordListener"/> 
</cache>

 
B、

<bean id="alarmRecordListener"    
      class="com.**.listener.AlarmRecordListener"  lazy-init="false"> 
<property name="alarminfoService" ref="alarminfoService">
</property> 
</bean>

 
C、

public class CacheEventListenerFactory extends   
    net.sf.ehcache.event.CacheEventListenerFactory{
       @Override
       public CacheEventListener createCacheEventListene (Properties  properties) {

       String beanName = properties.getProperty( "bean" );

       if ( beanName == null ) {

         throw new IllegalArgumentException( "缓存监听器名字未定义" );

       }

         return (CacheEventListener)  
            SpringContextTool.getApplicationContext().getBean(          beanName );

}

}

 

  

 

四、基站分2种:小区与CDMA ,小区基站有固定ip CDMA基站无固定ip,通过发送消息通过sim->移动->互联网,所以CDMAip地址是变动的。业务中有要求给CDMA下发指令,因为没有固定ip ,所以只能广播。这样就有一个问题,广播时会有很多“远程主机已经关闭”错误,因为该ip的连接已经没有了。

解决:将所有下发的命令先存放在一个HashMap(Integer,List),integer 为基站编号,List 中存放命令,命令可能有多条。当CDMA基站向服务器发送信息,SessionOpened 时间中增加代码:根据基站编号查询命令并下发。即:CDMA打开连接时下发命令,基本上这个时候连接还在的。

A、

public class CdmaSendCommandSupport {

   /**

    * 数据存放格式 integer -> 基站号 List<AbstractCommond> -> 命令LIST

    */

   public static HashMap<Integer, List<AbstractCommond>> cdmaCommandMap = new HashMap<Integer, List<AbstractCommond>>();

 

   /**

    * 把命令放到 Map 中去

    */

   public static void putCommandToQueue(int readerid, AbstractCommond c) {

      if (readerid == 0) {

         ApplicationContext appContext = SpringContextTool.getApplicationContext();

         ReaderService readerService = (ReaderService) appContext.getBean("readerService");

         @SuppressWarnings("rawtypes")

         List idList = readerService.loadAllCdmaReaderid();

         for (int i = 0; i < idList.size(); i++) {

            List<AbstractCommond> cList = CdmaSendCommandSupport.cdmaCommandMap

                   .get((Integer) idList.get(i));

            if (cList == null) {

                cList = new ArrayList<AbstractCommond>();

            }

            cList.add(c);

            CdmaSendCommandSupport.cdmaCommandMap.put((Integer) idList.get(i), cList);

         }

      } else {

         List<AbstractCommond> cList = CdmaSendCommandSupport.cdmaCommandMap

                .get(new Integer(readerid));

         if (cList == null) {

            cList = new ArrayList<AbstractCommond>();

         }

         cList.add(c);

         CdmaSendCommandSupport.cdmaCommandMap.put(new Integer(readerid),cList);

      }

   }

 

}

 

B、

// 1、处理未发送的命令

         List<AbstractCommond> cList = CdmaSendCommandSupport.cdmaCommandMap

                .get(readerState.getReaderId());

         if (cList != null) {

            for (AbstractCommond c : cList)

                session.write(c);

            CdmaSendCommandSupport.cdmaCommandMap.remove(readerState

                   .getReaderId());

                            }

 

  

                   

         五、枚举的应用

          业务中遇到这样的问题,卡的类型,基站的类型,报警的类型都是使用的固定值,程序中要定义常量,数据库中也存在记录。容易造成不一致,最后采用了枚举,hibernate中有一个UserType接口用用来自定义与数据库的映射,注意这样修改后,相关的前台显示与查询均要修改。

 

 


      public class EnumUserType<E extends Enum<E>> implements UserType {

   private static final int[] sqlTypes = {Types.INTEGER };

 

   private Class<E> clazz = null;

   

   protected EnumUserType(Class<E> c) {

      clazz = c;

      if(!clazz.isEnum()){//检查是否是枚举类

         throw new IllegalArgumentException(c+"不是枚举类");

      }

      if(!Identifiable.class.isAssignableFrom(clazz)){//检查是否实现Identifiable接口

         throw new IllegalArgumentException(c+"未实现Identifiable接口");

      }

   }

 

   @Override

   public int[] sqlTypes() {

      return sqlTypes;

   }

 

   @Override

   public Class<E> returnedClass() {

      return clazz;

   }

 

   @Override

   public boolean equals(Object x, Object y){

      if (x == y)

         return true;

      if (x == null || y == null)

         return false;

      else

         return x.equals(y);

   }

 

   @Override

   public int hashCode(Object x) {

      return x.hashCode();

   }

   /**

    * 把数据库中的查询结果集转换成相应的枚举类

    */

   @Override

   public Object nullSafeGet(ResultSet rs, String[] names, Object owner)

         throws HibernateException, SQLException {

      int id = rs.getInt(names[0]);

      Object result = null;

      if (!rs.wasNull())

         result = getEnumByID(id);

      return result;

   }

   /**

    * 私有方法,配合Identifiable接口通过ID返回相应的枚举值

    */

   private E getEnumByID(int id) {

      E[] values = clazz.getEnumConstants();

      E  type = null;

      for(E  t : values){

         if(id==((Identifiable)t).getID()){

            type = t;

            break;

         }

      }

      if(type==null){

         throw new HibernateException("ID为"+id+"的枚举类"+clazz.getName()+"不存在");

      }

      return type;

   }

   /**

    * 配合Identifiable接口将枚举值转成int类型以存入数据库

    */

   @Override

   public void nullSafeSet(PreparedStatement st, Object value, int index)

         throws HibernateException, SQLException {

      if (null == value)

         st.setNull(index, Types.INTEGER);

      else

         st.setInt(index, ((Identifiable) value).getID());//必须实现Identifiable接口

   }

 

   @Override

   public Object deepCopy(Object value) throws HibernateException {

      return value;

   }

 

   @Override

   public boolean isMutable() {

      return false;

   }

 

   @Override

   public Serializable disassemble(Object value) throws HibernateException {

      return (Serializable) value;

   }

 

   @Override

   public Object assemble(Serializable cached, Object owner)

         throws HibernateException {

      return cached;

   }

 

   @Override

   public Object replace(Object original, Object targer, Object owner)

         throws HibernateException {

      return original;

                    }

 

 

 

                                                     

 

 

 

六、帮助类的应用

使用帮助类能更好的减低程序的耦合, 并且这些帮助类和方法一般定义为static,能减少内存占用,但是帮助类中经常会需要用到其他类,直接声明显然不太好。Spring有获取上下文,进而获取bean的方法。正好能用。

A、/**

 * 持有Spring上下文

*/

public class SpringContextTool implements ApplicationContextAware {

    private static ApplicationContext context;

    public void setApplicationContext(ApplicationContext acx) {

       context = acx;

    }

    public static ApplicationContext getApplicationContext() {

        return context;

    }

 }

 

B、<bean name="springContextTool" class="com.yixun.middleware.util.SpringContextTool" lazy-init="false"></bean>

    <bean id="propertyConfigurer"

    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"  depends-on="springContextTool">

       <property name="location">

           <value>classpath:system.properties</value>

       </property>

    </bean>

 

C、public static NioSocketAcceptor getNioSocketAcceptor() {

      ApplicationContext context = SpringContextTool.getApplicationContext();

      return (NioSocketAcceptor) context.getBean("areaNioAcceptor");

                  }

 

 

七、关于Mina解析

   .....

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值