用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 CommunicationsLibrary. (Java串口通信)
· Apache ANT for building thesources. (编译源码时需要的)
· Apache log4j. (日志工具)
· Apache Jakarta Commons -NET. (网络操作相关的)
· JSMPP Library (SMPP协议时需要的)
有关Java串口通信需要补充说明:
· window系统可以用SUN Java Comm v2. (该版本好像也支持solaris)
其下载地址:http://smslib.googlecode.com/files/javacomm20-win32.zip
· 其他操作系统(比如:Linux, Unix, BSD,等等),你可以选择 Java Comm v3 或者是RxTx。
Java Comm v3下载地址:http://java.sun.com/products/javacomm/(需要注册);
RxTx官网:http://users.frii.com/jarvi/rxtx/index.html or http://rxtx.qbang.org/wiki/index.php/Main_Page
附件提供相关下载:
· java串口通信v2:javacomm20-win32.zip
· 短信modem驱动:PL2303_Prolific_DriverInstaller_v130.zip
本次测试的环境是window,GSM modem是wavecom,所以这次主要描述window环境下简单的实现过程:
【一】、配置相应的环境
首先解压下载的Java Comm v2文件javacomm20-win32.zip,具体配置步骤如下:
· 把文件:comm.jarcopy 到目录:JDKDIR/jre/lib/ext/,当然这一步也可以不要这样做,你只需把comm.jar copy到所要运行的项目对应的lib/下既可
· 把文件:javax.comm.propertiescopy 到目录:JDKDIR/jre/lib/
· 把DLL文件:win32com.dll(windows) copy 到目录:JDKDIR/jre/bin/
如果存在JRE目录, 最好安装上面步骤把文件copy到JREDIR相应的目录下
测试串口端口程序:
Test .java
Java代码
package test; import java.util.Enumeration; import javax.comm.CommDriver; import javax.comm.CommPortIdentifier; import javax.comm.SerialPort; public class Test { public static void main(String[] args) throws Exception { // 人工加载驱动 // MainTest.driverInit(); Test.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
Java代码
package test; import java.io.InputStream; import java.io.OutputStream; import java.util.Enumeration; import javax.comm.CommPortIdentifier; import javax.comm.SerialPort; 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 = "COM4"; 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", 1971); 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... 发现设备失败,沒有接收到响应结果!
【四】、测试收发短信:
Java代码
package test; 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.AGateway.Protocols; import org.smslib.GatewayException; import org.smslib.InboundMessage; import org.smslib.Message.MessageEncodings; import org.smslib.OutboundMessage; import org.smslib.Service; import org.smslib.modem.SerialModemGateway; public class SendSmsHandler { private static final Logger logger = Logger.getLogger(SendSmsHandler.class); private Service smsService; /** * 发送短信的类 */ public SendSmsHandler() { smsService = Service.getInstance(); //获得服务实例 单例模式的 List<AGateway> agatewayList = new ArrayList<AGateway>(); String portName = "COM4";//"/dev/ttyUSB0";// COM24 //使用的端口号 SerialModemGateway gateway = new SerialModemGateway( "modem." + portName, portName, 9600, "wavecom", "PL2303"); //通过端口号频率名称等内容获得设备实例 gateway.setInbound(true); gateway.setOutbound(true); gateway.setProtocol(Protocols.PDU); //发送凡是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("189*****", "信息测试"); //绑定接收电话号码和发送的消息 SendSmsHandler smsHandler = new SendSmsHandler(); 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
forsending 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. Queuedmessages 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 LocationsFound: SMBM
INFO - CNMIDetector.getBestMatch(142) | CNMI: No best match, returning: 1
INFO - ModemGateway.startGateway(191) | GTW: modem.COM24: Gatewaystarted.
INFO - SmsHandler.readSMS(113) | read SMS size: 1
发信人:8618918001030 短信内容:hello 回复测试
INFO - ModemGateway.stopGateway(197) | GTW: modem.COM24: Stoppinggateway...
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
-----------