您的位置:首页 > 理论基础 > 计算机网络

Android 网络中get与post两种提交数据的方式

2017-04-17 13:36 387 查看

项目简介:

该项目演示android中的两种网络请求方式:get与post

详细介绍:

该项目中有六个按钮,共有三种框架分别饰演GET和POST提交数据的方式,并获得从服务器返回的数据(类似与登录界面)

如下图所示,在两个输入框内输入数据后,点击第一个按钮,输入框中的数据会提交给服务器,如果输入的数据正确,则如下所示:



如果输入的数据不正确,就如下所示:



其余的按钮都一样,只是提交的方式或者使用的框架不一定。基本操作都是提交数据给服务器,然后服务器返回数据。

该应用涉及到的知识有:

1.POST提交与GET提交的区别

  GET直接把需要提交的数据凭借在URL后面。

  POST把需要提交的数据封装在请求正文中,并且在请求头中要多出两行属性Content-type和Content-Lenght。

2.使用HttpURLConnection框架来实现get和post的提交

3.使用HttpClient框架来实现get和post的提交

4.使用AsyncHttpClient框架来实现get和post的提交

5.解决服务器与客户端之间的乱码问题

注意:

1.需要自己在Tomcat上新建一个web项目,然后在web项目中新建一个servlet。最好现在网页上实验数据能够提交,再在Android上实现。

2.post方式提交失败,即在请求码获取的时候总是抛出错误,可能是使用setRequestProperty设置Content-type和Content-Lenght时属性出错导致的

3.对于Android 6.0以后,HttpClient框架已经移除,官方推荐使用HttpURLConnection,因为后者的效率更高。如果要想在Android 6.0 以后使用HttpClient,需要在自己的项目下添加org.apache.http.legacy.jar(点击到下载界面),即可使用,

4.对于中文乱码的问题,要注意到一点,服务器默认使用iso8859-1,windows平台默认使用gbk,而Android系统使用utf-8,所以在编写服务器的servlet的时候一定要注意将中文先解码在编码

步骤:

1.准备工作

1.1由于涉及到服务器,所以新建一个Dynamic Web Project,这里命名为Nweb。

1.2 在Src目录下创建一个包,在创建一个Servlet,这里命名为LoginServlet:

import java.io.IOException;
import java.io.OutputStream;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 浏览器(Android手机的浏览器)提交数据是会把中文用utf-8提交到服务器
// 服务器会使用iso8859-1解析数据
// 浏览器提交的编码与服务器的解码不一致,会导致中文乱码
String name = request.getParameter("name");
String password = request.getParameter("password");

// 在控制台上输出信息,便于开发
System.out.println("没有处理之前      姓名:" + name + "  用户:" + password);

// 中文会乱码,所以先用iso8859-1把字符串解码成字节数组,然后在用utf-8编码成字符串
name = new String(name.getBytes("iso8859-1"), "utf-8");

// 在控制台上输出信息,便于开发
System.out.println("处理后      姓名:" + name + "  用户:" + password);

// 获取输出流,用来给客户端返回信息
OutputStream os = response.getOutputStream();

// 这里应当连接数据库,进行查询语句,这里直接判断了,不连接数据库了
if ("hhh".equals(name) && "123".equals(password)) {
// 注意,要写上编码格式,不然windows系统下默认为gbk,而Android客户端默认是utf-8,这样会导致乱码。
os.write((name + " 登录成功").getBytes("utf-8"));
} else if ("张三".equals(name) && "123".equals(password)) {
os.write((name + " 登录成功").getBytes("utf-8"));
} else {
os.write(("你总是登录不上,还要这手机干什么?摔了吧,换个新的就登上了").getBytes("utf-8"));
}

}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}

}


这个Servlet的作用就是判断输入的两个数据(姓名name和密码password)是否符合要求,符合就返回登录成功的信息,不符合就返回登录失败的信息。

1.3 在webRoot目录下创建一个login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>登录界面</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
get提交方式
<body>
<form action="LoginServlet" method="get">
用户名:<input type="text" name="name"><br>
密码:<input type="text" name="password"><br>
<input type="submit" value="提交">
</form>
</body>
<br/>
<br/>
<


这个界面对Android项目没有任何作用,只是测试一下自己的LoginServlet写的是否正确

1.4部署在tomcat服务器上,开始测试

打开浏览器,输入http://10.12.16.141:8080/Nweb/login.jsp,出现如下界面:



在第一个表单下面正确填写数据,并点击上面的提交按钮后,显示登录成功的信息,然后会发现,浏览器里面的地址栏变成了了http://10.12.16.141:8080/Nweb/LoginServlet?name=%E5%BC%A0%E4%B8%89&password=123,其中%E5%BC%A0%E4%B8%89是中文经过编码后产生的数据。这里就得到了GET提交方式的路径格式了。

