1、json从服务端解析服务端数据
客户端的运行结果本来是这样的
[{id:1,title:"马云",publishTime:Sat May 14 15:31:11 CST2016},{id:1,title:"李彦宏",publishTime:SatMay 14 15:31:11 CST 2016},{id:1,title:"李嘉诚",publishTime:Sat May 14 15:31:11 CST 2016}]
,为了方便解析我们把他先改成这样
[{id:1,title:"马云",publishTime:1463209359065},{id:1,title:"李彦宏",publishTime:1463209359065},{id:1,title:"李嘉诚",publishTime:1463209359065}]
,在客户端的时候通过json解析成时间就ok了
首先要让服务端有这些数据
sdaoimp=new ServiceDaoImp(); List<News>nLists=sdaoimp.getAllNews();//获取集合对象 StringBuilder stringBuilder=new StringBuilder();//遍历所有对象 stringBuilder.append('['); for (News news : nLists) { stringBuilder.append("{"); stringBuilder.append("id:").append(news.getId()).append(","); stringBuilder.append("title:\"").append(news.getTitle()).append("\","); stringBuilder.append("publishTime:").append(news.getPublishTime()); //通过getTime()将时间改为长整形,到客户端再改回来 stringBuilder.append("},"); } //[{"id:1","title:马云","publishTime:06-25"},{"id:1","title:李彦宏","publishTime:06-26"},{"id:1","title:李嘉诚","publishTime:06-27"}] stringBuilder.deleteCharAt(stringBuilder.length()-1); stringBuilder.append(']'); //作为属性的值存放 request.setAttribute("json", stringBuilder); //response.sendRedirect("json.jsp"); request.getRequestDispatcher("json.jsp").forward(request, response);
这里我们用了StringBulider,通常情况下 StringBuilder >StringBuffer >String
String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)
好了接下来我们看一下客户端的编码
Service.java
package com.json.service; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.os.Handler; import android.os.Message; import android.util.Log; import com.json.entity.News; public class Service { private Handler mhanHandler=new Handler(); public Service(Handler mhanHandler) { super(); this.mhanHandler = mhanHandler; } public void getAll() {//由于此时将集合放进message中,就不需要返回值为List<News> new Thread(new Runnable() { String url = "http://localhost:8080/JsonXmlService/JsonServlet"; @Override public void run() { // TODO Auto-generated method stub List<News> newsList=null; try { HttpURLConnection conn = (HttpURLConnection) new URL(url) .openConnection(); conn.setReadTimeout(5000); conn.setRequestMethod("GET"); if (conn.getResponseCode() == 200) { // 当请求码为200的时候表示网络服务连接成功 // 将字节流转换成集合或字符串 InputStream inputStream = conn.getInputStream(); newsList=parserJson(inputStream); if (newsList.size()>0) {//这里最好先判断一下 Message msg=new Message(); msg.obj=newsList; msg.what=0x12; mhanHandler.sendMessage(msg); //将集合封装在message中并通过handler发送出去 } } } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); } <span style="color:#ff0000;">// 自定义一个方法将流转换成字节数组 public byte[] costom(InputStream is) { ByteArrayOutputStream baos=new ByteArrayOutputStream(); byte[] buffer=new byte[1024];//创建一个字节缓冲区 int length=0; while (buffer.length!=-1) { try { baos.write(buffer); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return baos.toByteArray();//返回baos,由于方法的返回值是byte[]类型,所以通过toByteArray()方法进行转换一下 }</span> //将字节数组转换成对象封装在News对象中。,并插入集合中 public List<News> parserJson(InputStream is) { List<News> lists=new ArrayList<News>(); byte[] byteJson=costom(is); String strJson=new String(byteJson);//由于不能通过字符串(没有带流参数的构造方法,但有带byte参数的构造方法)将流 //转换成字符串,这里我们通过字节,先将流转换成byte字节数组,再转换成字符串 try { JSONArray jsonArray=new JSONArray(strJson); for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonObject=new JSONObject(); int id=jsonObject.getInt("id"); String title=jsonObject.getString("title"); Date time=new Date(jsonObject.getLong("publishTime"));//由于没有Date的类型可获得 //所以创建一个date对象将字符串转换成Date对象 //封装对象 News news=new News(id, title, time); //将对象添加到集合中 lists.add(news); } } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } return lists; } }由于网络访问一般要在线程中实现,所以这里我使用了handler线程来通过网络获取下面集合中获取到的数据
这里我们需要处理的是基本数据类型,那么我们如何将流转换成字符串呢?
流→字节数组→字符串,不能通过流直接到字符串,首先这里自定义一个custom方法,返回值为字节数组,而又通过
String strJson=new String(byteJson);将字节转换为字符串
<span style="color:#ff0000;">由于时间没有办法直接通过json获取到,所以我们在服务端的时候做成了长整形,而这里我们获取长整形,再强转为Date类型就又可以显示具体的时间了</span>
接下来进行界面数据绑定,通过 message获取service.java传递过来的值,并通过SimpleAdapter实现界面数据的绑定
JsonXmlActivity.javapackage com.json.activity; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.json.entity.News; import com.json.service.Service; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.widget.ListView; import android.widget.SimpleAdapter; public class JsonXmlActivity extends Activity { /** Called when the activity is first created. */ List<News> newsList=null; private ListView lv; Handler handler = new Handler() { public void handleMessage(Message msg) { if (msg.what == 0x12) { newsList = (List<News>) msg.obj;//取到传递过来的值,传递过来的是个集合,所以获取到的值要放在集合中 } }; }; //通过service.java获取传递过来的值,并通过SimpleAdapter实现界面数据的绑定 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); lv = (ListView) findViewById(R.id.listView1); Service service = new Service(handler);// 参数为上面的handler对象 service.getAll();// 只有调用这个方法上面的Handler才能够获取到数据 } private void getData() { List<Map<String, Object>> datalist = new ArrayList<Map<String, Object>>(); for (com.json.entity.News news : newsList) { Map<String, Object> map = new HashMap<String, Object>(); map.put("id", news.getId());// 此处通过map将SimpleAdapter的values与Service中获取的标签内容进行绑定 map.put("title", news.getTitle()); map.put("time", news.getPublishTime()); datalist.add(map); } SimpleAdapter adapter = new SimpleAdapter(this, datalist, R.layout.test, new String[] { "id", "title", "time" }, new int[] { R.id.id, R.id.id, R.id.id }); lv.setAdapter(adapter); } }
这里一定要调用getAll()这个方法,只有调用这个方法上面的Handler才能够获取到数据传递过来的数据
2、pull从服务端解析服务端数据
在android系统中,很多资源文件中,很多都是xml格式,在android系统中解析这些xml的方式,是使用pul解析器进行解析的,它和sax解析一样(个人感觉要比sax简单点),也是采用事件驱动进行解析的,当pull解析器,开始解析之后,我们可以调用它的next()方法,来获取下一个解析事件(就是开始文档,结束文档,开始标签,结束标签),当处于某个元素时可以调用XmlPullParser的getAttributte()方法来获取属性的值,也可调用它的nextText()获取本节点的值。
接下来进行代码示例
首先是服务端集合对象中要添加数据
public List<News> getAll() { // TODO Auto-generated method stub List<News> nLists=new ArrayList<News>(); News news1=new News(1, "英雄联盟", new Date(System.currentTimeMillis())); News news2=new News(2, "穿越火線", new Date(System.currentTimeMillis())); News news3=new News(3, "刀塔", new Date(System.currentTimeMillis())); nLists.add(news1); nLists.add(news2); nLists.add(news3); return nLists; }这里很简单就不多说了,接下来就是Servlet部分
List<News> newsList=nImp.getAll(); request.setAttribute("newsList", newsList); request.getRequestDispatcher("/a.jsp").forward(request, response);
注意获取jsp页面的连接,而a.jsp
<newslist> <c:forEach items="${newsList}" var="new"> <news id="${new.id }"> <title>${new.title }</title> <data>${new.data}</date> </news> </c:forEach> </newslist>服务端没什么可说的,接下来我们看一下 客户端
NewsService.java
package edu.service; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import org.xmlpull.v1.XmlPullParser; import android.util.Xml; import edu.entity.News; public class NewsService { // 连接服务器 public static List<News> getlistNews() { String path = "http://172.20.58.104:8080/XmlService/XmlServlet"; List<News> newsList = null; try { HttpURLConnection conn = (HttpURLConnection) new URL(path) .openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); if (conn.getResponseCode() == 200) { // 正常连接服务器 try { InputStream xml = conn.getInputStream(); // 经过解析转换成集合对象 newsList = pullParserxml(xml); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return newsList; } // 自定义方法,利用pull解析xml public static List<News> pullParserxml(InputStream is) throws Exception { List<News> list = null; News news = null; XmlPullParser pullParser = Xml.newPullParser();// pull解析器 pullParser.setInput(is, "utf-8"); int envent = pullParser.getEventType(); while (envent != XmlPullParser.END_DOCUMENT) { switch (envent) { case XmlPullParser.START_DOCUMENT: list = new ArrayList<News>(); break; case XmlPullParser.START_TAG: if ("news".equals(pullParser.getName())) { news = new News(); int id = new Integer(pullParser.getAttributeValue(0));
//开始标签的内容从0开始 <span style="white-space:pre"> </span>//记住此处是getAttributeValues不是getAttributeName news.setId(id); } if ("title".equals(pullParser.getName())) { // String title = pullParser.nextText(); // news.setTitle(title); news.setTitle(pullParser.nextText()); } if ("data".equals(pullParser.getName())) { String time = pullParser.nextText(); // SimpleDateFormat sdf = new SimpleDateFormat("yyyy--MM--dd"); // news.setTime(sdf.parse(time)); news.setTime(time); } break; case XmlPullParser.END_TAG: if ("news".equals(pullParser.getName())) { list.add(news); news = null; } break; } envent = pullParser.next(); } return list; } }
这里的path中的8686根据个人电脑的端口号而定,默认是8080。当请求码为200的时候表示网络服务连接成功
package edu.abc; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import edu.entity.News; import edu.service.NewsService; import android.app.ListActivity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.widget.SimpleAdapter; public class ListXmlActivity extends ListActivity { /** Called when the activity is first created. */ public static final String TAG = "ListXmlActivity"; List<Map<String, Object>> data = null; SimpleAdapter adapter = null; Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); if (msg.what == 0x123) { adapter = new SimpleAdapter(ListXmlActivity.this, data, R.layout.test, new String[] { "id", "title", "data" }, new int[] { R.id.id, R.id.title, R.id.time }); setListAdapter(adapter); } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); new Thread(){ @Override public void run() { // TODO Auto-generated method stub super.run(); data = getData(); handler.sendEmptyMessage(0x123); } }.start(); } public List<Map<String, Object>> getData() { List<Map<String, Object>> list = new ArrayList<Map<String,Object>>(); List<News> newsList = NewsService.getlistNews(); for (News news : newsList) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("id", news.getId()); map.put("title", news.getTitle()); map.put("data", news.getTime()); list.add(map); } return list; } }此处通过map将SimpleAdapter的values与NewService中获取的标签内容进行绑定
3、客户端与服务端的互相通信
服务端不仅可以获取客户端发过来的数据,也可反馈给客户端数据,那么我们先看一下服务端的Servlet代码
String name=(String) request.getParameter("name"); String pass=(String) request.getParameter("pass"); System.out.println("My Name:"+name); System.out.println("My Pass:"+pass); //回馈数据 OutputStream os=response.getOutputStream(); String ss="Get successfully,this is the back!"; os.write(ss.getBytes());//转换成字节读取接下来看一下 客户端的代码
Service.java
package com.up.activity; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map; import javax.net.ssl.HttpsURLConnection; import android.os.Handler; import android.os.Message; public class Service { String path = "http://172.20.52.25:8080/UpService/ResceviceServlet"; String name, pass; Handler handler; public Service(String name, String pass, Handler handler) { super(); this.name = name; this.pass = pass; this.handler = handler; } public void setMsg() {// 讲参数写在上面的构造方法中 new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(path); sb.append("?"); Map<String, String> map = new HashMap<String, String>(); map.put("name", name); map.put("pass", pass); if (map != null && !map.isEmpty()) {//此处之循环一次 for (Map.Entry<String, String> damap : map.entrySet()) { sb.append(damap.getKey()).append("="); sb.append(damap.getValue()); sb.append("&"); // http://172.20.58.109:8686/UpService/ResceviceServlet?name=***&pass=***& } sb.deleteCharAt(sb.length() - 1);// 多余一个&去掉 // http://172.20.58.109:8686/UpService/ResceviceServlet?name=***&pass=*** } try { HttpURLConnection conn = (HttpURLConnection) new URL(sb.toString())//前面已经将不完整的path添加到StringBulider .openConnection(); conn.setReadTimeout(2000);//链接超市 conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); // 请求属性,可以把地址的?与&之间的属性隔开 conn.setDoOutput(true);// 设置允许输出流输出内容 byte[] data = sb.toString().getBytes();// 将字符串转换成字节数组,因为前面的字符串存储在StringBuilder里,所以要转换成字符串通过toString OutputStream os = conn.getOutputStream(); os.write(data);// 数据上传是输出流,是write写数据 os.flush(); // 等待网络请求的响应 if (conn.getResponseCode() == 200) { InputStream is = conn.getInputStream();// 数据下载回应是输入流,是read读数据 ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] size = new byte[1024]; int length = 0; while ((length = is.read(size)) != -1) { baos.write(size);//将读的内容写入字节中 } Message msg = new Message(); msg.what = 12; msg.obj=baos.toString();//转换成字符串 handler.sendMessage(msg);// 注意上面构造handler的使用 } } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // 连接服务器 }).start(); } }要说的内容都在注释里面做了详细的介绍,接下来看一下我们在主线程中要做的事情
UpToServiceActivity.java
package com.up.activity; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class UpToServiceActivity extends Activity implements OnClickListener{ /** Called when the activity is first created. */ private EditText etName,etPass; private Button bt; Handler handler=new Handler(){ public void handleMessage(android.os.Message msg) { if (msg.what==12) { String sss=(String)msg.obj; Toast.makeText(UpToServiceActivity.this, sss, Toast.LENGTH_LONG).show(); } }; }; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); etName=(EditText) findViewById(R.id.etName); etPass=(EditText) findViewById(R.id.etPass); bt=(Button) findViewById(R.id.bt); bt.setOnClickListener(this); } @Override public void onClick(View arg0) { // TODO Auto-generated method stub String name=etName.getText().toString().trim(); String pass=etPass.getText().toString().trim(); //将网络请求放在主线程中实现 Service s=new Service(name, pass, handler);//此时有个handler参数,所以上面要创建一个handler s.setMsg(); } }
这里我在服务端设置了一段文字
Get successfully,this is the back!
以方便观察是否成功,下面就是客户端与服务端的效果图
以上所有的服务端与客户端的代码我都放在一个文件夹中你们可以参考一下