Android - 服务器json数据交互.
一,服务器端
服务器端使用的是Servlet,封装json对象使用的 'json-lib-2.2.2-jdk15.jar,ezmorph-1.0.4.jar,commons-logging-1.1.jar,commons-lang-2.4.jar,commons-collections-3.2.jar,commons-beanutils-1.7.0.jar' 6个jar包.可在 json封装的jar包 中下载,我也不懂最近什么情况,使用Firefox总是很难下载csdn资源,可以使用ie.
1.首先是使用一个Person进行原始数据的封装:
package spt.src; public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person(String name, int age) { this.name = name; this.age = age; } }
2.然后是两个服务类PersonService和JsonService,分别提供Person对象和将Person对象转换为json格式的字符串的服务类.
package spt.service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import spt.src.Person; /** * 该类用于产生Person对象的服务类. * * @author Administrator 2015-1-29 */ public class PersonService { public Person getAPerson() { return new Person("莉莉", 21); } public List<Person> getListPersons() { List<Person> persons = new ArrayList<Person>(); persons.add(new Person("李静", 23)); persons.add(new Person("lucy", 20)); persons.add(new Person("小气", 22)); return persons; } /**获取 id-Person对应的Map列表. * @return */ public List<Map<String, Person>> getListMaps() { List<Map<String, Person>> maps = new ArrayList<Map<String,Person>>(); Map<String, Person> map01 = new HashMap<String, Person>(); map01.put("a01", new Person("王静", 19)); map01.put("a02", new Person("json", 26)); Map<String, Person> map02 = new HashMap<String, Person>(); map01.put("b01", new Person("okay", 19)); map01.put("b02", new Person("小琴", 24)); maps.add(map01); maps.add(map02); return maps; } }
package spt.service; import net.sf.json.JSONObject; /**将对象映射为json格式数据的服务类. * @author Administrator *2015-1-29 */ public class JsonService { public String getJsonStr(String key, Object value) { JSONObject jsonObject = new JSONObject(); jsonObject.put(key, value); return jsonObject.toString(); } }
3.HttpServlet的子类JsonServlet,用于响应客户端的Servlet的核心处理类.
package spt.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import spt.service.JsonService; import spt.service.PersonService; @WebServlet("/JsonAction") public class JsonServlet extends HttpServlet{ /** * */ private static final long serialVersionUID = 1L; @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //get person data. PersonService personService = new PersonService(); //change person as json. JsonService jsonService = new JsonService(); String action = req.getParameter("action"); String json = null; if("p".equalsIgnoreCase(action)) json = jsonService.getJsonStr("p", personService.getAPerson()); else if("plst".equalsIgnoreCase(action)) json = jsonService.getJsonStr("plst", personService.getListPersons()); else if("plstMap".equalsIgnoreCase(action)) json = jsonService.getJsonStr("plstMap", personService.getListMaps()); System.out.println(json); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); //Get的处理方式和POST的处理方式一样. } }
4.另外的一个类是处理不同响应的编码的统一类:
package spt.servlet.filter; import java.io.IOException; import java.io.UnsupportedEncodingException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; //filter all servlets. @WebFilter("/*") public class EncodingFilter implements Filter { public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpReq = (HttpServletRequest) servletRequest; //由于HttpServletRequest.setCharacterEncoding()对get方式不起作用,所以要单独编码. if ("GET".equals(httpReq.getMethod())) filterChain.doFilter(new HttpServletRequestEncodingWrapper(httpReq), servletResponse); else { //use utf encoding for none-get request. httpReq.setCharacterEncoding("utf-8"); filterChain.doFilter(httpReq, servletResponse); } } public void init(FilterConfig filterConfig) throws ServletException { } /**inner class dealing for 'GET' method. * @author Administrator *2015-1-27 */ private class HttpServletRequestEncodingWrapper extends HttpServletRequestWrapper { public HttpServletRequestEncodingWrapper(HttpServletRequest request) { super(request); } @Override public String getParameter(String name) { //encode with 'iso', and than decode with 'utf'. String val = super.getRequest().getParameter(name); if (null != val) { try { return new String(val.getBytes("iso8859-1"), "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } return super.getParameter(name); } } public void destroy() { } }
到此,服务器端已经基本完成,启动服务器后,可在浏览器中输入不同请求参数的url获取不同的json字符串,例如
http://192.168.1.101:8080/ReceiveAndroid/JsonAction?action=Plst
可获得
{"plst":[{"age":23,"name":"李静"},{"age":20,"name":"lucy"},{"age":22,"name":"小气"}]}
接触json数据不是很多,不过很奇怪的是,为什么获得Map列表的时候,我在调试的时候,获得的Map的size()是2,但是在使用url为:
http://192.168.1.101:8080/ReceiveAndroid/JsonAction?action=plstMap
的时候,获取的json字符串为:
{"plstMap":[{"b01":{"age":19,"name":"okay"},"a01":{"age":19,"name":"王静"},"a02":{"age":26,"name":"json"},"b02":{"age":24,"name":"小琴"}},{}]}
末尾有一个成员为空的'{}'.
二,接下来写Android客户端
1.首先,记得加 Internet permission.
2.Activity代码:
package spt.http.activity; import java.lang.ref.WeakReference; import spt.http.get.activity.R; import spt.http.post.PostSender; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity { //view. private EditText edt_param = null; private Button btn_ok = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initListener(); } /** * 初始化View. */ private void initView() { edt_param = (EditText)findViewById(R.id.edt_para); btn_ok = (Button)findViewById(R.id.btn_ok); //test: edt_param.setText("plstMap"); } /**使用静态内部类,解决'This Handler class should be static or leaks might occur',以免造成内存泄露. * @author Administrator * */ private static class StatusHandler extends Handler { WeakReference<MainActivity> iMainActivity = null; public StatusHandler(MainActivity mainActivity) { iMainActivity = new WeakReference<MainActivity>(mainActivity); } @Override public void handleMessage(Message msg) { switch (msg.what) { case PostSender.SEND_SUCCESS: //有iMainActivity.get()和iMainActivity.getClass(). Toast.makeText(iMainActivity.get(), "发送成功", Toast.LENGTH_SHORT).show(); break; case PostSender.SEND_FAIL: Toast.makeText(iMainActivity.get(), "发送失败", Toast.LENGTH_SHORT).show(); break; default: throw new RuntimeException("未知的发送结果!"); } } } /** * 处理发送是否成功的状态的Handler. */ private final Handler handler = new StatusHandler(this); /** * 初始化监听器. */ private void initListener() { //点击按钮,往服务器端发送数据. btn_ok.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { String name = edt_param.getText().toString(); if(name.isEmpty()) { Toast.makeText(MainActivity.this, "参数不能为空", Toast.LENGTH_SHORT).show(); return; } new PostSender(handler).send(name); } }); } }
3.使用Apache提供的HTTPClient进行POST请求的业务逻辑层类:
package spt.http.post; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.http.HttpResponse; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.json.JSONException; import spt.json.JsonParser; import spt.src.Person; import android.os.Handler; import android.util.Log; /** * 用户向服务器端发送数据的类(使用post)方法. * * @author Administrator * */ public class PostSender { // 连接服务器的url. private static final String URL = "http://192.168.1.101:8080/ReceiveAndroid/JsonAction"; // 标识是否连接到服务器成功. public static final int SEND_SUCCESS = 1; public static final int SEND_FAIL = 0; private Handler handler = null; //新线程关联的Handler,用于将是否发送成功的标识Message放到消息队列中. public PostSender(Handler handler) { this.handler = handler; } /** * 往服务器发送数据. * * @param param * @param pwd */ public void send(String param) { // 这里params要传递到另外一个方法,加final为了防止被修改. final Map<String, String> params = new HashMap<String, String>(); params.put("action", param); // 启动新的线程连接服务器. new Thread(new Runnable() { @Override public void run() { // 请求连接. try { if (postSend(params, URL, "utf-8")) handler.sendEmptyMessage(SEND_SUCCESS); else handler.sendEmptyMessage(SEND_FAIL); } catch (MalformedURLException e) { Log.d("sysout", "run:MalformedURLException" + e.getMessage()); } catch (IOException e) { Log.d("sysout", "run:IOException" + e.getMessage()); } } }).start(); } /** * 发送post请求的方法. * * @param params * 请求参数的键-值对. * @param url * @param encoding * 使用指定编码对参数值进行编码. * @return * @throws MalformedURLException * @throws IOException */ private boolean postSend(Map<String, String> params, String url, String encoding) throws MalformedURLException, IOException { // 封装请求参数的键值对. List<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>(); for (Entry<String, String> param : params.entrySet()) { pairs.add(new BasicNameValuePair(param.getKey(), param.getValue())); } //封装请求参数的实体. UrlEncodedFormEntity entity = new UrlEncodedFormEntity(pairs, encoding); //使用post请求. HttpPost post = new HttpPost(url); post.setEntity(entity); //使用DefaultHttpClient指定请求,以获取响应信息. DefaultHttpClient client = new DefaultHttpClient(); HttpResponse response = client.execute(post); BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "utf-8")); String ln = null; while((ln = reader.readLine()) != null) { // Log.d("sysout", ln); try { List<Map<String, Person>> maps = JsonParser.getListPersonMap("plstMap", ln); for (Map<String, Person> map : maps) { for (Entry<String, Person> en : map.entrySet()) { Person p = en.getValue(); Log.d("sysout", "k:" + en.getKey() + "->" + p.getName() + "," + p.getAge()); } } } catch (JSONException e) { Log.d("sysout", "postSend::readLine:JSONException" + e.getMessage()); e.printStackTrace(); } } return response.getStatusLine().getStatusCode() == 200; // 等于200表示发送成功. } }
4.在客户端定义一个对象类,与服务器端的一致,用来封装json数据.
package spt.src; /**用于将json数据转换的目标对象的类. * @author Administrator * */ public class Person { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person(String name, int age) { this.name = name; this.age = age; } }
5.解析json数据为目标类对象的辅助类:
package spt.json; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import spt.src.Person; /** * 解析从服务器端获取的json数据,并封装为对象. * * @author Administrator * */ public class JsonParser { public static Person getPerson(String key, String jsonStr) throws JSONException { JSONObject jObj = new JSONObject(jsonStr); JSONObject personObj = jObj.getJSONObject(key); return new Person(personObj.getString("name"), personObj.getInt("age")); } /** * 根据json数据,返回对象列表. * * @param key * @param jsonStr * @return * @throws JSONException */ public static List<Person> getPersonList(String key, String jsonStr) throws JSONException { JSONObject jsonObject = new JSONObject(jsonStr); JSONArray jArr = jsonObject.getJSONArray(key); List<Person> persons = new ArrayList<Person>(); // 存储返回对象. JSONObject jObj = null; for (int j = 0; j < jArr.length(); j++) { jObj = jArr.getJSONObject(j); persons.add(new Person(jObj.getString("name"), jObj.getInt("age"))); } return persons; } /** * 根据json数据,返回对象构成的键值对的列表. * * @param key * @param jsonStr * @return * @throws JSONException */ public static List<Map<String, Person>> getListPersonMap(String key, String jsonStr) throws JSONException { JSONObject jsonObject = new JSONObject(jsonStr); List<Map<String, Person>> personMaps = new ArrayList<Map<String, Person>>(); // 存储返回对象构成的键值对. //Map<String, Person>构成的数组. JSONArray jArr = jsonObject.getJSONArray(key); JSONObject jObj = null; for (int j = 0; j < jArr.length(); j++) { jObj = jArr.getJSONObject(j); //迭代每一个Map<String, Person>. Map<String, Person> personMap = new HashMap<String, Person>(); @SuppressWarnings("unchecked") Iterator<String> ks = jObj.keys(); JSONObject jPersonObj = null; //一个Person对象对应的json. String k = null; //Person对象对应的键. while(ks.hasNext()) { k = ks.next(); jPersonObj = (JSONObject)jObj.get(k); //将Person对象封装到Map中. personMap.put(k, new Person(jPersonObj.getString("name"), jPersonObj.getInt("age"))); } //将Map<String, Person>封装成数组. personMaps.add(personMap); } return personMaps; } }
客户端可以运行,在这里偷懒一下,对于不同解析,如何遍历List<Person> 和显示Person单独对象,相对简单,所以就省略了.
json api: http://json-lib.sourceforge.net/apidocs/jdk15/