引言
该篇博客主要对Okhttp的几种使用方法做总结,包括get,post,上传文件,下载文件。一.Okhttp重要内容梳理
1.OkHttpClient: OkHttp请求的客户端类,核心地位,很多功能主要靠OkhttpClent来转发和实现,他的创建方法有两种1.1).默认的通过new一个对象来实例化,如:
OkhttpClient okhttpclient=new OkhttpClient();
1.2).通过构建者模式Builder创建,如
OkhttpClient okhttpclient=new OkhttpClient.Builder().build();
1.3).说明:现实中网络情况是比较复杂的,需要考虑的设置一些参数,如设置超时时间,readTimeout也可以通过设置okhttoClient对象来实现,如
OkHttpClient okHttpClient=new OkHttpClient.Builder().readTimeout(5000,TimeUnit.MILLISECONDS)
.build();
2.Request:主要用来设置请求报文类的相关信息,如Url,请求方式以及请求头等。
2.1).默认的通过new一个对象来实例化,与OkhttpClient的创建方法相同,如
Request request=new Request()
2.2).通过构建者模式设置,如
Request request=new Request.Builder().build();
2.3).说明:我们需要给request设置一些参数,如请求地址方式等
Request request=new Request.Builder().post(requestBody).url(“http://xxxx.com”).build();
Request request=new Request.Builder().get().url(“http://xxxx.com”).build();
2.4).补充:post请求方式需要传入RequestBody对象,后面会说。
3.Call:他实际上代表了一个待执行的http请求,可以理解为连接request和response 的一个桥梁。
2.1).创建call对象的方式与okhttpclient和request不同,如:
Call call=okhttpclient.newCall(request);//其中okhttpclient和request是之前创建好的对象
2.2).说明:newCall方法实际上是空的,返回的是RealCall.newCall(request),关于源码分析的详情可以看相关视频。
2.3).同步请求与异步请求
Response response = call.execute();;//同步请求,会阻塞当前线程,直到请求返回结果,reponse是返回结果
call.enqueue(new CallBack());//异步请求,开启子线程执行,不会阻塞当前线程。CallBack是一个回调接口,当请求产生结果时被调用
2.4)关于CallBack
/*改回调在子线程执行,所以不可以在其中更新UI,可以使用runOnUiThread;来更新UI,如下*/
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//onFailure当请求发生异常或请求失败时调用
L.e("onFailure:"+e.getMessage());
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
//请求成功时调用
// InputStream is = response.body().byteStream();获得请求返回的字节流
String res=reponse.body().String();//服务器返回的信息
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(res);
}
});
}
});
4.小结
4.1.一个最简单的Okhttp使用分为三步
4.1.1).创建OkhttpCilent和requset对象
4.1.2).创建Call对象
4.1.3).执行Call对象,发起同步或异步请求并处理返回数据
4.2.同步请求与异步请求的区别:
4.2.1.发起请求时的方法调用不同;
4.2.2.同步阻塞当前线程,异步开启子线程执行,不阻塞当前线程
4.2.3.内部实现:excute()方法将该请求推入执行队列,enqueue()方法则需要经过处理加入准备执行队列,其内部实现有很大的区别。
补充:本篇只对OkhttpClient的使用做说明,其中详细的实现机制如dispatcher分发器,connectpool连接池以及getResponseIncepterChain等重要的机制需要自己去看源码!(也有相关讲解视频,有需要联系我)
二.搭建服务器端
建议:将下载的tomcat,struts放在E盘下,这样就可以参考我的路径配置!5.1.tomcat.struts框架的下载
云盘地址:链接: https://pan.baidu.com/s/1jkYVw6Flm8sLJknn5ZjAXg 提取码: 9wba 复制这段内容后打开百度网盘手机App,操作更方便哦
5.2.Eclipse下新建Web项目,1.File——》2.Dynamic Web project——》3.填写项目名称:Okhttp(可自定义)
5.3.配置tomcat,1.Eclipse下的window按钮——》2.选择Preference——》3.搜索Server——》4.选择runtime environment——》5.点击Add按钮——》6.选择你要配置的tomcat版本——》7.点击next——》8.name不需要修改,修改tomcat installation dir,将你下载好的tomcat包解压,放在适合的位置后,一定要选择最后一个带编号的apache文件夹点进去,如我的路径E:apache-tomcat-7.0.94-windows-x64apache-tomcat-7.0.94,然后点击finsih即可。
5.4.解压struts文件,并将E:struts-2.3.24.1-allstruts-2.3.24.1appsstruts2-blankWEB-INFlib目录下的所有jar包复制到你刚才创建的web项目的WEB-INFlib下,并将E:struts-2.3.24.1-allstruts-2.3.24.1appsstruts2-blankWEB-INFclasses目录下的struts.xml文件复制到你刚才创建的web项目的src下即可,然后打开struts.xml文件,将其中的 两个filtter复制到你web项目的web.xml文件中,两个filtter:
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
如果你的web项目没有web.xml右键你的项目然后选择JavaEE tools——》generate…即可;
然后修改struts.xml文件成如下状态:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<constant name="setruts.devMode" value="true" />
<package name="default" namespace="/" extends="struts-default">
</package>
</struts>
服务器端搭建完毕!
5.5.测试服务器端
1.首先在web端的src目录下新建一个包:com.okhttp,在该包中新建一个UserAction.java文件,代码如下:
package com.okhttp;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
//有些包是这一步不需要导入的可以忽略
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class UserAction extends ActionSupport {
//ActionSupport是框架内提供的一个类,非常便捷
private String username;//用户名
private String password;//密码
public String Login() throws IOException
{
System.out.println(username+" "+password);
//直接打印username和password
return null;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
代码写完以后,我们需要去映射这个方法,打开struts.xml文件,修改成如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<constant name="struts.devMode" value="true" />
<package name="default" namespace="/" extends="struts-default">
<action name="Login" class="com.okhttp.UserAction" method="Login"></action>
</package>
<!--name="Login"是你在浏览器端访问时的名字,class是对应包名,method是指至该class中对应的Login方法,这样就完成了映射 -->
</struts>
然后将web项目运行起来,选择刚才配置的tomcat即可,在浏览器上输入
localhost:8080//项目名/Login?username=xxx&password=123;
观察Eclipse控制台有无输出,有输出说明配置成功,若无输出看日志找错误
三.OkHttp的使用
准备工作:由于我们是在本地方法,在模拟器上不知道localhost是什么,先通过cmd控制台输入ipconfig/all,查询你的localhost地址即是你的Ipv4地址,每一个请求都是通过一个按钮来发起的,所以每一种新的请求方法,都需要新建一个button,添加OnClick="xxxx",并在Activity中创建出来,布局代码不再说明,后面不再做说明6.1.get请求代码
public void Doget(View view) throws IOException {
Request.Builder builder=new Request.Builder();
final Request request = builder.get().url(mBaseUrl+"Login?username=Yang&password=123").build();
//mBaseurl是全局变量即“http://IPv4/项目名/”
//okhttpclient也是全局变量,只需要创建即可,无需其他设置
Call call=okHttpClient.newCall(request);
Response response = call.execute();
//执行后查看Eclipse 控制台的输出,这一步需要允许网络权限,在AndroidManifest.xml文件中添加
// <uses-permission android:name="android.permission.INTERNET"></uses-permission>即可
}
6.2.添加web端的响应代码,即客户端发出请求后,服务器返回响应信息:
将刚才web端的Login()方法修改成如下:
public String Login() throws IOException
{
System.out.println(username+" "+password);
HttpServletResponse response=ServletActionContext.getResponse();
PrintWriter writer=response.getWriter();
writer.write("Login Success!");
writer.flush();
return null;
}
客户端修改成如下:
public void Doget(View view) throws IOException {
Request.Builder builder=new Request.Builder();
final Request request = builder.get().url(mBaseUrl+"Login?username=Yang&password=123").build();
Call call=okHttpClient.newCall(request);
Response response = call.execute();
String res=response.body().String();
Log.d("Response",res);
}
再次发起请求,观察Android logcat下的日志有无Login success!,到这一步已经打通客户端与服务器端的响应!
6.3.Post请求
客户端代码如下:
public void Dopost(View view) throws IOException {
FormBody requestbuilder=new FormBody.Builder().add("username", "Yang")
.add("password", "123456").build();
//FormBody的简单用法,可理解为键值对
Request request=new Request.Builder().post(requestbuilder).url(mBaseUrl+"Login").build();
ExcuteRequest(request);//该方法用来处理返回信息
}
private void ExcuteRequest(Request request) throws IOException {
Call call=okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
L.e("onFailure:"+e.getMessage());
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
final String res=response.body().string();
L.e("onResponse:"+res);
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(res);//在界面上添加了一个textview用来显示响应信息
}
});
}
});
}
6.4.PostString
改动web端,新增加PostString()方法,代码如下:
每次新建方法以后,不要忘记添加该方法的映射,并重新运行web项目
public String PostString() throws IOException
{
HttpServletRequest request=ServletActionContext.getRequest();
ServletInputStream is=request.getInputStream();
//HttpServletRequest 类如果没有被导入,需要手动导入E:apache-tomcat-7.0.94-windows-x64lib目录下的 servlet-api.jar,导入方法1.右键你的项目——》2.build path——》3.configure build path——》4.add External Jars——》5.找到E:apache-tomcat-7.0.94-windows-x64lib的servlet-api.jar文件导入即可
StringBuilder sb=new StringBuilder();
byte[] buf=new byte[1024];
int len=0;
while((len=is.read(buf))!=-1) {
sb.append(new String(buf,0,len));
}
System.out.println(sb.toString());
return null;
}
客户端代码
public void DopostString(View view) throws IOException {
RequestBody requestBody = RequestBody.create("{username:xxx,password:123456789}"
, MediaType.parse("text/plain;charset=utf-8"));
//构建一个requestBody
Request request=new Request.Builder().post(requestBody).url(mBaseUrl+"PostString").build();
ExcuteRequest(request);
}
6.5.PostFile
web端新建postFile方法,别忘了添加映射,重新运行,代码如下
public String PostFile() throws IOException
{
HttpServletRequest request=ServletActionContext.getRequest();
ServletInputStream is=request.getInputStream();
String dir=ServletActionContext.getServletContext().getRealPath("files");
System.out.println(dir+"----------------");
File file=new File(dir,"陈.jpg");
//dir是保存图片的路径
//"陈.jpg"是保存图片的名称,可以打印出来保存的路径
//下面的输出流是基本操作
FileOutputStream fos=new FileOutputStream(file);
int len=0;
byte[] buf=new byte[1024];
while((len=is.read(buf))!=-1) {
fos.write(buf,0,len);
}
fos.flush();
fos.close();
return null;
}
客户端代码:
public void PostFile(View view) throws IOException {
File file=new File(Environment.getExternalStorageDirectory(),"陈.jpg");
//需要在模拟器中存放一张照片,并添加权限
//<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
//还需要再模拟器设置权限中手动打开该客户端项目的权限
if(!file.exists()){
L.e("File not exists!");
//此处的L是自己写的一个方法,可用Log代替,不必在意
return;
}else{
RequestBody requestBody = RequestBody.create(file
, MediaType.parse("application/octet-stream"));
Request request=new Request.Builder().post(requestBody).url(mBaseUrl+"PostFile").build();
ExcuteRequest(request);
}
}
6.6还有上传表单等,以及下载文件,不再单独说明,以下是总的服务器端和客户端代码
web端
package com.okhttp;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class UserAction extends ActionSupport {
private String username;
private String password;
public File mPhoto;
public String mPhotoFileName;
public String UploadInfo() throws IOException
{
if(mPhoto==null) {
System.out.println("Photo not exist!");
}else {
String dir=ServletActionContext.getServletContext().getRealPath("files");
File file=new File(dir,mPhotoFileName);
System.out.println(username+"------------------"+password);
FileUtils.copyFile(mPhoto,file);
}
return null;
}
public String PostFile() throws IOException
{
HttpServletRequest request=ServletActionContext.getRequest();
ServletInputStream is=request.getInputStream();
String dir=ServletActionContext.getServletContext().getRealPath("files");
System.out.println(dir+"----------------");
File file=new File(dir,"陈.jpg");
FileOutputStream fos=new FileOutputStream(file);
int len=0;
byte[] buf=new byte[1024];
while((len=is.read(buf))!=-1) {
fos.write(buf,0,len);
}
fos.flush();
fos.close();
return null;
}
public String PostString() throws IOException
{
HttpServletRequest request=ServletActionContext.getRequest();
ServletInputStream is=request.getInputStream();
StringBuilder sb=new StringBuilder();
byte[] buf=new byte[1024];
int len=0;
while((len=is.read(buf))!=-1) {
sb.append(new String(buf,0,len));
}
System.out.println(sb.toString());
return null;
}
public String Login() throws IOException
{
System.out.println(username+" "+password);
HttpServletResponse response=ServletActionContext.getResponse();
PrintWriter writer=response.getWriter();
writer.write("Login Success!");
writer.flush();
return null;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
struts.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<constant name="struts.devMode" value="true" />
<package name="default" namespace="/" extends="struts-default">
<action name="Login" class="com.okhttp.UserAction" method="Login"></action>
<action name="PostString" class="com.okhttp.UserAction" method="PostString"></action>
<action name="PostFile" class="com.okhttp.UserAction" method="PostFile"></action>
<action name="UploadInfo" class="com.okhttp.UserAction" method="UploadInfo"></action>
</package>
</struts>
OkhttpClientActivity.java
package com.example.yang.crazydemo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import Java.L;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class OkhttpActivity extends AppCompatActivity {
private TextView textView;
private String mBaseUrl="http://47.106.141.161/Okhttp/";
private OkHttpClient okHttpClient=new OkHttpClient();
private File file;
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_okhttp);
textView=findViewById(R.id.text);
file=new File(Environment.getExternalStorageDirectory(),"陈.jpg");
imageView=findViewById(R.id.img);
}
public void Doget(View view) throws IOException {
Request.Builder builder=new Request.Builder();
final Request request = builder.get().url(mBaseUrl+"Login?username=Yang&password=123").build();
//ExcuteRequest(request);
Call call=okHttpClient.newCall(request);
Response response = call.execute();
}
private void ExcuteRequest(Request request) throws IOException {
Call call=okHttpClient.newCall(request);
call.execute();
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
L.e("onFailure:"+e.getMessage());
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
final String res=response.body().string();
L.e("onResponse:"+res);
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(res);
}
});
}
});
}
public void Dopost(View view) throws IOException {
FormBody requestbuilder=new FormBody.Builder().add("username", "Yang")
.add("password", "123456").build();
Request request=new Request.Builder().post(requestbuilder).url(mBaseUrl+"Login").build();
ExcuteRequest(request);
}
public void DopostString(View view) throws IOException {
RequestBody requestBody = RequestBody.create("{username:yang,password:123456789}"
, MediaType.parse("text/plain;char0set=utf-8"));
Request request=new Request.Builder().post(requestBody).url(mBaseUrl+"PostString").build();
ExcuteRequest(request);
}
public void PostFile(View view) throws IOException {
File file=new File(Environment.getExternalStorageDirectory(),"陈.jpg");
//需要在模拟器中存放一张照片,并添加权限
//<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
//还需要再模拟器设置权限中手动打开该客户端项目的权限
if(!file.exists()){
L.e("File not exists!");
//此处的L是自己写的一个方法,可用Log代替,不必在意
return;
}else{
RequestBody requestBody = RequestBody.create(file
, MediaType.parse("application/octet-stream"));
Request request=new Request.Builder().post(requestBody).url(mBaseUrl+"PostFile").build();
ExcuteRequest(request);
}
}
public void doUpload(View view) throws IOException {
//上传表单信息,包括文字和图片
RequestBody requestBody = RequestBody.create(file
, MediaType.parse("application/octet-stream"));
MultipartBody build = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("username", "yang")
.addFormDataPart("password", "yang123")
.addFormDataPart("mPhoto", "Yang.jpg",requestBody).build();
Request request=new Request.Builder().post(build).url(mBaseUrl+"UploadInfo").build();
ExcuteRequest(request);
}
public void doDownload(View view) {
//下载文件
Request.Builder builder=new Request.Builder();
final Request request = builder.get().url(mBaseUrl+"files/Yang.jpg").build();
Call call=okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
L.e("onFailure:"+e.getMessage());
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
InputStream is = response.body().byteStream();
int len=0;
byte[] buf=new byte[128];
File file = new File(Environment.getExternalStorageDirectory(),"Cheng.jpg");
L.e(Environment.getExternalStorageDirectory().toString());
FileOutputStream fileOutputStream = new FileOutputStream(file);
//输出流
while((len=is.read(buf))!=-1){
fileOutputStream.write(buf,0,len);
}
fileOutputStream.flush();
fileOutputStream.close();
is.close();
}
});
}
public void doDownloadImg(View view) {
//将图片显示在Imageview上
Request.Builder builder=new Request.Builder();
final Request request = builder.get().url(mBaseUrl+"files/Yang.jpg").build();
Call call=okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
L.e("onFailure:"+e.getMessage());
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
InputStream is = response.body().byteStream();
final Bitmap bitmap=BitmapFactory.decodeStream(is);
runOnUiThread(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
});
}
});
}
}