关于java后台接入百度地图返回参数为{"status":211,"message":"APP SN校验失败"}的解决方法
1.关于百度地图,天气预报,微信公众平台等一系列权威机构java接入的认识:
a.首先要认识到的是这些信息都属于外部接口,我们在进行接入的时候一定要注意到这些接口的参数设置,稍微一不留神就会出现接入失败的问题,而这些问题往往是我们不够认真导致的,所以,接入的时候一定要充分阅读官方的文档和示例。
b.这类的官方平台我们要接入都需要注册账号,注册之后需要在平台上进行设置,按照自己的习惯问题一一去设置该设置的参数,然后再去做自己的开发。
c.建议接入之前最好进行简单的接口调用测试,把这些参数都搞清楚再去布局代码。
2.项目需求:最近接到一个项目是工单系统,其中有一项内容是需要用到签到定位功能的,这时候就需要用到地图接口了,我选择了百度地图,当然做的时候最好和前台商量着来,前台最好也去调用百度的地图接口。但是自己做的时候就是出现了上述问题,报错APP SN校验失败,关于这个问题我发帖子和上百度搜索都无果,索性自己研究,最后发现是参数问题,我把ak的值放到了sk的位置,导致去调用接口的时候报错,就下面这一句:
3.最后附上完整的测试代码(也是官方的代码)
1 //演示get、post请求如何算sn,算得sn如何使用 2 import java.io.ByteArrayOutputStream; 3 import java.io.InputStream; 4 import java.io.UnsupportedEncodingException; 5 import java.net.URLEncoder; 6 import java.util.ArrayList; 7 import java.util.LinkedHashMap; 8 import java.util.List; 9 import java.util.Map; 10 import java.util.Map.Entry; 11 import java.util.TreeMap; 12 13 //需要httpclient-x.x.jar,httpcore-x.x.jar,commons-logging-x.x.jar,commons-httpclient-x.x.jar,commons-codec-x.x.jar包发http请求 14 import org.apache.commons.httpclient.URIException; 15 import org.apache.commons.httpclient.util.URIUtil; 16 import org.apache.http.HttpEntity; 17 import org.apache.http.HttpResponse; 18 import org.apache.http.NameValuePair; 19 import org.apache.http.client.HttpClient; 20 import org.apache.http.client.entity.UrlEncodedFormEntity; 21 import org.apache.http.client.methods.HttpGet; 22 import org.apache.http.client.methods.HttpPost; 23 import org.apache.http.impl.client.DefaultHttpClient; 24 import org.apache.http.message.BasicNameValuePair; 25 26 @SuppressWarnings("deprecation") 27 public class test02 { 28 public static void main(String[] args) throws Exception { 29 test02 test02 = new test02(); 30 test02.testGet(); 31 test02.testPost(); 32 } 33 34 @SuppressWarnings("all") 35 public void testGet() throws Exception { 36 /** 37 * 以http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=yourak为例 38 * ak设置了sn校验不能直接使用必须在url最后附上sn值,get请求计算sn跟url中参数对出现顺序有关,需按序填充paramsMap, 39 * post请求是按字母序填充,具体参照testPost() 40 */ 41 Map paramsMap = new LinkedHashMap<String, String>(); 42 paramsMap.put("address", "百度大厦"); 43 paramsMap.put("output", "json"); 44 paramsMap.put("ak", "XWnIC5k1cguL71ClpinbhmozUsBWY4Xr"); 45 46 // 调用下面的toQueryString方法,对paramsMap内所有value作utf8编码 47 String paramsStr = toQueryString(paramsMap); 48 49 // 对paramsStr前面拼接上/geocoder/v2/?,后面直接拼接yoursk 50 String wholeStr = new String("/geocoder/v2/?" + paramsStr + "rbCHDhb9fARPyxGVDhLSifx7IO4vWk"); 51 52 // 对上面wholeStr再作utf8编码 53 String tempStr = URLEncoder.encode(wholeStr, "UTF-8"); 54 55 // 调用下面的MD5方法得到sn签名值d 56 String sn = MD5(tempStr); 57 58 // 算得sn后发送get请求 59 HttpClient client = new DefaultHttpClient(); 60 HttpGet httpget = new HttpGet( "http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=XWnIC5k1cguL71ClpinbhmozUsBWY4Xr&sn=" + sn); 61 HttpResponse response = client.execute(httpget); 62 InputStream is = response.getEntity().getContent(); 63 String result = inStream2String(is); 64 // 打印响应内容 65 System.out.println(result); 66 } 67 68 public void testPost() throws Exception { 69 /** 70 * 以http://api.map.baidu.com/geodata/v3/geotable/create创建表为例 71 */ 72 LinkedHashMap<String, String> paramsMap = new LinkedHashMap<String, String>(); 73 paramsMap.put("geotype", "1"); 74 paramsMap.put("ak", "yourak"); 75 paramsMap.put("name", "geotable80"); 76 paramsMap.put("is_published", "1"); 77 78 // post请求是按字母序填充,对上面的paramsMap按key的字母序排列 79 Map<String, String> treeMap = new TreeMap<String, String>(paramsMap); 80 String paramsStr = toQueryString(treeMap); 81 82 String wholeStr = new String("/geodata/v3/geotable/create?" + paramsStr 83 + "yoursk"); 84 String tempStr = URLEncoder.encode(wholeStr, "UTF-8"); 85 // 调用下面的MD5方法得到sn签名值 86 String sn = MD5(tempStr); 87 88 HttpClient client = new DefaultHttpClient(); 89 HttpPost post = new HttpPost( 90 "http://api.map.baidu.com/geodata/v3/geotable/create"); 91 List<NameValuePair> params = new ArrayList<NameValuePair>(); 92 params.add(new BasicNameValuePair("geotype", "1")); 93 params.add(new BasicNameValuePair("ak", "yourak")); 94 params.add(new BasicNameValuePair("name", "geotable80")); 95 params.add(new BasicNameValuePair("is_published", "1")); 96 params.add(new BasicNameValuePair("sn", sn)); 97 HttpEntity formEntity = new UrlEncodedFormEntity(params); 98 post.setEntity(formEntity); 99 HttpResponse response = client.execute(post); 100 InputStream is = response.getEntity().getContent(); 101 String result = inStream2String(is); 102 // 打印响应内容 103 System.out.println(result); 104 } 105 106 // 对Map内所有value作utf8编码,拼接返回结果 107 public String toQueryString(Map<?, ?> data) 108 throws UnsupportedEncodingException, URIException { 109 StringBuffer queryString = new StringBuffer(); 110 for (Entry<?, ?> pair : data.entrySet()) { 111 queryString.append(pair.getKey() + "="); 112 // queryString.append(URLEncoder.encode((String) pair.getValue(), 113 // "UTF-8") + "&"); 114 queryString.append(URIUtil.encodeQuery((String) pair.getValue(), 115 "UTF-8") + "&"); 116 } 117 if (queryString.length() > 0) { 118 queryString.deleteCharAt(queryString.length() - 1); 119 } 120 return queryString.toString(); 121 } 122 123 // MD5计算方法,调用了MessageDigest库函数,并把byte数组结果转换成16进制 124 public String MD5(String md5) { 125 try { 126 java.security.MessageDigest md = java.security.MessageDigest 127 .getInstance("MD5"); 128 byte[] array = md.digest(md5.getBytes()); 129 StringBuffer sb = new StringBuffer(); 130 for (int i = 0; i < array.length; ++i) { 131 sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100) 132 .substring(1, 3)); 133 } 134 return sb.toString(); 135 } catch (java.security.NoSuchAlgorithmException e) { 136 } 137 return null; 138 } 139 140 // 将输入流转换成字符串 141 private static String inStream2String(InputStream is) throws Exception { 142 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 143 byte[] buf = new byte[1024]; 144 int len = -1; 145 while ((len = is.read(buf)) != -1) { 146 baos.write(buf, 0, len); 147 } 148 return new String(baos.toByteArray(), "UTF-8"); 149 } 150 }
4.总结:总之,我们在调用平台的接口时,一定要注意参数问题,不可再不知道参数的情况下胡乱的粘贴复制,这样就很难保证代码的成功率了。