blog迁移至:
http://www.micmiu.com
用java实现短信收发的功能,目前一般项目中短信群发功能的实现方法大致有下面三种:
- 1、 向运行商申请短信网关,不需要额外的设备,利用运行商提供的API调用程序发送短信,适用于大型的通信公司。
- 2、 借助像GSM MODEM之类的设备(支持AT指令的手机也行),通过数据线连接电脑来发送短信,这种方法比较适用于小公司及个人。要实现这种方式必须理解串口通信、AT指令、短信编码、解码。
- 3、 借助第三方运行的网站实现,由网站代发短信数据,这种方法对网站依赖性太高,对网络的要求也比较高。
鉴于项目的情况和多方考虑,同时又找到了一个开源的SMSLib项目的支持,比较倾向于第二种方法,SMSLib的出现就不需要我们自己去写底层的AT指令,这样就可以直接通过调用SMSLib的API来实现通过GSM modem来收发送短信了。
SMSLib官方网站:http://smslib.org/,使用SMSLib的一些基本要点:
- SUN JDK 1.6 or newer. (Java环境)
- Java Communications Library. (Java串口通信)
- Apache ANT for building the sources. (编译源码时需要的)
- Apache log4j. (日志工具)
- Apache Jakarta Commons - NET. (网络操作相关的)
- JSMPP Library (SMPP协议时需要的)
有关Java串口通信需要补充说明:
附件提供相关下载:
本次测试的环境是window,GSM modem是wavecom,所以这次主要描述window环境下简单的实现过程:
【一】、配置相应的环境
首先解压下载的Java Comm v2文件javacomm20-win32.zip,具体配置步骤如下:
- 把文件:comm.jar copy 到目录:<JDKDIR>/jre/lib/ext/,当然这一步也可以不要这样做,你只需把comm.jar copy到所要运行的项目对应的lib/下既可
- 把文件:javax.comm.properties copy 到目录:<JDKDIR>/jre/lib/
- 把DLL文件:win32com.dll(windows) copy 到目录:<JDKDIR>/jre/bin/
- 如果存在JRE目录, 最好按照上面步骤把文件copy到<JREDIR>相应的目录下
【二】、测试串口端口程序:
TestGetPortList.java
package michael.comm.serial;
import java.util.Enumeration;
import javax.comm.CommDriver;
import javax.comm.CommPortIdentifier;
import javax.comm.SerialPort;
/**
* @author michael
*
*/
public class TestGetPortList {
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// 人工加载驱动
// MainTest.driverInit();
TestGetPortList.getCommPortList();
// 人工加载驱动获取端口列表
// TestGetPortList.getPortByDriver();
}
/**
* 手工加载驱动<br>
* 正常情况下程序会自动加载驱动,故通常不需要人工加载<br>
* 每重复加载一次,会把端口重复注册,CommPortIdentifier.getPortIdentifiers()获取的端口就会重复
*/
public static void driverManualInit() {
String driverName = "com.sun.comm.Win32Driver";
String libname = "win32com";
CommDriver commDriver = null;
try {
System.loadLibrary("win32com");
System.out.println(libname + " Library Loaded");
commDriver = (javax.comm.CommDriver) Class.forName(driverName)
.newInstance();
commDriver.initialize();
System.out.println("comm Driver Initialized");
} catch (Exception e) {
System.err.println(e);
}
}
/**
* 获取端口列表
*/
public static void getCommPortList() {
CommPortIdentifier portId;
Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
while (portEnum.hasMoreElements()) {
portId = (CommPortIdentifier) portEnum.nextElement();
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
System.out.println("串口: name-" + portId.getName()
+ " 是否占用-" + portId.isCurrentlyOwned());
} else {
System.out.println("并口: name-" + portId.getName()
+ " 是否占用-" + portId.isCurrentlyOwned());
}
}
System.out.println("-------------------------------------");
}
/**
*
*/
public static void getPortByDriver() {
String driverName = "com.sun.comm.Win32Driver";
String libname = "win32com";
CommDriver commDriver = null;
try {
System.loadLibrary("win32com");
System.out.println(libname + " Library Loaded");
commDriver = (CommDriver) Class.forName(driverName).newInstance();
commDriver.initialize();
System.out.println("comm Driver Initialized");
} catch (Exception e) {
System.err.println(e);
}
SerialPort sPort = null;
try {
sPort = (SerialPort) commDriver.getCommPort("COM24",
CommPortIdentifier.PORT_SERIAL);
System.out.println("find CommPort:" + sPort.toString());
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
本机运行结果:
引用
串口: name-COM10 是否占用-false
串口: name-COM21 是否占用-false
串口: name-COM23 是否占用-false
串口: name-COM20 是否占用-false
串口: name-COM22 是否占用-false
串口: name-COM24 是否占用-false
串口: name-COM9 是否占用-false
串口: name-COM19 是否占用-false
串口: name-COM3 是否占用-false
串口: name-COM8 是否占用-false
串口: name-COM98 是否占用-false
串口: name-COM99 是否占用-false
串口: name-COM4 是否占用-false
串口: name-COM5 是否占用-false
串口: name-COM6 是否占用-false
并口: name-LPT1 是否占用-false
并口: name-LPT2 是否占用-false
-------------------------------------
【三】、检查串口设备信息:
TestCommPort.java
package michael.comm.serial;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import javax.comm.CommPortIdentifier;
import javax.comm.SerialPort;
/**
* @author michael
*
*/
public class TestCommPort {
static CommPortIdentifier portId;
static Enumeration portList;
static int bauds[] = { 9600, 19200, 57600, 115200 };
/**
* @param args
*/
public static void main(String[] args) {
portList = CommPortIdentifier.getPortIdentifiers();
System.out.println("GSM Modem 串行端口连接测试开始...");
String portName = "COM24";
while (portList.hasMoreElements()) {
portId = (CommPortIdentifier) portList.nextElement();
if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL
&& portName.equals(portId.getName())) {
System.out.println("找到串口: " + portId.getName());
for (int i = 0; i < bauds.length; i++) {
System.out.print(" Trying at " + bauds[i] + "...");
try {
SerialPort serialPort;
InputStream inStream;
OutputStream outStream;
int c;
StringBuffer response = new StringBuffer();
serialPort = (SerialPort) portId.open(
"SMSLibCommTester", 2000);
serialPort
.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN);
serialPort.setSerialPortParams(bauds[i],
SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
inStream = serialPort.getInputStream();
outStream = serialPort.getOutputStream();
serialPort.enableReceiveTimeout(1000);
c = inStream.read();
while (c != -1) {
c = inStream.read();
}
outStream.write('A');
outStream.write('T');
outStream.write('\r');
try {
Thread.sleep(1000);
} catch (Exception e) {
}
c = inStream.read();
while (c != -1) {
response.append((char) c);
c = inStream.read();
}
if (response.indexOf("OK") >= 0) {
System.out.print(" 正在检测设备:");
try {
outStream.write('A');
outStream.write('T');
outStream.write('+');
outStream.write('C');
outStream.write('G');
outStream.write('M');
outStream.write('M');
outStream.write('\r');
response = new StringBuffer();
c = inStream.read();
while (c != -1) {
response.append((char) c);
c = inStream.read();
}
System.out.println(" 发现设备: "
+ response.toString().replaceAll(
"(\\s+OK\\s+)|[\n\r]", ""));
} catch (Exception e) {
System.out.println(" 检测设备失败,获取设备信息异常:"
+ e.getMessage());
}
} else {
System.out.println(" 检测设备失败,沒有接收到响应结果!");
}
serialPort.close();
} catch (Exception e) {
System.out.println(" 检测设备失败,发生异常:" + e.getMessage());
}
}
}
}
}
}
运行结果如下:
引用
GSM Modem 串行端口连接测试开始...
找到串口: COM24
Trying at 9600... 正在检测设备: 发现设备: AT+CGMM MULTIBAND 900E 1800
Trying at 19200... 发现设备失败,沒有接收到响应结果!
Trying at 57600... 发现设备失败,沒有接收到响应结果!
Trying at 115200... 发现设备失败,沒有接收到响应结果!
【四】、测试收发短信:
package michael.sms;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.smslib.AGateway;
import org.smslib.GatewayException;
import org.smslib.InboundMessage;
import org.smslib.OutboundMessage;
import org.smslib.Service;
import org.smslib.AGateway.Protocols;
import org.smslib.Message.MessageEncodings;
import org.smslib.modem.SerialModemGateway;
/**
* @author michael
*
*/
public class SmsHandler {
private static final Logger logger = Logger.getLogger(SmsHandler.class);
private Service smsService;
/**
*
*/
public SmsHandler() {
smsService = Service.getInstance();
List<AGateway> agatewayList = new ArrayList<AGateway>();
String portName = "COM24";//"/dev/ttyUSB0";// COM24
SerialModemGateway gateway = new SerialModemGateway(
"modem." + portName, portName, 9600, "wavecom", "PL2303");
gateway.setInbound(true);
gateway.setOutbound(true);
gateway.setProtocol(Protocols.PDU);
gateway.setSimPin("0000");
agatewayList.add(gateway);
try {
for (AGateway gatewayTmp : agatewayList) {
smsService.addGateway(gatewayTmp);
}
} catch (GatewayException ex) {
logger.error(ex.getMessage());
}
}
/**
*
*/
public void start() {
logger.info("SMS service start.....");
try {
smsService.startService();
} catch (Exception ex) {
logger.error("SMS service start error:", ex);
}
}
/**
*
*/
public void destroy() {
try {
smsService.stopService();
} catch (Exception ex) {
logger.error("SMS service stop error:", ex);
}
logger.info("SMS service stop");
}
/**
* send SMS
* @param msg
* @return Boolean
*/
public Boolean sendSMS(OutboundMessage msg) {
try {
msg.setEncoding(MessageEncodings.ENCUCS2);
return smsService.sendMessage(msg);
} catch (Exception e) {
logger.error("send error:", e);
}
return false;
}
private boolean isStarted() {
if (smsService.getServiceStatus() == Service.ServiceStatus.STARTED) {
for (AGateway gateway : smsService.getGateways()) {
if (gateway.getStatus() == AGateway.GatewayStatuses.STARTED) {
return true;
}
}
}
return false;
}
/**
* read SMS
* @return List
*/
public List<InboundMessage> readSMS() {
List<InboundMessage> msgList = new LinkedList<InboundMessage>();
if (!isStarted()) {
return msgList;
}
try {
this.smsService.readMessages(msgList,
InboundMessage.MessageClasses.ALL);
logger.info("read SMS size: " + msgList.size());
} catch (Exception e) {
logger.error("read error:", e);
}
return msgList;
}
/**
* @param args
*/
public static void main(String[] args) {
Logger.getRootLogger().setLevel(Level.INFO);
OutboundMessage outMsg = new OutboundMessage("189xxxx****", "信息测试");
SmsHandler smsHandler = new SmsHandler();
smsHandler.start();
//发送短信
smsHandler.sendSMS(outMsg);
//读取短信
List<InboundMessage> readList = smsHandler.readSMS();
for (InboundMessage in : readList) {
System.out.println("发信人:" + in.getOriginator() + " 短信内容:"
+ in.getText());
}
smsHandler.destroy();
System.out.println("-----------");
}
}
发送短信亲测,手机能正常接收显示。读取设备的短信程序运行结果结果如下:
引用
INFO - Service.listSystemInformation(113) | SMSLib: A Java API library for sending and receiving SMS via a GSM modem or other supported gateways.
This software is distributed under the terms of the Apache v2.0 License.
Web Site: http://smslib.org
INFO - Service.listSystemInformation(114) | Version: 3.5.1
INFO - Service.listSystemInformation(115) | JRE Version: 1.6.0_18
INFO - Service.listSystemInformation(116) | JRE Impl Version: 16.0-b13
INFO - Service.listSystemInformation(117) | O/S: Windows Vista / x86 / 6.0
INFO - SmsHandler.start(55) | SMS service start.....
INFO - DefaultQueueManager.init(92) | Queue directory not defined. Queued messages will not be saved to filesystem.
INFO - ModemGateway.startGateway(188) | GTW: modem.COM24: Starting gateway, using Generic AT Handler.
INFO - SerialModemDriver.connectPort(68) | GTW: modem.COM24: Opening: COM24 @9600
INFO - AModemDriver.waitForNetworkRegistration(459) | GTW: modem.COM24: GSM: Registered to foreign network (roaming).
INFO - AModemDriver.connect(175) | GTW: modem.COM24: MEM: Storage Locations Found: SMBM
INFO - CNMIDetector.getBestMatch(142) | CNMI: No best match, returning: 1
INFO - ModemGateway.startGateway(191) | GTW: modem.COM24: Gateway started.
INFO - SmsHandler.readSMS(113) | read SMS size: 1
发信人:8618918001030 短信内容:hello 回复测试
INFO - ModemGateway.stopGateway(197) | GTW: modem.COM24: Stopping gateway...
INFO - SerialModemDriver.disconnectPort(120) | GTW: modem.COM24: Closing: COM24 @9600
INFO - ModemGateway.stopGateway(201) | GTW: modem.COM24: Gateway stopped.
INFO - SmsHandler.destroy(72) | SMS service stop
-----------
-----------------------------------分 ------------------------------------隔 ------------------------------------线 --------------------------------------