同样,利用第二个表单,得到POST提交方式的路径为http://10.12.16.141:8080/Nweb/LoginServlet,并且打开浏览器的开发者工具,可以看到请求表头中多了两行数据:



2.创建Android项目

2.1由于项目中使用了HttpCLinet框架,而在Android6.0后被移除了,所以要添加一个支持该框架的jar包(可以点击这里到下载地址)。在项目先新建一个libs文件夹,把支持包放进去进行了,点后对该包右击,选择Build path就完成了:



2.2 项目中使用了AsyncHttpClient,这是一个开源项目,是别人基于HttpClinet框架封装好的框架,比使用HttpClient更方便,下载地址点击这里(里面的readme.txt文件有详细说明)。使用该框架前,需要添加该矿建的源码包,并且也要添加支持HttpClinet框架的jar包:



3.布局文件

编写activity_mian.xml布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="hhh.exercise.ngetandpost.MainActivity" >

<EditText
android:id="@+id/et_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="张三"
android:textColor="#00ff00"
android:textSize="30sp" />

<requestFocus />

<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="123"
android:textColor="#00ff00"
android:textSize="30sp" />

<Button
android:id="@+id/bt_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="GET/HttpURLConnection"
android:textColor="#ff0000" />

<Button
android:id="@+id/bt_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="GET/HttpClient"
android:textColor="#ff0000" />

<Button
android:id="@+id/bt_3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="GET/AsyncHttpClient"
android:textColor="#ff0000" />

<Button
android:id="@+id/bt_4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="POST/HttpURLConnection"
android:textColor="#0000ff" />

<Button
android:id="@+id/bt_5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="POST/HttpClient"
android:textColor="#0000ff" />

<Button
android:id="@+id/bt_6"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="POST/AsyncHttpClient"
android:textColor="#0000ff" />

</LinearLayout>


这里的布局就是从上到下,两个EditText,六个按钮。

2.Activity

