在这个项目中涉及到了短信和彩信等功能,这个算是一个项目重要组成部分,曾经想过这个功能怎么开发,例如在我们永和系统中有很多订单,可以给用户办理会员卡等业务如何让用户及时知道自己卡里的消费情况?如何让用户心中存在安全感,试想想在你的银行卡每次消费或者转入、转出每一笔款的时候都有短信提示,你是不是无意中增加了一份安全感呢?
大家在想想目前的各类门户网站,以及我们常用的CSDN等论坛都提供有短信登录、以及短信验证码、短信注册等等同短信沾边的业务内容,所有的这些都是一个思想提高系统灵活性、易用性、安全性,方便用户替用户考虑,全心全意为人民服务嘛,假如在项目中嵌入短信功能无疑增加了系统的信用等级,也是给我们的系统增加用户,学着处处替别人考虑才会使得自己受益,俗话说“利己者生,利人者恒”,意思是说做每件事情如果只是想到自己,对自己有利,那么你可以生活,但利别人会让自己长久受益。
开始说正文:我负责的这部分是封装第三方的接口,把这些接口需要的各种配置以及别的工具类等都写成jar文件,在我们项目中哪一部分用到了发送短信彩信等功能只需要引入我这个jar包就可以实现这些功能变的很方便。
反过来想想我们这个高校平台里面也是可以加入短信功能,学生信息中都有学生手机号,等考试的成绩出来了给学生发个信息就行了,这样岂不是变的很简单了,当然短信费需要让学生自己扣、这么多学生发信息也发不少。
项目经理给了我一个短信服务商给提供了一个短信API文档,里面是底层的各种方法从网站找了找这些文档从网上是可以搜到的,这块作者到是不难,重点放在了逻辑以及没有没什么bug上,因为是底层的东西需要非常谨慎,这些写好之后都是提供给项目中其他人使用和调用的不容出现一点问题,在写的时候我也是格外注意加了很多判断和空指针等处理。
设计思路;本着可靠、灵活为、别人使用方便为目的。
调用方式
WebService
服务器以及跨平台、跨语言的调用。
Https
这个项目中使用的是这种方式利用urlconnection对象实现两个服务器之间通信,感兴趣的可以查一查。
再说一下设计底层接口时候的经验以及注意事项:
1.短信服务器服务器地址可以配置
服务商的接口地址可能会变,开发测试一个接口系统上线后又是另一个接口,我们在开发时这个需要设计成可变不能写在代码里面,第一次设计我卸载了代码里面显这不灵活,其实不仅仅是这一点,无论大家在写什么如果是容易变、可能变的量都需要写在配置文件里面避免今后不必要的麻烦,以后维护方便不需要再改动代码。
2.同一个方法提供不同参数的接口
这一点已经体会到了在高校平台中,底层提供了各种接口仅仅是一个更新就提供了各种参数,几乎是更新操作都可以调用这个方法,这就是方便可用性,底层发部分是这样提供给别的,在生活中也是一样每个人都喜欢用简单的东西,太复杂了还的学习,要拿用户当猪来对待。
3.参数和返回值明确
越是底层越是严格,越是彰显益彰,不知道大家有没有兴趣研究过开源框架,比如struts、springmvc、hibernate等等,看看这些框架底层的方法是怎么写的,站在巨人的肩膀上才会学的快、站的高才能看的远,它们写的都是很详细例如参数,看名知意知道什么类型,当你参数输入不合法了都会有提示,这就是它们设计的好处,设想一下你自己写的方法在别人调用的时候,如果参数不合法你会提示别人啥信息吗?觉得至少现在不会呢,尤其是在多人合作开发中,如果你不做到这一点,我们的合作版机房系统、我们在合作中的项目,怎么合作?没有办法继续开发下去,只有你遇到了啥问题当面去找那个写接口、写方法的人当面解决当面问才能继续下去,这显然有点违背合作开发、违背面向OOP的思想。
4.当参数不合规范时,立即返回不可在往下面执行
底层方法调用频率可能是相当高的,不要造成内容不必要的浪费,当一个方法执行到中间每一个位置、突然遇到问题,需要立即将这个问题返回给调用方,不可再往下面执行,这也是底层编程的一个原则很多框架中也是这么做的,我们都学过处理异常的原则。
这个原理也是异常处理原则,当遇到异常切记处理并向向一级也就是调用该方法的部分抛出,有异常就需要处理,做的及时高效解决。
就像生活中,难免会遇到这样或那样的问题,你是选择让问题越积累越多还是及时处理,道理是相通的,问题积累多了只能是带来更多的麻烦,让小的问题变成大问题最后悔不好解决,有什么问题都需要在最初解决,我又想到了扁鹊治病,为什么说扁鹊非常有名那时原因为他可以把严重的大病治好,大家就都认为扁鹊医术非常高明。不知大家是否还知道比扁鹊医术还要高明的是谁?那时他的哥哥,他哥治病在初,在病还没有严重的时候就给别人治好了这才算是大智慧,将问题在变大之前解决,因此,我们遇到问题也许需要在最初解决、及时解决。
5.静态变量要当心
你是否真正懂得他的原理呢?如果一个方法使用了静态方法它的成员变量也是静态的变量,如果底层方法的成员变量有值就要格外小心了(工具函数除外),有一次在我测试的时候,我调用了好几遍底层方法,我纳闷为什么结果总是一样呢,仔细检查底层原来是静态方法惹的祸,它里面有一个静态成员变量,静态的是不可以修改的在以后调用的时候都是这一个值,使用静态的东西最后在没有成员变量或者成员变量不可变的时候再使用,否则会带来不必要的麻烦。
上面都是在写接口时候需要注意的一点问题,看一下一个发送短信接口
<span style="font-size:14px;"> /** * @author lilongsheng * @deprecated 发送短信方法,可以定时发送 * @param map CorpID: 账号, * Pwd: 密码, * Mobile: 联系人手机 , * Content: 发送内容, * Cell: 子号,可以为空 * SendTime:定时发送时间, 比如:20060912152435代表2006年9月12日15时24分35秒 * 为空,表示立即发送 * * @return 结果字符串 */ public String send(String userURL, String CorpID, String Pwd, String Mobile,String Content, String Cell, String SendTime) { //函数返回默认值 String result="短信发送失败"; //短信内容大小 if (!isEmpty(prosURL.getProperty("contentSize"))) { contentSize=Integer.parseInt(prosURL.getProperty("contentSize")); } //判断用户是否提供了URL地址 if ("".equals(userURL) || null==userURL) { userURL=prosURL.getProperty("SendURL"); } //存储参数信息 Map<String,Object> map=new HashMap<String, Object>(); //判断账号是否为空 if (!isEmpty(CorpID)) { map.put("CorpID",CorpID); }else { return result="账号不能为空"; } //判断密码是否为空 if (!isEmpty(Pwd)) { map.put("Pwd",Pwd); }else { return result="密码不能为空"; } //判断手机格式是否正确 if (!isEmpty(Mobile) && checkMobile(Mobile)) { map.put("Mobile",Mobile); }else { return result="发送手机号码为空或格式不正确"; } //判断短信内容是否为空、大小是否合适 if (!isEmpty(Content) && Content.length()< contentSize) { map.put("Content",Content); }else { return result="发送内容为空或内容太长"; } //子号可以为空 if (!isEmpty(Cell)) { map.put("Cell",Cell); } //发送时间可以为空 if (!isEmpty(SendTime)) { map.put("SendTime",SendTime); } try { //String strReg=""; //调用底层接口发送短信 //将参数拼到url地址后面 String url_str=getUserURL(userURL, map); System.out.println("url_str="+url_str); String strReg=sendgetinfo(url_str); System.out.println("strResult="+strReg); if (!isEmpty(strReg)) { //根据底层返回值,返回相应结果 if ("0".equals(strReg)) { return result="发送成功"; } if ("-1".equals(strReg)) { return result="账号未注册"; } if ("-2".equals(strReg)) { return result="其它错误"; } if ("-3".equals(strReg)) { return result="密码错误"; } if ("-4".equals(strReg)) { return result="手机号格式不对"; } if ("-5".equals(strReg)) { return result="余额不足"; } if ("-6".equals(strReg)) { return result="定时发送时间不是有效的时间格式"; } if ("-7".equals(strReg)) { return result="禁止10小时以内向同一手机号发送相同短信"; } if ("-100".equals(strReg)) { return result="限制此IP访问"; } if ("-101".equals(strReg)) { return result="调用接口速度太快"; } } } catch (Exception e) { e.printStackTrace(); } return result; }</span>封装的公共方法
<span style="font-size:14px;"> /** * @author lilongsheng * @param userURL * @param maps * @return */ private String getUserURL(String userURL,Map<String, Object> maps) { //取得map中的参数,并拼接成URL参数 StringBuilder sb = new StringBuilder(); sb.append(userURL); Set<String> keys = maps.keySet(); for (final String key : keys) { Object value = maps.get(key); //判断参数是否为空 if (!"".equals(value) && null!=value) { sb.append(key); // 不能包含特殊字符 sb.append('='); sb.append(value); sb.append('&'); } } sb.deleteCharAt(sb.length() - 1); return sb.toString(); }</span>
<span style="font-size:14px;"> /** * @author lilongsheng * @param url_str 发送接口 * @return * @throws Exception */ private String sendgetinfo(String url_str)throws Exception{ System.out.println(url_str); URL url =new URL(url_str); URLConnection connection=url.openConnection(); byte[] buf=new byte[1024*4]; ByteArrayOutputStream bos =new ByteArrayOutputStream (); int n; while((n=connection.getInputStream().read(buf))>=0) bos.write(buf,0,n); return bos.toString("gbk"); } </span>这是一个简单的发动短信的接口,另外还有彩信等等,彩信格式为TMS、MMS等还需彩信开发包。
短信、彩信开发并不算难,其实挺简单的也是用别人的类库,在开发中需要一边开发一边学习,难免会遇到自己不会的,只要拿过来好好看看、查查资料、看看别人的理解以及现有的资料都可以解决,另外刚去了时由于对于系统还是没有真正写过代码,写的不是很严谨,最近经理看了看我写的代码说比以前写的好多了,改进了很多,这一点还是有点满意的,写代码重要的是设计思路和灵活性、严谨性。