Android实战之旅 006Android中的HTTP通信
Posted DaveBobo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android实战之旅 006Android中的HTTP通信相关的知识,希望对你有一定的参考价值。
对于http协议我想很多朋友并不陌生,一次HTTP操作称为一个事务。http中需要掌握的基础知识包括:URL,http三次握手,http请求头信息,http请求的方式,http响应码信息,http协议的特点,TCP/IP四层协议,OSI七层协议,以及http1.0和http1.1区别。这里需要注意的http无连接:限制每一次连接只处理一个请求,服务器处理完客户的请求,并收到客户的应答后,即断开连接。http无状态:协议对于事务处理没有记忆能力,缺少状态意味着如果后续处理需要前面的信息,则它必须重传。基础知识可以参考:http://blog.csdn.net/davebobo/article/details/52728841
开发环境:
android Studio1.5 RC 1
Myeclipse 10
jdk-7u80-windows-x64
apache-tomcat-7.0.69
一、HttpURLConnection的介绍及使用
案例一:http访问百度,WebView展示内容
新建http_01项目,首先我们需要进行网络操作,在AndroidManifest.xml中添加permission权限
<uses-permission android:name="android.permission.INTERNET"/>
activity_main.xml中添加WebView组件
<WebView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/webView"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true" />
由于网络操作是一个耗时操作,我们在线程中执行,创建VisitWeb类继承Thread重写run方法处理网络耗时操作。
package com.davebobo.http_01;
import android.media.tv.TvView;
import android.os.Handler;
import android.webkit.WebView;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Created by DaveBobo on 2016/10/9.
*/
public class VisitWeb extends Thread{
private String url;
private WebView webView;
private Handler handler;
public VisitWeb(String url, WebView webView, Handler handler){
this.url = url;
this.webView = webView;
this.handler = handler;
}
@Override
public void run() {
super.run();
try {
URL httpUrl = new URL(url);
try {
HttpURLConnection conn = (HttpURLConnection)httpUrl.openConnection();
conn.setReadTimeout(5000);//设置超时等待
conn.setRequestMethod("GET");
final StringBuffer sb = new StringBuffer();//缓存
//通过网址回传网页流数据
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String str;
while ((str = reader.readLine())!=null){
sb.append(str);
}
handler.post(new Runnable(){
@Override
public void run() {
webView.loadData(sb.toString(),"text/html;charset=utf-8",null);
}
});
} catch (IOException e) {
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
在MainActivity中查找WebView创建VisitWeb对象调用它的start()方法。
package com.davebobo.http_01;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
private WebView webView;
private Handler handler = new Handler();
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (WebView) findViewById(R.id.webView);
imageView = (ImageView) findViewById(R.id.imageView);
new VisitWeb("https://www.baidu.com/",webView,handler).start();
//new DownImage("http://avatar.csdn.net/3/B/3/1_davebobo.jpg",imageView,handler).start();
}
}
运行模拟器查看效果
创建URL对象,通过HttpURLConnection设置请求的方式,得到读入流放到缓存区中,通过webView加载本地的页面信息。
案例二:通过网络请求下载图片到本地
在activity_main.xml中将WebView设置为隐藏,添加 ImageView
<WebView
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/webView"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true" />
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:id="@+id/imageView"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
创建DownImage继承自Thread
package com.davebobo.http_01;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.Handler;
import android.widget.ImageView;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Created by DaveBobo on 2016/10/9.
*/
public class DownImage extends Thread{
private String url;
private ImageView imageView;
private Handler handler;
public DownImage(String url, ImageView imageView, Handler handler){
this.url = url;
this.imageView = imageView;
this.handler = handler;
}
@Override
public void run() {
super.run();
try {
URL httpUrl = new URL(url);
try {
HttpURLConnection conn = (HttpURLConnection)httpUrl.openConnection();
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
conn.setDoInput(true);
InputStream in = conn.getInputStream();
FileOutputStream out = null;
File downloadFile = null;
String fileName = String.valueOf(System.currentTimeMillis());
//判断SD卡是否存在
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
File parent = Environment.getExternalStorageDirectory();//获取SD目录
downloadFile = new File(parent,fileName);
out = new FileOutputStream(downloadFile);
}
byte[] b = new byte[2*1024];
int len;
if (out!=null){
while ((len = in.read(b))!=-1){
out.write(b,0,len);
}
}
final Bitmap bitmap = BitmapFactory.decodeFile(downloadFile.getAbsolutePath());
handler.post(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
});
} catch (IOException e) {
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
在MainActivity中初始化ImageView组件并调用start()方法。
package com.davebobo.http_01;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
private WebView webView;
private Handler handler = new Handler();
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (WebView) findViewById(R.id.webView);
imageView = (ImageView) findViewById(R.id.imageView);
//new VisitWeb("https://www.baidu.com/",webView,handler).start();
new DownImage("http://avatar.csdn.net/3/B/3/1_davebobo.jpg",imageView,handler).start();
}
}
运行效果
二、通过HttpURLConnection传递post,get参数
1.服务器端
首先我们使用myeclipse创建j2ee WEB项目,项目名称为web
新建MyServlet的servlet程序,重写doGet和doPost方法,为了简单重写一个方法即可。
package com.davebobo.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String name = request.getParameter("name");
String age = request.getParameter("age");
PrintWriter out = response.getWriter();
out.println("name="+name+" age="+age);
System.out.println("name="+name);
System.out.println("age="+age);
}
}
在index.jsp中添加form表单通过action访问servlet
<form action="servlet/MyServlet" method="get">
name:<input type="text" name="name"><br/>
age:<input type="text" name="age"><br/>
submit:<input type="submit" value="submit"><br/>
</form>
运行效果
2 客户端
当我们的服务器端搭建成功后,开始编写客户端,新建一个RegistActivity继承自AppCompatActivity
package com.davebobo.http_01;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
/**
* Created by DaveBobo on 2016/10/26.
*/
public class RegistActivity extends AppCompatActivity {
private EditText name;
private EditText age;
private Button regist;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.regist);
name = (EditText) findViewById(R.id.name);
age = (EditText)findViewById(R.id.age);
regist = (Button) findViewById(R.id.regist);
regist.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String url ="http://192.168.1.100:8080/web/servlet/MyServlet";
new HttpTherad1(url,name.getText().toString(),age.getText().toString()).start();
}
});
}
}
RegistActivity对应的布局文件regist.xml为:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.davebobo.http_01.MainActivity">
<RelativeLayout
android:id="@+id/name_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/name_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerInParent="true"
android:text="name"/>
<EditText
android:layout_toRightOf="@id/name_textView"
android:id="@+id/name"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
<RelativeLayout
android:layout_below="@id/name_layout"
android:id="@+id/age_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/age_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerInParent="true"
android:text="age"/>
<EditText
android:id="@+id/age"
android:layout_toRightOf="@id/age_textView"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
<Button
android:id="@+id/regist"
android:layout_below="@id/age_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="regist"/>
</RelativeLayout>
由于我们需要进行网络操作单独新建一个线程类HttpTherad1编写相关的get和post方法。
package com.davebobo.http_01;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Created by DaveBobo on 2016/10/26.
*/
public class HttpTherad1 extends Thread{
private String url;
private String name;
private String age;
public HttpTherad1(String url,String name,String age){
this.url = url;
this.name = name;
this.age = age;
}
private void doGet(){
url = url+"?name="+name+"&age="+age;//get方式只能通过url进行传参
try {
URL httpUrl = new URL(url);
try {
HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String str;
StringBuffer sb = new StringBuffer();
while ((str =reader.readLine())!=null ){
sb.append(str);
}
System.out.println("result:"+sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
private void doPost(){
try {
URL httpUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();
conn.setRequestMethod("POST");
conn.setReadTimeout(5000);
OutputStream out = conn.getOutputStream();
String content = "name="+name+"&age="+age;
out.write(content.getBytes());
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuffer sb = new StringBuffer();
String str;
while ((str=reader.readLine())!=null){
sb.append(str);
}
System.out.println(sb.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
super.run();
//doGet();
doPost();
}
}
客户端请求get方法 post方法测试:
服务器打印出结果:
由此我们可以看出doGet是通过URL方式进行发送,而doPost是通过OutputStream的方式进行发送。那有什么区别呢?一般地如果发送的实体数据比较少的话我们使用doGet方式进行发送,这种方式对发送的实体数据是有一定的限制的(几K),如果发送的数据量比较大时我们使用doPost。另外通过doGet方式发送我们通过url将数据暴露出来,如果想安全的话也采用doPost通过实体去发送。
三、httpClient的使用
Java给我们提供了一套访问网络的API但不远远足够我们开发应用程序,在这里我们使用httpClient进行GET和POST请求。在API 23中,Google已经移除了Apache HttpClient相关的类 。谷歌推荐使用HttpUrlConnection,如果要继续使用Apache HttpClient,导入相应的jar包并需要在
Eclipse下libs里添加org.apache.http.legacy.jar,
Android studio里在相应的module下的build.gradle中加入如下即可。
导入我们用到的jar包httpclient-4.5.2.jar httpcore-4.4.4.jar
android {
useLibrary 'org.apache.http.legacy'
}
android {
packagingOptions {
exclude 'META-INF/DEPENDENCIES.txt'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE'
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/notice.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/dependencies.txt'
exclude 'META-INF/LGPL2.1'
}
}
新建HttpClientThread继承自Thread
package com.davebobo.http_01;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
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 org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
/**
* Created by DaveBobo on 2016/10/26.
*/
public class HttpClientThread extends Thread{
private String url;
private String name;
private String age;
public HttpClientThread(String url){
this.url=url;
}
public HttpClientThread(String url,String name,String age){
this.url = url;
this.name = name;
this.age = age;
}
private void dohttpClientGet(){
//创建HttpGet对象
HttpGet httpGet = new HttpGet(url);
//创建HttpClient对象
HttpClient client = new DefaultHttpClient();
HttpResponse response;
try {
//发送请求
response = client.execute(httpGet);
//判断类型
if (response.getStatusLine().getStatusCode()== HttpStatus.SC_OK){
//取出服务器返回的数据
String content = EntityUtils.toString(response.getEntity());
System.out.println("content----->"+content);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void doHttpClientPost(){
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
//通过NameValuePair存储数据
ArrayList<NameValuePair> list = new ArrayList<NameValuePair>();
list.add(new BasicNameValuePair("name",name));
list.add(new BasicNameValuePair("age",age));
try {
//设置要发送的数据
post.setEntity(new UrlEncodedFormEntity(list));
try {
HttpResponse response = client.execute(post);
if (response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
String content = EntityUtils.toString(response.getEntity());
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
@Override
public void run() {
//dohttpClientGet();
doHttpClientPost();
}
}
RegistActivity.java中的onCreate方法测试
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.regist);
name = (EditText) findViewById(R.id.name);
age = (EditText)findViewById(R.id.age);
regist = (Button) findViewById(R.id.regist);
regist.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String url ="http://192.168.1.100:8080/web/servlet/MyServlet";
//new HttpTherad1(url,name.getText().toString(),age.getText().toString()).start();
//url = url+"?name="+name.getText().toString()+"&age="+age.getText().toString();
//new HttpClientThread(url).start();
new HttpClientThread(url,name.getText().toString(),age.getText().toString()).start();
}
});
}
四、Http多线程下载和文件上传
案例一:Http多线程下载
首先我们在服务器端拷贝一张图片并重新发布。
新建DownLoadActivity.继承自AppCompatActivity
package com.davebobo.http_01;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
/**
* Created by DaveBobo on 2016/10/26.
*/
public class DownLoadActivity extends AppCompatActivity {
private Button button;
private TextView textView;
private int count =0;
//更新UI操作
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg){
int result = msg.what;
count+=result;
if (count==3){
textView.setText("download success!");
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.download);
button = (Button) findViewById(R.id.button1);
textView = (TextView) findViewById(R.id.textView);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(){
public void run(){
DownLoad load = new DownLoad(handler);
load.downLoadFile("http://192.168.1.100:8080/web/head.jpg");
}
}.start();
}
});
}
}
多线程下载业务处理在DownLoad.java中
package com.davebobo.http_01;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* Created by DaveBobo on 2016/10/26.
*/
public class DownLoad {
private Handler handler;
public DownLoad(Handler handler){
this.handler = handler;
}
//创建线程池
private Executor threadPool = Executors.newFixedThreadPool(3);
static class DownLoadRunnable implements Runnable{
private String url;
private String fileName;
private long start;
private long end;
private Handler handler;
DownLoadRunnable(String url,String fileName,long start,long end,Handler handler){
this.url = url;
this.fileName = fileName;
this.start = start;
this.end = end;
this.handler = handler;
}
@Override
public void run() {
try {
URL httpUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)httpUrl.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
RandomAccessFile access = new RandomAccessFile(new File(fileName),"rwd");
access.seek(start);
InputStream in = conn.getInputStream();
byte[] b=new byte[1024*4];
int len=0;
while ((len = in.read(b))!=-1){
access.write(b,0,len);
}
if (access!=null){
access.close();
}
if (in!=null){
in.close();
}
Message message = new Message();
message.what =1;
handler.sendMessage(message);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void downLoadFile(String url){
try {
URL httpUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)httpUrl.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
/**
* 11/3 3 2
* 第一个线程 0-2
* 第二个线程 3-5
* 第三个线程 6-10
*/
int count = conn.getContentLength();
int block = count/3;
String fileName = getFileName(url);
File parent = Environment.getExternalStorageDirectory();
File fileDownLoad = new File(parent,fileName);
for (int i=0;i<3;i++){
long start = i*block;
long end = (i+1)*block-1;
if (i==2){
end = count;
}
DownLoadRunnable runnable = new DownLoadRunnable(url,fileDownLoad.getAbsolutePath(),start,end,handler);
threadPool.execute(runnable);
; }
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public String getFileName(String url){
return url.substring(url.lastIndexOf("/")+1);
}
}
布局配置文件很简单
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.davebobo.http_01.MainActivity">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerInParent="true"
android:text="Button"/>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
/>
</RelativeLayout>
在AndroidManifest.xml中配置默认加载的Activity
<activity android:name=".DownLoadActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
运行测试结果
知识总结:
1.Http协议字段Range “bytes=”+start+"-'+end
2.RandomAccessFile设置写入的位置
3.开启线程发送网络请求
案例二:http文件上传
服务器端:
在这里我们需要用到servlet3.0的新特性,不需要添加额外的jar包,servlet3.0对文件的操作做了很好的支持。开发Servlet3的程序需要一定的环境支持。Servlet3是Java EE6规范的一部分,MyEclipse10和Tomcat7都提供了对Java EE6规范的支持。Tomcat需要Tomcat7才支持Java EE6,Tomcat7需要使用JDK6。
使用Myeclipse新建servlet命名为AnnotationUpload
对上图进行如下操作:如果要使用Servlet3.0新特性——采用注释的方式该servlet接受的请求路径,则取消上图被红框框定的复选框(取消后web.xml文件中将不会含有创建的Servlet的一些配置信息,此处取消该复选选中项);否则直接点击“Finish”按钮即可。至此3.0版的Servlet创建成功。将该Servlet修改为如下代码:package com.davebobo.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
/**
* 使用注解描述Servlet
* @author DaveBobo
*/
/**
* 注解WebServlet用来描述一个Servlet
* 属性name描述Servlet的名字,可选
* 属性urlPatterns定义访问的URL,或者使用属性value定义访问的URL.(定义访问的URL是必选属性)
*/
@WebServlet(name="AnnotationUpload",urlPatterns="/AnnotationUpload")
@MultipartConfig(
location = "D:\\\\"
)
public class AnnotationUpload extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Part part = request.getPart("file");
part.write("upload.jpg");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.print("upload success");
System.out.println("upload success");
}
}
新建upload.jsp
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%
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>My JSP 'upload.jsp' starting page</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">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<form action="AnnotationUpload" method="post" enctype="multipart/form-data">
<input type ="file" name="file"/><br>
<input type="submit" value="submit"/><br>
</form>
</body>
</html>
运行测试图片传到指定文件夹中。
客户端:
UploadThread.java
package com.davebobo.http_01;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Created by DaveBobo on 2016/10/26.
*/
public class UploadThread extends Thread{
private String fileName;
private String url;
public UploadThread(String url,String fileName){
this.url = url;
this.fileName = fileName;
}
@Override
public void run() {
//上传表单分割线的描述符
String boundary = "---------------------------7e01ee305f069a"; //Content-Type
String reqCon = "-----------------------------7e01ee305f069a"; //请求正文比Content-Type多两个-
String prefix ="--";
String end="\\r\\n";
try {
URL httpUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + boundary);
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
out.writeBytes(prefix+boundary+end);
out.writeBytes("Content-Disposition: form-data;"+
"name=\\"file\\";filename=\\""+"head.jpg"+"\\""+end);//实体数据
out.writeBytes(end);
FileInputStream fileInputStream = new FileInputStream(new File(fileName));
byte[] b = new byte[1024*4];
int len;
while ((len=fileInputStream.read(b))!=-1){
out.write(b,0, len);
}
out.writeBytes(end);
out.writeBytes(prefix + boundary + prefix + end);
out.flush();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuffer sb = new StringBuffer();
String str;
while ((str= reader.readLine())!=null){
sb.append(str);
System.out.println("respose:"+sb.toString());
if (out!=null){
out.close();
}
if (reader!=null){
reader.close();
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这儿需要注意我们拼写上传表单分割线的描述符时,需要使用IE的开发人员工具。
UploadActivity.java
package com.davebobo.http_01;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import java.io.File;
/**
* Created by DaveBobo on 2016/10/27.
*/
public class UploadActivity extends AppCompatActivity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.upload);
button = (Button) findViewById(R.id.button2);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String url="http://192.168.1.100:8080/web/AnnotationUpload";
File file = Environment.getExternalStorageDirectory();
File fileAbs = new File(file,"head.jpg");
String fileName=fileAbs.getAbsolutePath();
UploadThread thread = new UploadThread(url,fileName);
thread.start();
}
});
}
}
布局文件upload.xml,就一个button
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
android:id="@+id/button2" />
</LinearLayout>
修改默认Activity为UploadActivity,运行程序成功。
httpclient简单实现
这里我们要将httpmime-4.5.2.jar包导入工程,修改UploadThread.java为
package com.davebobo.http_01;
import android.os.Environment;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Created by DaveBobo on 2016/10/26.
*/
public class UploadThread extends Thread{
private String fileName;
private String url;
public UploadThread(String url,String fileName){
this.url = url;
this.fileName = fileName;
}
private void httpUpload(){
//上传表单分割线的描述符
String boundary = "---------------------------7e01ee305f069a"; //Content-Type
String reqCon = "-----------------------------7e01ee305f069a"; //请求正文比Content-Type多两个-
String prefix ="--";
String end="\\r\\n";
try {
URL httpUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + boundary);
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
out.writeBytes(prefix+boundary+end);
out.writeBytes("Content-Disposition: form-data;"+
"name=\\"file\\";filename=\\""+"head.jpg"+"\\""+end);//实体数据
out.writeBytes(end);
FileInputStream fileInputStream = new FileInputStream(new File(fileName));
byte[] b = new byte[1024*4];
int len;
while ((len=fileInputStream.read(b))!=-1){
out.write(b,0, len);
}
out.writeBytes(end);
out.writeBytes(prefix + boundary + prefix + end);
out.flush();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuffer sb = new StringBuffer();
String str;
while ((str= reader.readLine())!=null){
sb.append(str);
System.out.println("respose:"+sb.toString());
if (out!=null){
out.close();
}
if (reader!=null){
reader.close();
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void uploadHttpClient(){
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
MultipartEntity muti = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
File parent = Environment.getExternalStorageDirectory();
File fileAbs = new File(parent,"head.jpg");
FileBody fileBody = new FileBody(fileAbs);
muti.addPart("file", fileBody);
post.setEntity(muti);
try {
HttpResponse response = client.execute(post);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
System.out.println(EntityUtils.toString(response.getEntity()));
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
uploadHttpClient();
}
}
在这里有一点小插曲,我使用的httpClient版本为httpcomponents-client-4.5.2,Android Studio提示错误:
10-27 10:33:06.980 24750-24826/com.davebobo.http_01 E/AndroidRuntime:
FATAL EXCEPTION: Thread-249
Process: com.davebobo.http_01, PID: 24750
java.lang.NoSuchFieldError: No static field INSTANCE of type Lorg/apache/http/message/BasicHeaderValueFormatter; in class Lorg/apache/http/message
/BasicHeaderValueFormatter; or its superclasses (declaration of 'org.apache.http.message.BasicHeaderValueFormatter'
解决方式:下载使用
httpclient-4.3.1即可。
替换为httpclient-4.3.1后测试运行成功。
【Android实战之旅 006】Android中的HTTP通信 配套的资源下载
以上是关于Android实战之旅 006Android中的HTTP通信的主要内容,如果未能解决你的问题,请参考以下文章
我的Android进阶之旅Android Studio 添加新的.Cpp和.h文件之后,代码不高亮,代码不可跳转的问题,写代码也没有提示
我的Android进阶之旅NDK开发之CMake自定义搜索规则,减少每次都需要配置.cpp和.h的工作量
我的Android进阶之旅NDK开发之CMake自定义搜索规则,减少每次都需要配置.cpp和.h的工作量
我的OpenGL学习进阶之旅强烈推荐一款强大的 Android OpenGL ES 调试工具 GAPID并展示实战操作演练一步一步看如何使用GAPID调试工具
我的OpenGL学习进阶之旅解决Android OpenGL ES 调试工具 GAPID 无法识别Android设备的问题
我的OpenGL学习进阶之旅解决Android OpenGL ES 调试工具 GAPID 无法识别Android设备的问题