编写MainActivity代码:

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity implements<
10d8c
/span> OnClickListener {

private EditText ed_name;
private EditText ed_password;

// 创建一个静态的Context对象,因为Handler是静态的,而且使用到了Context对象,所以这里也要静态的
private static Context context;

// 创建一个静态的Handler对象(静态的可以防止内存泄露,这里不用静态的也可以),用于输出从服务器返回的数据
public static Handler handler = new Handler() {
public void handleMessage(Message msg) {

switch (msg.what) {
case 0:
Toast.makeText(context, "读取流中数据出错", Toast.LENGTH_SHORT).show();
break;
case 1:
Toast.makeText(context, "出现未知错误", Toast.LENGTH_SHORT).show();
break;
case 2:
Toast.makeText(context, "无法连接网络,可能是响应码错误", Toast.LENGTH_SHORT).show();
break;
case 3:
// 吐司弹出服务器的数据
String result = (String) msg.obj;
Toast.makeText(context, result, Toast.LENGTH_SHORT).show();
break;
}
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);

context = getApplicationContext();

ed_name = (EditText) findViewById(R.id.et_name);
ed_password = (EditText) findViewById(R.id.et_password);

Button bt_1 = (Button) findViewById(R.id.bt_1);
Button bt_2 = (Button) findViewById(R.id.bt_2);
Button bt_3 = (Button) findViewById(R.id.bt_3);
Button bt_4 = (Button) findViewById(R.id.bt_4);
Button bt_5 = (Button) findViewById(R.id.bt_5);
Button bt_6 = (Button) findViewById(R.id.bt_6);

bt_1.setOnClickListener(this);
bt_2.setOnClickListener(this);
bt_3.setOnClickListener(this);
bt_4.setOnClickListener(this);
bt_5.setOnClickListener(this);
bt_6.setOnClickListener(this);
}

@Override
public void onClick(View v) {

// 不同的按钮对应处理不同的操作。前三个分别使用不同的框架处理get请求。后三个分别使用不同的框架框架处理post请求
switch (v.getId()) {
case R.id.bt_1:
method_1();
break;
case R.id.bt_2:
method_2();
break;
case R.id.bt_3:
method_3();
break;
case R.id.bt_4:
method_4();
break;
case R.id.bt_5:
method_5();
break;
case R.id.bt_6:
method_6();
break;
}
}

/* 创建一个方法,该方法传入一个输入流,读取流中的书,然后把数据转化为字节数组返回 */
private byte[] getDataFromStream(InputStream is) {

try {
byte[] buffer = new byte[1024];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int len = 0;
while ((len = is.read(buffer)) != -1) {
bos.write(buffer, 0, len);
bos.flush();
}

byte[] result = bos.toByteArray();
is.close();
bos.close();

return result;
} catch (Exception e) {
// 发送数据给主线程,告诉主线程读取流的时候出错
handler.sendEmptyMessage(0);
e.printStackTrace();
}
return null;
}

/** 使用HttpURLConnection框架发送get请求 */
private void method_1() {
// 按钮太多,这里出一个吐司,告诉用户使用的是HttpURLConnection发送GET请求
Toast.makeText(getApplicationContext(), "HttpURLConnection   GET", Toast.LENGTH_SHORT).show();

// 获取输入框中的信息
String name = ed_name.getText().toString();
String password = ed_password.getText().toString();

// 拼接servlet的URL地址.注意,如果提交的数据有中文,需要处理后在凭借。
// 提交的数据需要经过URL编码,英文和数字编码后保持不变,中文会变。
// URLEncoder.encode(name):该编码默认使用utf-8编码。如果要改变,可以使用它的重载方法
// 也可以编码成其他格式,但是必须要与服务器保持编码统一。
final String path = "http://10.12.16.141:8080/Nweb/LoginServlet?name=" + URLEncoder.encode(name) + "&password="
+ password;

// 开启子线程,进行数据的传入
new Thread(new Runnable() {

@Override
public void run() {

try {
URL url = new URL(path);

// 获取HttpURLConnection对象
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

// 设置连接属性并连接
conn.setReadTimeout(5000);
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
conn.connect();

// 判断响应码
if (conn.getResponseCode() == 200) {
InputStream is = conn.getInputStream();

// 读取流中的数据
byte[] data = getDataFromStream(is);

String result = new String(data, "UTF-8");
Message msg = handler.obtainMessage();
msg.what = 3;
msg.obj = result;
handler.sendMessage(msg);
} else {
handler.sendEmptyMessage(2);
}
} catch (Exception e) {
handler.sendEmptyMessage(1);
e.printStackTrace();
} finally {

}
}
}).start();

}

/** 使用HttpClinet框架提交get请求 */
private void method_2() {
Toast.makeText(getApplicationContext(), "HttpClinet   GET", Toast.LENGTH_SHORT).show();
String name = ed_name.getText().toString();
String password = ed_password.getText().toString();

final String path = "http://10.12.16.141:8080/Nweb/LoginServlet?name=" + URLEncoder.encode(name) + "&password="
+ password;

// 开启子线程,进行数据的传入
new Thread(new Runnable() {
@Override
public void run() {
try {
// 1.创建HttpClient对象
HttpClient client = new DefaultHttpClient();

// 2.获取HttpGet
HttpGet httpGet = new HttpGet(path);

// 3.使用HttpClient将HttpGet发送出去(即使用客户端对象将get请求发送出去),得到HttpResponse
HttpResponse response = client.execute(httpGet);

// 4.拿到状态行
StatusLine statusLine = response.getStatusLine();

if (statusLine.getStatusCode() == 200) {
// 拿到相应实体
HttpEntity entity = response.getEntity();

// 拿到输入流
InputStream is = entity.getContent();

byte[] data = getDataFromStream(is);
String result = new String(data, "UTF-8");

Message msg = handler.obtainMessage();
msg.what = 3;
msg.obj = result;
handler.sendMessage(msg);
} else {
handler.sendEmptyMessage(2);
}
} catch (Exception e) {
handler.sendEmptyMessage(1);
e.printStackTrace();
} finally {

}
}
}).start();

}

/** 使用自定义的高度封装的AsyncHttpClient框架提交get请求 */
private void method_3() {
Toast.makeText(getApplicationContext(), "AsyncHttpClient   GET", Toast.LENGTH_SHORT).show();
String name = ed_name.getText().toString();
String password = ed_password.getText().toString();

final String path = "http://10.12.16.141:8080/Nweb/LoginServlet?name=" + URLEncoder.encode(name) + "&password="
+ password;

// 1.创建异步HttpClient
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();

// 2.发送get请求
// 第一个参数是URL对象
// 第二个参数为服务器返回的响应信息
asyncHttpClient.get(path, new GetResponserHandler());

}

// 定义一个内部类,根据异步HttpClinet代码示例,该类继承AsyncHttpResponseHandler。该类的作用是用来处理get请求后服务器返回的信息
class GetResponserHandler extends AsyncHttpResponseHandler {

// 请求服务器成功时(即状态码为200时,系统自动调用该方法)
// 第三个参数 responseBody为服务器返回的信息
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
Toast.makeText(MainActivity.this, new String(responseBody), 1).show();
}

// 请求失败(即状态码不为200,系统调用此方法)
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
Toast.makeText(MainActivity.this, "请求失败", 1).show();
}

}

