基本介绍
HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议来访问网络资源。在 JDK 的 java.net 包中已经提供了访问HTTP协议的基本功能:HttpURLConnection。
但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。 除此之外,在Android中,androidSDK中集成了Apache的HttpClient模块,用来提供高效的、最新的、功能丰富的支持 HTTP 协议工具包。
Android有哪些HTTP请求编程形式呢?
java原生的–HttpURLConnection
Apache提供的–HttpClient
他们有什么区别?
我们根据Volley框架的源码,发现它在HTTP请求的使用上是这样的,在Android 2.3及以上版本,使用的是HttpURLConnection,而在Android 2.2及以下版本,使用的是HttpClient。这两种方式都支持HTTPS协议、以流的形式进行上传和下载、配置超时时间、IPv6、以及连接池等功能。
DefaultHttpClient和AndroidHttpClient都是HttpClient具体的实现类,它们都拥有众多的API,而且实现比较稳定,bug数量也很少。但同时也由于HttpClient的API数量过多,使得我们很难在不破坏兼容性的情况下对它进行升级和扩展,所以目前Android团队在提升和优化HttpClient方面的工作态度并不积极。
HttpURLConnection是一种多用途、轻量极的HTTP客户端,使用它来进行HTTP操作可以适用于大多数的应用程序。虽然HttpURLConnection的API提供的比较简单,但是同时这也使得我们可以更加容易地去使用和扩展它。
不过在Android2.2版本之前,HttpURLConnection一直存在着一些令人厌烦的bug。比如说对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效了。那么我们通常的解决办法就是直接禁用掉连接池的功能在Android 2.2版本之前,HttpClient拥有较少的bug,因此使用它是最好的选择。
而在Android2.3版本及以后,HttpURLConnection则是最佳的选择。它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。对于新的应用程序应该更加偏向于使用HttpURLConnection,因为在以后的工作当中我们也会将更多的时间放在优化HttpURLConnection上面。
http请求形式有哪些呢?
网络请求方式可分为get请求,post两种请求方式
GET方式在进行数据请求时,会把数据附加到URL后面传递给服务器,比如常见的:http://XXX.XXX.XXX/XX.jsp ? id=1
POST方式则是将请求的数据放到HTTP请求头中,作为请求头的一部分传入服务器。
所以,在进行HTTP编程前,首先要明确究竟使用的哪种方式进行数据请求。
应用实例
下面我们开始用一个简单的登陆功能来对HttpUrlConnection和HttpClient的交互进行展示,Android端将用户名和密码发送给后台进行验证处理,然后后台针对传来数据解析然后返回给客户端一个登陆的结果。
首先我们需要一个通用的服务器的处理登陆的程序,我们以一个servlet来进行服务器端的处理
———————————————服务器部分————————————————-
- - Servlet登陆 - -
我们首先需要建立一个web工程,然后在工程中创建一个Servlet类:LoginServlet
然后在xml配置文件中配置这个servlet,在这个servlet中我们包含了两种处理形式来分别处理GET和POST
public class LoginServlet extends HttpServlet {
private Map<String, String> map; // 模拟数据库的作用,其中放入用户名和密码
public LoginServlet() {
super();
}
@Override
public void init() throws ServletException {
super.init();
map = new HashMap<String, String>();
map.put("Johnson", "123");
map.put("John", "321");
}
@Override
public void destroy() {
super.destroy();
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
String username = request.getParameter("name");
String password = request.getParameter("password");
boolean isExist = false;
// 模拟查询数据库
for (String name : map.keySet()) {
System.out.println(name+1);
if (name.equals(username)) {
System.out.println(map.get(name)+2);
if (password.equals(map.get(name))) {
System.out.println("对的");
isExist = true;
}
}
}
System.out.println(isExist);
if (isExist == true) {// 用户名存在
String jsonString = "{code : 1}";
out.write(jsonString);
} else {// 用户名或密码错误
String jsonString = "{code : 0} ";
out.write(jsonString);
}
}
}
———————————————客户端部分————————————————–
Android端首先创建一个工程,这个界面只有两个EditText和一个Button,分别用于输入用户名和密码,按钮用于提交请求 以下是界面xml代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical" >
<EditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="用户名"
android:textSize="16sp" />
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:hint="密码"
android:textSize="16sp" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:onClick="login"
android:text="登 陆" />
</LinearLayout>
然后我们就是主要的功能部分代码,代码中有HttpUrlConnectionTool和HttoClientTool就是我们整合的两种不同请求方式的工具,在下面会有分别对应的相关网络工具类代码
- - **MainActivity界面** - -
public class MainActivity extends Activity {
private EditText user;
private EditText password;
private String name;// 记录用户名
private String passwd;// 记录密码
private Map<String, String> mMap;
String url = "http://localhost:8080/LoginServlet/login";// 服务器登陆地址
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
user = (EditText) findViewById(R.id.username);
password = (EditText) findViewById(R.id.password);
}
// 点击登陆
public void login(View view) {
name = user.getText().toString();
passwd = password.getText().toString();
mMap = new HashMap<String, String>();
mMap.put("name", name);
mMap.put("password", passwd);
new MyAsyncTask().execute(url);
}
class MyAsyncTask extends AsyncTask<String, Void, Integer> {
@Override
protected Integer doInBackground(String... params) {
// 以下四个为http的四个请求方法
int code = HttpClientTool.getMethod(params[0], mMap);
// int code = HttpClientTool.postMethod(params[0], mMap);
// int code = HttpUrlConnectionTool.doGet(params[0], mMap);
// int code = HttpUrlConnectionTool.doPost(params[0], mMap);
return code;
}
@Override
protected void onPostExecute(Integer result) {
if (result == 0) {
Toast.makeText(MainActivity.this, "用户名或密码错误", Toast.LENGTH_LONG)
.show();
} else if (result == 1) {
Toast.makeText(MainActivity.this, "登陆成功 ", Toast.LENGTH_LONG)
.show();
} else {
}
super.onPostExecute(result);
}
}
}
- - HttpClient方式 - -
这里我们用HttpClient方式进行网络交互,代码如下
public class HttpClientTool {
/**
* GET方式登陆
*
* @param url
* @param map
* @return
*/
public static int getMethod(String url, Map<String, String> map) {
// code为1登陆成功 0登陆失败
HttpClient httpClient = new DefaultHttpClient();
int code = 0;
StringBuilder builder = new StringBuilder(url + "?");
for (String key : map.keySet()) {
String value = map.get(key);
builder.append(key + "=" + value);
builder.append("&");
}
builder.deleteCharAt(builder.length() - 1);// 去掉最后一个&
String mUrl = builder.toString();
try {
HttpGet httpGet = new HttpGet(mUrl);
HttpResponse response = httpClient.execute(httpGet);
int responseCode = response.getStatusLine().getStatusCode();
if (responseCode == HttpStatus.SC_OK) {
HttpEntity entity = response.getEntity();
// 传回来的是一个json数据
String jsonEntity = EntityUtils.toString(entity);
Log.i("tag",jsonEntity+"---------");
JSONObject jsonObject = new JSONObject(jsonEntity);
code = jsonObject.getInt("code");
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return code;
}
/**
* POST方式登陆
*
* @param url
* @param map
* @return
*/
public static int postMethod(String url, Map<String, String> map) {
// code为1登陆成功 0登陆失败
HttpClient httpClient = new DefaultHttpClient();
int code = 0;
List<NameValuePair> mList = new ArrayList<NameValuePair>();
for (String key : map.keySet()) {
String value = map.get(key);
mList.add(new BasicNameValuePair(key, value));
}
try {
// 使用HttpPost对象设置发送的URL路径
HttpPost httpPost = new HttpPost(url);
// 把请求参数变成请求体部分
UrlEncodedFormEntity uee = new UrlEncodedFormEntity(mList, "utf-8");
// 使用HttpPost对象设置发送的URL路径
httpPost.setEntity(uee);
HttpResponse response = httpClient.execute(httpPost);
int resultCode = response.getStatusLine().getStatusCode();
if (resultCode == HttpStatus.SC_OK) {
HttpEntity entity = response.getEntity();
// 传回来的是一个json数据
String jsonEntity = EntityUtils.toString(entity);
JSONObject jsonObject = new JSONObject(jsonEntity);
code = jsonObject.getInt("code");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return code;
}
}
- - HttpUrlConnection方式 - -
以下是HttpUrlConnection方式进行访问服务器,这样的方式更加灵活和便于自定义
public class HttpUrlConnectionTool {
// get方式
public static int doGet(String mUrl, Map<String, String> map) {
int code = 0;
StringBuilder builder = new StringBuilder(mUrl + "?");
for (String key : map.keySet()) {
String value = map.get(key);
builder.append(key + "=" + value);
builder.append("&");
}
builder.deleteCharAt(builder.length() - 1);// 去掉最后一个&
String finalUrl = builder.toString();
try {
URL url = new URL(finalUrl);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
// 设定请求的方法为"GET",默认是GET
connection.setRequestMethod("GET");
// 设置是否从httpUrlConnection读入,默认情况下是true;
connection.setDoInput(true);
// GET 请求可以使用缓存
connection.setUseCaches(true);
// 设定传送的内容类型是可序列化的java对象
// (如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException)
connection.setRequestProperty("Content-type",
"application/x-java-serialized-object");
// 连接,从上述url.openConnection()至此的配置必须要在connect之前完成,
connection.connect();
BufferedReader br = new BufferedReader(new InputStreamReader(
connection.getInputStream(), "utf-8"));
StringBuilder result = new StringBuilder(); // 接收返回的Json字符串
String line;
while ((line = br.readLine()) != null) {
result.append(line);
}
JSONObject jsonObject = new JSONObject(result.toString());
code = jsonObject.getInt("code");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return code;
}
// post方式
public static int doPost(String mUrl, Map<String, String> map) {
int code = 0;
StringBuilder builder = new StringBuilder();
for (String key : map.keySet()) {
String value = map.get(key);
builder.append(key + "=" + value);
builder.append("&");
}
builder.deleteCharAt(builder.length() - 1);// 去掉最后一个&
String params = builder.toString();
try {
URL url = new URL(mUrl);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setConnectTimeout(5000);
connection.setRequestMethod("POST");
connection.setDoInput(true);
// 设置是否向httpUrlConnection输出,因为这个是post请求,参数要放在http正文内需要设为true,
// 默认情况下是false;
connection.setDoOutput(true);
// post方式不支持缓存
connection.setUseCaches(false);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
connection.getOutputStream(), "utf-8"));
bw.write(params);
bw.flush();
bw.close();
// 调用此方法就不必再使用conn.connect()方法
int responseCode = connection.getResponseCode();
if (responseCode == HttpStatus.SC_OK) {
BufferedReader br = new BufferedReader(new InputStreamReader(
connection.getInputStream(), "utf-8"));
StringBuilder result = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
result.append(line);
}
JSONObject jsonObject = new JSONObject(result.toString());
code = jsonObject.getInt("code");
} else {
Log.i("error", "访问失败");
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return code;
}
}
以上就是Android中对网络访问的两种形式,最后别忘了在Android项目中的配置文件中加入
<uses-permission android:name="android.permission.INTERNET"/>
这样就可以实现简单的登陆效果了