因为客户需要,本身使用的 阿里云的短信服务改为了中国移动MAS HTTP 1.0 短信通知,因为看到网络上关于此类的博客知识很少,再趟完坑后特地写下这篇博客,提醒后来人。
特别感谢 中国移动MAS 客服 @左立,可能你看不到,非常感谢你 不厌其烦的回答!!
首先创建 接口,用户类型是HTTP
然后下载文档,下载签名:
这里简单说一下流程: HTTP 1.0 的通讯方式是,
1. 先向中国移动 发送 企业名、接口名、接口密码,实现登录操作。中国移动返回登录id 和密钥。
2. 携带中国移动返回的密钥和 所需要的信息进行第二次的 请求,此次请求就是发送短信的请求。
根据文档书写所需要的发送短信的工具类:
1 public class HttpSend { 2 private static String ec_name = "山东*****" ; // 企业名 3 private static String user_name = "***" ; // 接口账号 4 private static String user_passwd = "****" ; // 接口账号密码 5 private static String sign = "*****" ; //签名编号 6 private static String serial = "" ; // 扩展码 7 private static String checkUrl = "http://mas.ecloud.10086.cn/app/http/authorize" ; // 身份验证url 8 private static String sendUrl = "http://mas.ecloud.10086.cn/app/http/sendSms" ; // 发送信息的url 9 10 // 身份验证方法11 public static CheckRes check (){12 String req = "ec_name="+ec_name+"&user_name="+user_name+"&user_passwd="+user_passwd ;13 System.out.println("传入参数:"+req);14 HttpRequest httpRequest = new HttpRequest() ;15 String checkStr = httpRequest.sendPost(checkUrl,req) ; //返回验证信息的 回参16 System.out.println("验证身份结果:"+checkStr);17 CheckRes checkRes = JSONUtils.json2pojo(checkStr,CheckRes.class);18 String mas_user_id = checkRes.getMas_user_id() ;19 System.out.println("mas_user_id:"+mas_user_id);20 return checkRes ;21 }22 23 // 发送短信 方法,需要使用到 check()方法的 返回值 CheckRes24 public static Boolean send (CheckRes checkRes ,String mobiles ,String content){25 String temporary = checkRes.getMas_user_id() + mobiles + content + sign + serial + checkRes.getAccess_token() ; // 存放要进行加密的信息26 String mac = MD5Util.getMD5Up(temporary) ; //加密27 String sendReq = "mas_user_id="+checkRes.getMas_user_id()+"&mobiles="+mobiles+"&content="+content+"&sign="+sign+"&serial="+serial+"&mac="+mac;28 HttpRequest httpRequest = new HttpRequest() ;29 String sendStr = httpRequest.sendPost(sendUrl,sendReq) ; //发送 普通短信30 System.out.println("发送结果:"+sendStr);31 String[] test = sendStr.split(",",0); // 将字符串 按照 逗号分隔,取前面一段32 if (test[0].equals("{\"RET-CODE\":\"SC:0000\"")){ // 直接进行比较33 return true ;34 }else {35 return false ;36 }37 38 }39 40 // 测试 main函数41 public static void main(String[] args){42 CheckRes result = check() ;43 Boolean b =send(result,"15610446589","益羊铁路测试短信");44 if (b){45 System.out.println("成功");46 }else {47 System.out.println("失败");48 }49 }50 51 }
这里用到的工具 HttpRequest ,用于携带参数请求页面:
public class HttpRequest { /** * 向指定URL发送GET方法的请求 * * @param url * 发送请求的URL * @param param * 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 * @return URL 所代表远程资源的响应结果 */ public static String sendGet(String url, String param) { String result = ""; BufferedReader in = null; try { String urlNameString = url + "?" + param; URL realUrl = new URL(urlNameString); // 打开和URL之间的连接 URLConnection connection = realUrl.openConnection(); // 设置通用的请求属性 connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 建立实际的连接 connection.connect(); // 获取所有响应头字段 Map> map = connection.getHeaderFields(); // 遍历所有的响应头字段 for (String key : map.keySet()) { System.out.println(key + "--->" + map.get(key)); } // 定义 BufferedReader输入流来读取URL的响应 in = new BufferedReader(new InputStreamReader( connection.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("发送GET请求出现异常!" + e); e.printStackTrace(); } // 使用finally块来关闭输入流 finally { try { if (in != null) { in.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return result; } /** * 向指定 URL 发送POST方法的请求 * * @param url * 发送请求的 URL * @param param * 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 * @return 所代表远程资源的响应结果 */ public static String sendPost(String url, String param) { PrintWriter out = null; BufferedReader in = null; String result = ""; try { URL realUrl = new URL(url); // 打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); // 设置通用的请求属性// conn.setRequestProperty("accept", "*/*");// conn.setRequestProperty("connection", "Keep-Alive");// conn.setRequestProperty("user-agent",// "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 发送POST请求必须设置如下两行 conn.setDoOutput(true); conn.setDoInput(true); // 获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); // 发送请求参数 out.print(param); // flush输出流的缓冲 out.flush(); // 定义BufferedReader输入流来读取URL的响应 in = new BufferedReader( new InputStreamReader(conn.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("发送 POST 请求出现异常!"+e); e.printStackTrace(); } //使用finally块来关闭输出流、输入流 finally{ try{ if(out!=null){ out.close(); } if(in!=null){ in.close(); } } catch(IOException ex){ ex.printStackTrace(); } } return result; }}
JSONUtils工具:
public class JSONUtils { private final static ObjectMapper objectMapper = new ObjectMapper(); private static Logger log = LoggerFactory.getLogger(JSONUtils.class); private JSONUtils() { } public static ObjectMapper getInstance() { return objectMapper; } public static String obj2json(Object obj) { try { return objectMapper.writeValueAsString(obj); } catch (JsonProcessingException e) { // TODO Auto-generated catch block log.error(e.getMessage()); } return null; } public staticT json2pojo(String jsonStr, Class clazz) { try { return objectMapper.readValue(jsonStr, clazz); } catch (JsonParseException e) { // TODO Auto-generated catch block log.error(e.getMessage()); } catch (JsonMappingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } }
MD5工具,加密使用大写的 MD5加密方式
public class MD5Util { public static String getMD5(String value) { String s = null; char hexDigits[] = { // 用来将字节转换成 16 进制表示的字符 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; try { java.security.MessageDigest md = java.security.MessageDigest .getInstance("MD5"); md.update(value.getBytes()); // MD5 的计算结果是一个 128 位的长度整数, byte tmp[] = md.digest(); // 用字节表示就是 16 个字节 char str[] = new char[16 * 2]; // 每个字节用 16 进制表示的话,使用两个字符, // 所以表示成 16 进制需要 32 个字符 int k = 0; // 表示转换结果中对应的字符位置 for (int i = 0; i < 16; i++) { // 从第一个字节开始,对 MD5 的每一个字节 // 转换成 16 进制字符的转换 byte byte0 = tmp[i]; // 取第 i 个字节 str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字节中高 4 位的数字转换, // >>> 为逻辑右移(即无符号右移),将符号位一起右移 // 取字节中低 4 位的数字转换 str[k++] = hexDigits[byte0 & 0xf]; } s = new String(str); // 换后的结果转换为字符串 } catch (Exception e) { e.printStackTrace(); } return s; } // MD5大写 public static String getMD5Up(String value) { String s = null; char hexDigits[] = { // 用来将字节转换成 16 进制表示的字符 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; try { java.security.MessageDigest md = java.security.MessageDigest .getInstance("MD5"); md.update(value.getBytes()); // MD5 的计算结果是一个 128 位的长度整数, byte tmp[] = md.digest(); // 用字节表示就是 16 个字节 char str[] = new char[16 * 2]; // 每个字节用 16 进制表示的话,使用两个字符, // 所以表示成 16 进制需要 32 个字符 int k = 0; // 表示转换结果中对应的字符位置 for (int i = 0; i < 16; i++) { // 从第一个字节开始,对 MD5 的每一个字节 // 转换成 16 进制字符的转换 byte byte0 = tmp[i]; // 取第 i 个字节 str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字节中高 4 位的数字转换, // >>> 为逻辑右移(即无符号右移),将符号位一起右移 // 取字节中低 4 位的数字转换 str[k++] = hexDigits[byte0 & 0xf]; } s = new String(str); // 换后的结果转换为字符串 } catch (Exception e) { e.printStackTrace(); } return s; } /** * 判断字符串的md5校验码是否与一个已知的md5码相匹配 * * @param md5 要校验的字符串 * @param md5PwdStr 已知的md5校验码 */ public static boolean checkPassword(String md5, String md5PwdStr) { return md5.equals(md5PwdStr); }}
这里注意的是 ,这两次的请求都是 post 请求。
要注意拼接字符串以及加密的字符串 的顺序是不能乱的!!
最后再次感谢 @左立