买了金仓短信猫,由于中间件需要加钱,故自己用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
/*======哎呦喂: http://www.aiiuui.com ======有人问,这个域名怎么记住呢??汉语拼音韵母学过吗??《ai--哎 |||||| iu--呦 |||||| ui--喂》,会了吗??*/