/** 使用HttpURLConnection框架发送post请求 */
private void method_4() {
Toast.makeText(getApplicationContext(), "HttpURLConnection   POST", Toast.LENGTH_SHORT).show();
final String name = ed_name.getText().toString();
final String password = ed_password.getText().toString();

// 拼接servlet的URL地址。
final String path = "http://10.12.16.141:8080/Nweb/LoginServlet";

// 开启线程,进行数据的传输
new Thread(new Runnable() {

@Override
public void run() {

try {
URL url = new URL(path);

HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(5000);
conn.setConnectTimeout(5000);
conn.setRequestMethod("POST");

// 拼接出要提交的数据的字符串
// 注意,如果提交的数据有中文,需要处理后再拼接。
// 提交的数据需要经过URL编码,英文和数字编码后保持不变,中文会变。
// URLEncoder.encode(name):该编码默认使用utf-8编码。如果要改变,可以使用它的重载方法
String text = "name=" + URLEncoder.encode(name) + "&password=" + password;

// 添加post请求的两行属性
// Content-Type: application/x-www-form-urlencoded
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

// Content-Length:
conn.setRequestProperty("Content-Length", text.length() + "");

// 设置打开输出流,并拿到输出流(一定要写这一句,不然无法向输出流中写入数据)
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();

// 将拼接的字符串写入请求正文中,即使用输出流往服务器提交数据
os.write(text.getBytes());

if (conn.getResponseCode() == 200) {

InputStream is = conn.getInputStream();

// 从输入流获取数据
byte[] data = getDataFromStream(is);

String result = new String(data, "utf-8");

Message message = handler.obtainMessage();
message.what = 3;
message.obj = result;
handler.sendMessage(message);

} else {
handler.sendEmptyMessage(2);
}

} catch (Exception e) {
handler.sendEmptyMessage(1);
e.printStackTrace();
}

}
}).start();
}

/** 使用HttpClinet框架提交post请求 */
private void method_5() {
Toast.makeText(getApplicationContext(), "HttpClinet   POST", Toast.LENGTH_SHORT).show();
final String name = ed_name.getText().toString();
final String password = ed_password.getText().toString();

final String path = "http://10.12.16.141:8080/Nweb/LoginServlet";

new Thread(new Runnable() {

@Override
public void run() {

// 1.创建客户端对象
HttpClient httpClient = new DefaultHttpClient();

// 2.创建post请求对象
HttpPost httpPost = new HttpPost(path);

// 封装from表单要提交的数据
List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();

// 第一个参数是servlet中接收的数据的名称,第二个参数是android布局文件中提价的数据的名称
BasicNameValuePair basicNameValuePair = new BasicNameValuePair("name", name);
list.add(basicNameValuePair);
BasicNameValuePair basicNameValuePair2 = new BasicNameValuePair("password", password);
list.add(basicNameValuePair2);

try {
// 需要提交的数据已经在集合中了,把集合传给实体对象,此处最好设置一下编码,不然可能导致中文乱码。
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "utf-8");

// 设置post请求对象的实体,其实即使把要提交的数据封装到post请求的输出流中
httpPost.setEntity(entity);

// 3.使用客户端发送post请求
HttpResponse httpResponse = httpClient.execute(httpPost);

// 获取响应码
if (httpResponse.getStatusLine().getStatusCode() == 200) {

InputStream is = httpResponse.getEntity().getContent();

// 从输入流获取数据
byte[] data = getDataFromStream(is);
String result = new String(data, "utf-8");

Message message = handler.obtainMessage();
message.what = 3;
message.obj = result;
handler.sendMessage(message);

} else {
handler.sendEmptyMessage(2);
}

} catch (Exception e) {
handler.sendEmptyMessage(1);
e.printStackTrace();
}

}
}).start();

}

/** 使用自定义的高度封装的AsyncHttpClient框架提交post请求 */
private void method_6() {
Toast.makeText(getApplicationContext(), "AsyncHttpClient   POST", Toast.LENGTH_SHORT).show();
String name = ed_name.getText().toString();
String password = ed_password.getText().toString();
final String path = "http://10.12.16.141:8080/Nweb/LoginServlet";

// 1.创建异步HttpClinet
AsyncHttpClient client = new AsyncHttpClient();

// 封装要提交的数据
RequestParams params = new RequestParams();
params.put("name", name);
params.put("password", password);

// 2.发送post请求
client.post(path, params, new PostResponseHandler());

}

// 定义一个内部类,根据异步HttpClinet代码示例,该类继承AsyncHttpResponseHandler。该类的作用是用来处理Post请求后服务器返回的信息
class PostResponseHandler extends AsyncHttpResponseHandler {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
Toast.makeText(MainActivity.this, new String(responseBody), 1).show();
}

@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
Toast.makeText(MainActivity.this, "请求失败", 1).show();
}
}
}


整个应用完成

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