因为客户需要,本身使用的 阿里云的短信服务改为了中国移动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()方法的 返回值 CheckRes 24 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<String, List<String>> 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 static <T> T json2pojo(String jsonStr, Class<T> 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 请求。
要注意拼接字符串以及加密的字符串 的顺序是不能乱的!!
最后再次感谢 @左立