买了金仓短信猫,由于中间件需要加钱,故自己用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--喂》,会了吗??*/
浙公网安备 33010602011771号