第二银行

yp.wang

导航

金仓短信猫多线程项目开发实例

Posted on 2011-02-09 19:07  第二银行  阅读(2009)  评论(0编辑  收藏  举报

买了金仓短信猫,由于中间件需要加钱,故自己用java开发了一个类似的中间件,放出来供大家参考!
需要实现的功能:
1.自动扫描数据库里的待发送短信表,有内容则将其读取到短信猫出发送出去,没有则不发送
2.短信猫定时接收短信,收到短信则放到数据库里收取短信表内,供其他用户使用
开发思路:
1.建立一个 操作数据库的服务:DataBaseService
2.建立一个 短信猫收发短信的服务:GsmService
3.在以上两个服务基础上,套用经典生产者和消费者模型,建立一个短信生产模块和一个短信发送模块和一个控制器,控制器负责生产者和消费者之间的通信,
分别是:SmsProducer、SmsSender和Controler
4.建立一个发送短息的表的model,当做存放短信的容器,此model由消费者和生产者共同维护
下面是具体的代码:

===============================================================================================
package service;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.log4j.Logger;

public class DataBaseService{
private static Properties property;

String Driver = null;   //驱动程序
    String url = null;    //连接的URL,db_name为数据库名    
    String user = null;    //用户名
    String password = null;    //密码
    Connection conn = null;
    Statement statement = null;
    ResultSet rs = null;
    private static Logger logger = Logger.getLogger(DataBaseService.class);
    public  DataBaseService() {
    	logger.info("------------------------开始分割线------------------------------");
    	 //加载配置文件
 property = new Properties();
  try {
property.load(
GsmService.class.getResourceAsStream(
"/config/tonconfig.properties"));
} catch (IOException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
Driver = property.getProperty("Driver");
url = property.getProperty("url");
user = property.getProperty("user");
password = property.getProperty("password");

    	try {
Class.forName(Driver).newInstance();
} catch (InstantiationException e) {
// TODO 自动生成 catch 块
logger.error("********错误:数据库驱动实例化失败,连接数据库失败!!!********");
} catch (IllegalAccessException e) {
// TODO 自动生成 catch 块
logger.error("********错误:驱动异常,连接数据库失败!!!********");
} catch (ClassNotFoundException e) {
// TODO 自动生成 catch 块
logger.error("********错误:没有找到数据库驱动,连接数据库失败!!!********");
}
try {
conn = DriverManager.getConnection(url,user,password);
if(!conn.isClosed()){
statement = conn.createStatement();
logger.info("Start:连接数据库,成功");

}
} catch (SQLException e) {
// TODO 自动生成 catch 块
logger.error("********错误:连接数据库失败,请检查数据库用户名,密码或者url是否正确!!!********");
}
    }
    /**
     * 根据传入的sql语句查询
     * @param sql
     * @param num 需要查询的表的列数
     * @return 数据库内容一个list为一行,里面为该行
     */
    public List selectSql(String sql,int num){
    	//String[] result = new String[num];
    	List<String[]> list = new ArrayList();
    	try {
    	  
 rs = statement.executeQuery(sql);
 while(rs.next()){
 String[] result = new String[num];
 for(int i = 1; i<=num ;i++){
 result[i-1] = rs.getString(i);
 }
 list.add(result);
  }
} catch (SQLException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
    	return list;
    }
    
    /**
     * @author Administrator
     * 执行写数据库操作
     * @param sql 需要执行的sql语句
     * @return 插入的记录条数
     */
    public int insertSql(String sql){
    	int i = 0;
    	 try {
i = statement.executeUpdate(sql);
} catch (SQLException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
return i;
    }
    
    /**
     * @author Administrator
     * 执行更新数据库操作
     * @param sql 需要执行的sql语句
     * @return 改变的记录条数
     */
    public int updateSql(String sql){
    	int i = 0;
    	try {
i= statement.executeUpdate(sql);
} catch (SQLException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
return i;
    }
    
    /**
     * 关闭数据库连接
     *
     */
    public void close(){
    	try {
    	 if(rs != null)
rs.close();
    	 if(statement != null)
statement.close();
logger.info("Over:关闭数据库,成功");
} catch (SQLException e) {
// TODO 自动生成 catch 块
logger.error("********错误:关闭数据库失败!!!********");
}	

logger.info("------------------------结束分割线------------------------------");
    }
    
//    public static void main(String[] args){
//    	DataBaseService sdb = null;
//    	try {
//    	 sdb = new DataBaseService();
//    	 String sql = "select * from sms_boxsending";
//    	 int num = 23;
//	 List<String[]> list = sdb.selectSql(sql, num);
//	 String[] ll = list.get(0);
//	 System.out.println(ll[22]);
//	 } catch (Exception e) {
//	 // TODO 自动生成 catch 块
//	 e.printStackTrace();
//	 }finally{
//	 //sdb.close();
//	 }
//    }

}
===============================================================================================
package service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import GSMModem.GSMMessage;
import GSMModem.GSMModem;
import org.apache.log4j.*;
import java.util.Properties;

public class GsmService {

 String device = null;
 String baud = null;
 String sn = null;
 String mobile = null;
 String count = null;
 int intCount = 1;
 String text = "113";     //短信内容
 String text_eng = "119"; //短信内容
 String result = null;
 private static Properties property;
 private static Logger logger = Logger.getLogger(GsmService.class);
 GSMModem gsmmodem1 = null;
 public GsmService(){
 //加载配置文件
 property = new Properties();
  try {
property.load(
GsmService.class.getResourceAsStream(
"/config/tonconfig.properties"));
} catch (IOException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
    gsmmodem1 = new GSMModem();
    device = System.getProperty("SMS.Device");
    baud = System.getProperty("SMS.Baud");
    sn = System.getProperty("SMS.Sn");
    mobile = System.getProperty("SMS.Mobile");
    count = System.getProperty("SMS.Count");
    if (device==null) device = property.getProperty("device");
   if (baud==null) baud = property.getProperty("baud");
   if (sn==null) sn = property.getProperty("sn");
   if (count==null){
   	}else{
   	 try{
   	 intCount = Integer.parseInt(count);
   	 }
   	 finally{
   	 intCount = 1;
   	 }
   	}
   
   if(device==null || baud==null ||sn==null){
      logger.error("请正确的设定通讯串口、波特率、注册码、接收号码,否则无法正常测试!");
      return;
    }
   gsmmodem1.setDevice(device);
   gsmmodem1.setBaudrate(baud);
   gsmmodem1.setSn(sn);

    	   if (gsmmodem1.GSMModemInit() == false) {
 	         System.out.println( gsmmodem1.GSMModemGetErrorMsg());
 	         return;
 	        }
 }
 /**
  * 初始化函数,与构造函数里的功能类似
  * @author Administrator
  *
  */
  public void initGsm(){
    gsmmodem1 = new GSMModem();
    device = System.getProperty("SMS.Device");
    baud = System.getProperty("SMS.Baud");
    sn = System.getProperty("SMS.Sn");
    mobile = System.getProperty("SMS.Mobile");
    count = System.getProperty("SMS.Count");
    if (device==null) device = property.getProperty("device");
   if (baud==null) baud = property.getProperty("baud");
   if (sn==null) sn = property.getProperty("sn");
   if (count==null){
   	}else{
   	 try{
   	 intCount = Integer.parseInt(count);
   	 }
   	 finally{
   	 intCount = 1;
   	 }
   	}
   
   if(device==null || baud==null ||sn==null){
      logger.error("********错误:请正确的设定通讯串口、波特率、注册码、接收号码!!!!********");
      return;
    }
   gsmmodem1.setDevice(device);
   gsmmodem1.setBaudrate(baud);
   gsmmodem1.setSn(sn);

    	   if (gsmmodem1.GSMModemInit() == false) {
 	         System.out.println( gsmmodem1.GSMModemGetErrorMsg());
 	         return;
 	        }else{
 	        	logger.info("与短信猫连接,成功!");
 	        }
  }
  
  public boolean sendMessage(String mobile,String text){
  this.mobile = mobile;
  this.text = text;
  boolean successed = false;
  //判断是否与设备连接,如果否,重新建立连接
  if (!gsmmodem1.GSMModemIsConn()) {
          if (!gsmmodem1.GSMModemInit()) {
            System.out.println(gsmmodem1.GSMModemGetErrorMsg());
            initGsm();
          }
        }else{
        	logger.info("与短信猫连接,成功!");
        }
  
  successed = gsmmodem1.GSMModemSMSsend(null, gsmmodem1.ENCodeing_GB2312, text, mobile, false);
  if (successed)
  logger.info(" 本条短信发送成功!");
        else
          logger.info(" 本条短信发送失败!");
  return successed;
  }
  
  /**
   * @author Administrator
   * 读取设备中的短信
   * @return
   */
  public List loadMessage(){
  
  //判断是否与设备连接,如果否,重新建立连接
  if (!gsmmodem1.GSMModemIsConn()) {
          if (!gsmmodem1.GSMModemInit()) {
            System.out.println(gsmmodem1.GSMModemGetErrorMsg());
            initGsm();
          }
        }
  
      logger.info(" 正在接收短信,请稍后... ...");
      java.util.Vector allmsg = gsmmodem1.GSMModemSMSReadAll(gsmmodem1.ReadSMS_ALL_DELETE);
      List<GSMMessage> listMessage = new ArrayList();
      for(int i=0; i<allmsg.size();i++){
        GSMMessage gsmmsg1 = (GSMMessage) allmsg.elementAt(i);
        listMessage.add(gsmmsg1);
       
      }
  return listMessage;
  }
  /**
   * @author Administrator
   * 释放与短信猫的连接
   *
   */
  public void release(){
  gsmmodem1.GSMModemRelease();
  logger.info(" 与短信猫断开连接");
  }
  
  public static void main(String[] args){
  GsmService gsm = new GsmService();
  gsm.sendMessage("10086", "113");
  gsm.loadMessage();
  }
}
===============================================================================================
package tonsoft;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;

import model.BoxsendingModel;
import service.DataBaseService;
import service.GsmService;
import GSMModem.GSMMessage;

public class SmsProducer implements Runnable{
private Controler controler;
List<String[]> listArray = new ArrayList();  //存储数据库查询得到的结果集
//List<BoxsendingModel> listModel = new ArrayList();  //存储model
public SmsProducer(Controler c){controler = c;}  //注册到控制器controler

private static Logger logger = Logger.getLogger(GsmService.class);

int num = 23;  //需要查询的表结构的列数目
public void run(){
  try {
while(!Thread.interrupted()){
//锁住短信生产者本身,如果还有没有处理好的信息,则一直等待,直到唤醒 
synchronized(this){
 if(controler.listModel.size() > 0)
 wait();
  }

  //锁住发送机,生产者生产完毕后将其唤醒
  synchronized(controler.smsSender){
  DataBaseService dbsProducer = new DataBaseService();  //连接数据库初始化
  String sql = "select * from sms_boxsending where ifreceipt = 0 and retrytimes < 3";  //需要执行的查询语句
  listArray = dbsProducer.selectSql(sql, num);
  for(int i = 0; i <  listArray.size();i++){
  String[] s = listArray.get(i);
  BoxsendingModel bm = new BoxsendingModel();
  bm.setId(Integer.valueOf(s[0]));
  bm.setAppid(s[1]);
  bm.setSender(s[2]);
  bm.setReceiver(s[3]);
  bm.setContent(s[4]);
  bm.setRetrytimes(s[7]);
  controler.listModel.add(bm);
  }
  //如果生产了短消息,那么关闭数据库连接,唤醒发送机进行发送
  if(controler.listModel.size()>0){
  if(dbsProducer != null)
  dbsProducer.close();
  controler.smsSender.notifyAll();
  }else if(controler.listModel.size() == 0){//如果生产不出产不出短消息,说明没有原料了(数据库里没有待发送消息),则休息10分钟
  GsmService gs = new GsmService();
  GSMMessage gsmmsg1 = null;
  List<GSMMessage> list  =  gs.loadMessage();
  
  if(list.size() != 0){
  for(int i=0;i<list.size();i++){
    gsmmsg1 = list.get(i);
    String sql1 = "Insert into sms_boxreceived (sender,content,inserttime,readed) Values ("+
    "'"+gsmmsg1.getNumber()+"','"+gsmmsg1.getContent()+"','"+gsmmsg1.getSendTime()+"','0')";
    
    dbsProducer.insertSql(sql1);
  } 
  String info = "共接收了 "+list.size()+" 条短信息";
  logger.info(info);
  }
  if(dbsProducer != null)
  dbsProducer.close();
  TimeUnit.MILLISECONDS.sleep(30000);
  }
 
  }
 
  }
} catch (InterruptedException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
}

}

===============================================================================================

package tonsoft;

import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;

import model.BoxsendingModel;
import service.DataBaseService;
import service.GsmService;

public class SmsSender implements Runnable{
  private Controler controler;
  BoxsendingModel bm;
  String mobile = null;
  String text = null;
  public SmsSender(Controler c){controler = c;}
  private static Logger logger = Logger.getLogger(GsmService.class);
  public void run(){
  try {
while(!Thread.interrupted()){
//锁住发送机自己,如果没有消息,则一直等待。直到被唤醒
  synchronized(this){
  while(controler.listModel.size()<1){
  wait();
  }
  }
  //锁住生产者,开始发送信息
  synchronized(controler.smsProducer){
  DataBaseService dbs = new DataBaseService();
  GsmService gsm = new GsmService();
  String info = "有"+controler.listModel.size()+"条消息等待发送";
  logger.info(info);
  for(int i=0;i<controler.listModel.size();i++){
  bm = controler.listModel.get(i);
  mobile = bm.getReceiver();
  text = bm.getContent();
  String sql = "UPDATE sms_boxsending SET ifreceipt = '1' WHERE id ="+bm.getId();
  String sql1 ="UPDATE sms_boxsending SET retrytimes = '"+(Integer.valueOf(bm.getRetrytimes())+1)+ "' WHERE  id ="+bm.getId();
  dbs.updateSql(sql1);
  bm.setRetrytimes(String.valueOf(Integer.valueOf(bm.getRetrytimes())+1));
  if(gsm.sendMessage(mobile, text)){  
  dbs.updateSql(sql);
  }
  if(controler.listModel.size() >0){
  controler.listModel.remove(i);
  }
  TimeUnit.MILLISECONDS.sleep(1000);
  }
  if(controler.listModel.size()<1){
  gsm.release();
  if(dbs != null)
  dbs.close();
  }
  controler.smsProducer.notifyAll();
  }
  }
} catch (InterruptedException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
  }
  
}
===============================================================================================
package tonsoft;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import model.BoxsendingModel;

public class Controler {
List<BoxsendingModel> listModel = new ArrayList();  //存储model 
SmsProducer smsProducer = new SmsProducer(this);
SmsSender smsSender = new SmsSender(this);
ExecutorService exec = Executors.newCachedThreadPool();

public Controler(){
  exec.execute(smsProducer);
  exec.execute(smsSender);
}

public static void main(String[] args){
             new Controler();	
}
}
===============================================================================================


关于数据库结构和model在此就不作阐述,再说明一点,里面用到了配置文件和日志记录功能。
改程序运行效果图如下:

经过多次修改,本程序比较稳定,连续运行几个月没出过任何问题,在多个项目中已经使用。

 

如果有感兴趣的朋友可以联系QQ:837981803