用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系统可以用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
- smslib-3.5.1.jar
- 短信 modem驱动:PL2303_Prolific_DriverInstaller_v130.zip
本次测试的环境是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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
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()); } } } |
本机运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
串口: 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
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()); } } } } } } |
运行结果如下:
1 2 3 4 5 6 |
GSM Modem 串行端口连接测试开始... 找到串口: COM24 Trying at 9600... 正在检测设备: 发现设备: AT+CGMM MULTIBAND 900E 1800 Trying at 19200... 发现设备失败,沒有接收到响应结果! Trying at 57600... 发现设备失败,沒有接收到响应结果! Trying at 115200... 发现设备失败,沒有接收到响应结果! |
【四】、测试收发短信:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
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("-----------"); } } |
发送短信亲测,手机能正常接收显示。读取设备的短信程序运行结果结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
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 ----------- |
原创文章,转载请注明: 转载自micmiu – 软件开发+生活点滴[ http://www.micmiu.com/ ]
你用这个代码有第二次运行么?
没太理解什么叫第二次运行?