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();
ListnLists=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);
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
new Thread(new Runnable() {
String url = "http://localhost:8080/JsonXmlService/JsonServlet";
@Override
public void run() {
// TODO Auto-generated method stub
List 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();
}
// 自定义一个方法将流转换成字节数组
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()方法进行转换一下
}
//将字节数组转换成对象封装在News对象中。,并插入集合中
public List parserJson(InputStream is) {
List lists=new ArrayList();
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);将字节转换为字符串
由于时间没有办法直接通过json获取到,所以我们在服务端的时候做成了长整形,而这里我们获取长整形,再强转为Date类型就又可以显示具体的时间了
接下来进行界面数据绑定,通过 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 newsList=null;
private ListView lv;
Handler handler = new Handler() {
public void handleMessage(Message msg) {
if (msg.what == 0x12) {
newsList = (List) 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
2、pull从服务端解析服务端数据
在android系统中,很多资源文件中,很多都是xml格式,在android系统中解析这些xml的方式,是使用pul解析器进行解析的,它和sax解析一样(个人感觉要比sax简单点),也是采用事件驱动进行解析的,当pull解析器,开始解析之后,我们可以调用它的next()方法,来获取下一个解析事件(就是开始文档,结束文档,开始标签,结束标签),当处于某个元素时可以调用XmlPullParser的getAttributte()方法来获取属性的值,也可调用它的nextText()获取本节点的值。
接下来进行代码示例
首先是服务端集合对象中要添加数据
public List getAll() {
// TODO Auto-generated method stub
List nLists=new ArrayList();
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 newsList=nImp.getAll();
request.setAttribute("newsList", newsList);
request.getRequestDispatcher("/a.jsp").forward(request, response);
${new.title }
${new.data}
服务端没什么可说的,接下来我们看一下
客户端
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 getlistNews() {
String path = "http://172.20.58.104:8080/XmlService/XmlServlet";
List 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 pullParserxml(InputStream is) throws Exception {
List 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();
break;
case XmlPullParser.START_TAG:
if ("news".equals(pullParser.getName())) {
news = new News();
int id = new Integer(pullParser.getAttributeValue(0));
//开始标签的内容从0开始
//记住此处是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> 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> getData() {
List> list = new ArrayList>();
List newsList = NewsService.getlistNews();
for (News news : newsList) {
HashMap map = new HashMap();
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 map = new HashMap();
map.put("name", name);
map.put("pass", pass);
if (map != null && !map.isEmpty()) {//此处之循环一次
for (Map.Entry 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!
以方便观察是否成功,下面就是客户端与服务端的效果图