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/

  

你可能感兴趣的:(android)