记录一个Android客户端和Servlet服务端的JSON传输的小例子:
1.PostParam 包装了要发送的JSONObject类,这个例子中不包装也可以,但是会麻烦那么一点点。
2.ResponseParam 包装了服务端返回的JSONObject类,这个例子中勉强算是需要的,因为我们会用到bundle传递序列化对象,而JSONObject无法序列化。当然我们也可以把返回的EntIty转化为String传送。
3.PostAction post的线程,HttpPost操作都放到里面来了。
4.OnHttpActionListener action的监听器,就像按钮的设置事件一样,我们在创建它的时候实现方法,从而对获得的数据操作。
5.MainActivity 主线程
下面贴代码,最后会放上GetParam,GetAction和服务端的代码,这样就全了。但是GetAction就不测试了,毕竟和Post很类似。
PostParam:
package com.example.httputil;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
*
* @author Administrator
* JSONObject的包装类,我们可以把数据放入这个类的实例并传输它。
*/
public class PostParam
{
JSONObject param;
//懒汉式创建param,第一次addParam的时候才创建param。
//键值对添加数据
public void addParam(String key, String value){
if (null == param)
{
param = new JSONObject();
}
try
{
param.put(key, value);
} catch (JSONException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//重载addParam,参数是以JSON文件形式添加数据
public void addParam(String key, JSONObject object){
if (null == param)
{
param = new JSONObject();
}
try
{
param.put(key, object);
} catch (JSONException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//重载addParam,参数是以JSONArray形式添加数据
public void addParam(String key, JSONArray array){
if (null == param)
{
param = new JSONObject();
}
try
{
param.put(key, array);
} catch (JSONException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//重写toString,方便传输数据。
@Override
public String toString()
{
if (null != param)
{
return param.toString();
}
// TODO Auto-generated method stub
return "";
}
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResponseParam:
package com.example.httputil;
import java.io.Serializable;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
*
* @author Administrator
*这个类用来包装服务端返回的jsonobject,使得可以序列化,用bundle传输。
*/
public class ResponseParam implements Serializable
{
private static final long serialVersionUID = 75656654L;
JSONObject response;
ResponseParam(JSONObject response){
this.response=response;
}
ResponseParam(String value){
try
{
response = new JSONObject(value);
} catch (JSONException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//返回JSONObject中含有这个key的String
public String getString(String key){
if (response.has(key))
{
try
{
return response.getString(key);
} catch (JSONException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return "";
}
//返回JSONObject中含有这个key的JSONOBJECT
public JSONObject getJsonObject(String key){
if (response.has(key))
{
try
{
return response.getJSONObject(key);
} catch (JSONException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
//返回JSONObject中含有这个key的JSONArray
public JSONArray getJsonArray(String key){
if (response.has(key))
{
try
{
return response.getJSONArray(key);
} catch (JSONException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
OnHttpActionListener:
package com.example.httputil;
public interface OnHttpActionListener
{
//成功post的代码编写
public void onHttpActionSuccess(int actionId,ResponseParam responseParam);
//post失败的代码编写
public void onHttpActionFailed(int actionId,int failHttpCode);
//post报错的代码编写
public void onHttpActionException(int actionId,String excepionMsg);
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
PostAction:
package com.example.httputil;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
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.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import android.content.Entity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
/**
*
* @author Administrator
*用来发送PostParam实例到指定服务器地址,并接受服务器返回的JSONObject.
*这个JSONObject将放入ResponseParam的实例中,ResponseParam的实例又赋予给了监听器接口的SUCCESS方法,
*所以我们只要在主线程创建监听器,实现监听器的SUCCESS接口,就可以把返回的JSONObect里的数据拿出来处理了。
*/
public class PostAction implements Runnable
{
//线程ID
int Id;
//要发送的端口地址
String url;
//要传送的Post包的键名
String paramKey;
//要传送的Post包
PostParam postParam;
//用Handler接受返回的包
Handler handler;
//监听器,用来监听post是否成功,或者报错
OnHttpActionListener onHttpActionListener;
//如果post服务端成功连接,则返回这个值
final static int MSG_POST_SUCCESS = 0x10;
//如果post服务端失败,比如404页面,则返回这个值
final static int MSG_POST_FAIL = 0x20;
//如果连接报错,则返回这个值
final static int MSG_POST_EXCEPTION = 0x30;
//服务器返回的JSONObject将打包成ResponseParam,放到bundle的序列化Object里,这个就是Object的Key
//然后这个bundle随着message发送到handler里再根据key提取。
final static String MSG_KEY_SERIALIZABLE = "serializableParmKey";
//如果连接服务器报错,则会把出错的信息放到Bundle发到handler,这个就是提取的key
final static String MSG_KEY_EXCEPTION = "exceptionKey";
//和服务器接口事先规定好的登录信息提取key,客户端根据这个key发出登录帐号密码包,服务器根据这个key再提取。
public final static String LoginParam="LoginParam";
/**
*
* @param actionId 用来区分各个action的id
* @param url post服务端地址
* @param paramKey post服务端的包key,一般是这个类里设置好的常量,比如这个类里的LoginParam
*/
public PostAction(int actionId, String url,String paramKey)
{
this.Id = actionId;
this.url = url;
this.paramKey=paramKey;
//handler接收message并赋值给监听器,至此,接受端的代码就结束了,我们成功地把服务端的返回值交给了监听器。
//new action的时候需要setOnHttpActionListener(),创建监听器的的时候又需要实现它的三个方法,根据这三个方法我们可以做相应的处理。
handler = new Handler(){
@Override
public void handleMessage(Message msg)
{
//判断是否本线程发出的信息,监听器是否设置了
if (msg.what == Id && onHttpActionListener != null)
{
//接收的msg里的arg1里我们统一放了post状态常量,根据msg的arg1值,去对应着监听器的接口方法
switch (msg.arg1)
{
//如果是成功连接服务器端,则把返回的包放入监听器。
case MSG_POST_SUCCESS:
onHttpActionListener.onHttpActionSuccess(Id,
(ResponseParam)msg.getData().getSerializable(MSG_KEY_SERIALIZABLE));
break;
//如果是连接服务器端失败,则把失败返回的http码放入监听器。
case MSG_POST_FAIL:
onHttpActionListener.onHttpActionFailed(Id, msg.arg2);
break;
//如果是连接服务器端报错,则把报错的信息String放入监听器。
case MSG_POST_EXCEPTION:
onHttpActionListener.onHttpActionException(Id,
msg.getData().getString(MSG_KEY_EXCEPTION));
break;
}
}
}
};
}
//传入监听器
public void setOnHttpActionListener(OnHttpActionListener onHttpActionListener)
{
this.onHttpActionListener = onHttpActionListener;
}
//设置要传输的post包
public void setPostParam(PostParam postParam)
{
this.postParam = postParam;
}
//线程执行的代码
@Override
public void run()
{
// TODO Auto-generated method stub
try
{
//设置post连接,连接地址url已经在构造方法那传过来了
HttpPost post =new HttpPost(url);
//键值对List,下面用工具可以把它转化为entity
List<NameValuePair> param =new ArrayList<NameValuePair>();
//往键值对里添加数据,paramKey是构造方法那传进来的,发送包的key,值就是postParam里的JSONObject转化为String的值
param.add(new BasicNameValuePair(paramKey,postParam.toString()));
//用工具把List转化为Entity之后,再放入post里
post.setEntity(new UrlEncodedFormEntity(param,HTTP.UTF_8));
//执行post,并得到返回的response
HttpResponse response = new DefaultHttpClient().execute(post);
//得到response里的HttpCode,这个值如果是404则是找不到端口,200则是成功连接,很好理解的
int httpCode = response.getStatusLine().getStatusCode();
//SC_OK=200,判断是否成功连接到服务端
if ( httpCode== HttpStatus.SC_OK)
{
//成功连接,当然有一个服务器返回的JSONOject包了,我们要把这个包传给handler,通过message就可以很好的完成任务
Message message =new Message();
//发送这个Message的线程ID
message.what = Id;
//arg1放入成功连接状态的常量,告诉handler成功连接了
message.arg1 = MSG_POST_SUCCESS;
//JSONOject需要用Bundle来放
Bundle bundle = new Bundle();
//由于Bundle只能放序列化的实例,所以JSONOject是放不进的,但是我们已经做好了一个可以序列化的类来包装JSONOject
//所以把服务端返回的包放进ResponseParam里就可以用Bundler传了。
//这里还用到了工具类,去把返回的entity转化为String类型。而ResponseParam的其中一个构造方法可以用String做参数。完美结合。
ResponseParam responseParam = new ResponseParam(EntityUtils.toString(response.getEntity()));
//从BUNDLE里拿出序列化包,还得用设置好的key常量,handler中可以用这个key拿出包。
bundle.putSerializable(MSG_KEY_SERIALIZABLE, responseParam);
//把bundle放入message里
message.setData(bundle);
//发送message
handler.sendMessage(message);
}else {
//如果连接服务端口失败,直接在arg2里放入失败的 httpcode就行
Message message =new Message();
message.what = Id;
message.arg1 = MSG_POST_FAIL;
message.arg2 = httpCode;
handler.sendMessage(message);
}
} catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
//连接服务器接口报错,则返回报错信息即可
Message message =new Message();
message.what = Id;
message.arg1 = MSG_POST_EXCEPTION;
Bundle bundle = new Bundle();
bundle.putString(MSG_KEY_EXCEPTION, e.getMessage());
message.setData(bundle);
handler.sendMessage(message);
}
}
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
MainActivity(只贴主要方法):
public class MainActivity extends FragmentActivity
{
//服务器发过来的包的key,服务器端事先声明好登录页面数据包的key
final static String MSG_KEY_LOGIN = "MSG_KEY_LOGIN";
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);
//加载帐号,密码框和登录按钮
final EditText userText = (EditText)findViewById(R.id.username);
final EditText passText = (EditText)findViewById(R.id.password);
Button loginbtn = (Button)findViewById(R.id.loginbtn);
Button exitbtn = (Button)findViewById(R.id.exitbtn);
//登录按钮的点击事件:发送帐号密码到服务端
loginbtn.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
String username=userText.getText().toString();
String password=passText.getText().toString();
//判断帐号密码是否为空
if (username != null && password != null && username.length() > 0 && password.length() > 0)
{
doLogin(username, password);
}else {
Toast.makeText(MainActivity.this, "请输入帐号和密码", Toast.LENGTH_LONG).show();
}
}
});
}
void doLogin(String username,String password){
//创建action,10.0.2.2是虚拟机中的电脑主机本地IP,不要使用localhost或者127.0.0.1
PostAction action = new PostAction(0,"http://10.0.2.2:8080/TestServer/LoginDo", PostAction.LoginParam);
PostParam loginParma = new PostParam();
loginParma.addParam("username",username);
loginParma.addParam("password",password);
action.setPostParam(loginParma);
//设置acion的监听器,这个时候我们可以好好处理获得的数据了
action.setOnHttpActionListener(new OnHttpActionListener()
{
@Override
public void onHttpActionSuccess(int actionId, ResponseParam responseParam)
{
//返回的包里的的key已经在上面声明好了,得到值并用toast显示。
Toast.makeText(MainActivity.this,responseParam.getString(MSG_KEY_LOGIN), Toast.LENGTH_LONG).show();
}
@Override
public void onHttpActionFailed(int actionId, int failHttpCode)
{
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this,failHttpCode, Toast.LENGTH_LONG).show();
}
@Override
public void onHttpActionException(int actionId, String excepionMsg)
{
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this,excepionMsg, Toast.LENGTH_LONG).show();
}
});
//不要忘了创建新线程来运行action
new Thread(action).start();
}
服务器的servlet代码,里面要用的JSON的jar包需要自己上网下载,搜下就有,不多说了:
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONObject;
import net.sf.json.JSONString;
import net.sf.json.util.JSONUtils;
public class LoginDo extends HttpServlet {
//和客户端声明好的key,服务端用这个key发送数据,客户端会用这个key获得返回的数据。
final static String MSG_KEY_LOGIN="MSG_KEY_LOGIN";
//如果登录成功则返回这个数据,也就是1
final static int MSG_KEY_LOGIN_SUCCESS = 1;
//如果帐号密码不正确,就返回它
final static int MSG_KEY_LOGIN_FAIL = 0;
//如果验证出了异常,则返回它
final static int MSG_KEY_LOGIN_EXCEPTION = -1;
//和客户端声明好的Key,客户端用这个key发数据过来,而服务端就可以用这个key获得数据
final static String LoginParam = "LoginParam";
/**
* Constructor of the object.
*/
public LoginDo() {
super();
}
/**
* Destruction of the servlet. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置编码
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "text/html;charset=UTF-8");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
//获取接收到的值
String loginParam = request.getParameter(LoginParam);
//把这个得到的String转化为JSONObject,这个转化的方式其实并不是很好。
JSONObject loginObject =JSONObject.fromObject(loginParam);
//
String username = loginObject.getString("username");
String password = loginObject.getString("password");
try {
//加载jdbc驱动
Class.forName("com.mysql.jdbc.Driver");
//连接数据库,这里我用的是mysql
Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/TestServer","root","root");
//创建陈述对象
Statement st=conn.createStatement();
//编写sql语句
String sql="Select * from User Where username='"+username+"' and password='"+password+"'";
//使用陈述对象执行sql语句,并把返回值赋给rs
ResultSet rs=st.executeQuery(sql);
//如果返回值不为空,则用out传输过去MSG_KEY_LOGIN_SUCCESS
if(rs.next()!=false){
JSONObject object =new JSONObject();
object.put(MSG_KEY_LOGIN, MSG_KEY_LOGIN_SUCCESS);
out.print(object);
//服务端还是得print一下
System.out.print("登录成功");
}else{
//帐号密码不正确,返回MSG_KEY_LOGIN_FAIL
JSONObject object =new JSONObject();
object.put(MSG_KEY_LOGIN, MSG_KEY_LOGIN_FAIL);
out.print(object);
System.out.print("登录失败");
}
//关闭连接
rs.close();
st.close();
conn.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
//查询报错返回MSG_KEY_LOGIN_EXCEPTION
JSONObject object =new JSONObject();
object.put(MSG_KEY_LOGIN,MSG_KEY_LOGIN_EXCEPTION);
out.print(object);
}
out.flush();
out.close();
}
/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request,response);
}
/**
* Initialization of the servlet. <br>
*
* @throws ServletException if an error occurs
*/
public void init() throws ServletException {
// Put your code here
}
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
GetParam:
package com.example.httputil;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
*
* @author Administrator
* 参考postparam吧
*/
public class GetParam
{
//用来存放键值对的map
Map<String, String> param;
//把键值对放进HashMap里
public void addParam(String key,String value){
if (param == null)
{
param =new HashMap<String, String>();
}
param.put(key, value);
}
//重写toString,把map里的键值对按照?key="value"&key2="value2"的方式输出。
@Override
public String toString()
{
if (param != null)
{
StringBuffer sb=new StringBuffer();
sb.append('?');
//keySet()可以把map的key放入Set<String>里,从而得到iterator,方便操作,实用的办法。
Iterator<String> iterator =param.keySet().iterator();
while (iterator.hasNext())
{
String key=iterator.next();
sb.append(key);
sb.append('=');
sb.append(param.get(key));
//判断是否最后一个参数,如果不是就是加一个“&”
if (iterator.hasNext())
{
sb.append('&');
}
}
return sb.toString();
}
return "";
}
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
GetAction:
package com.example.httputil;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import android.R.integer;
import android.content.Entity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
/**
*
* @author Administrator
*和PostAction基本一样,参考它就可以了。
*/
public class GetAction implements Runnable
{
int actionId;
String url;
GetParam param;
OnHttpActionListener onHttpActionListener;
Handler handler;
final static int MSG_GET_SUCCESS = 0x10;
final static int MSG_GET_FAIL = 0x20;
final static int MSG_GET_EXCEPTION = 0x30;
final static String MSG_KEY_SERIALIZABLE = "serializableParmKey";
final static String MSG_KEY_EXCEPTION = "exceptionKey";
public String getUrl()
{
return url;
}
public void setParam(GetParam param)
{
this.param = param;
}
public int getActionId()
{
return actionId;
}
public void setOnHttpActionListener(OnHttpActionListener onHttpActionListener){
this.onHttpActionListener =onHttpActionListener;
}
public GetAction(int Id,String url)
{
// TODO Auto-generated constructor stub
actionId = Id;
this.url=url;
handler = new Handler(){
@Override
public void handleMessage(Message msg)
{
if (msg.what == actionId && onHttpActionListener != null)
{
switch (msg.arg1)
{
case MSG_GET_SUCCESS:
onHttpActionListener.onHttpActionSuccess(actionId,
(ResponseParam)msg.getData().getSerializable(MSG_KEY_SERIALIZABLE));
break;
case MSG_GET_FAIL:
onHttpActionListener.onHttpActionFailed(actionId,msg.arg2);
break;
case MSG_GET_EXCEPTION:
onHttpActionListener.onHttpActionException(actionId,
msg.getData().getString(MSG_KEY_EXCEPTION));
break;
}
}
}
};
}
@Override
public void run()
{
// TODO Auto-generated method stub
HttpGet get = new HttpGet(url+param.toString());
try
{
HttpResponse response =new DefaultHttpClient().execute(get);
int httpCode = response.getStatusLine().getStatusCode();
if (httpCode == HttpStatus.SC_OK)
{
String ret =EntityUtils.toString(response.getEntity());
ResponseParam responseParam =new ResponseParam(ret);
Message message = new Message();
message.what = actionId;
message.arg1 = MSG_GET_SUCCESS;
Bundle bundle = new Bundle();
bundle.putSerializable(MSG_KEY_SERIALIZABLE, responseParam);
message.setData(bundle);
handler.sendMessage(message);
}else {
Message message =new Message();
message.what = actionId;
message.arg1 = MSG_GET_FAIL;
message.arg2 = httpCode;
handler.sendMessage(message);
}
}catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
Message message = new Message();
message.what = actionId;
message.arg1 = MSG_GET_EXCEPTION;
Bundle bundle =new Bundle();
bundle.putString(MSG_KEY_EXCEPTION, e.getMessage());
message.setData(bundle);
handler.sendMessage(message);
}
}
}
---------完------------