使用okhttp下载文件 、传统方式下载文件,简介okhttp使用(Java)

说明:

01:使用okhttp下载文件(NIO)
02:传统的URLConnection下载文件
03:说明下okhttp
04:个人见解(Java):在文件下载,和登录用到okhttp较多。在Android使用:小编是个小白

1 使用okhttp下载文件:

  1. 引入okhttp3的依赖
<!--okhttp-->
 <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>okhttp</artifactId>
      <version>3.14.9</version>
 </dependency>
  1. 封装下okhttp
import coms.common.http.RetryIntercepter;
import coms.common.sys.Usual;
import okhttp3.*;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * HttpUtil封装,异步连接池模式
 */
public class HttpUtil {
    /**
     * Http连接超时时间
     */
    private static final int minCONNECT_TIMEOUT = 3000;
    /**
     * Http 写入超时时间
     */
    private static final int minWRITE_TIMEOUT = 3000;
    /**
     * Http Read超时时间
     */
    private static final int minREAD_TIMEOUT = 3000;
    /**
     * Http Async Call Timeout
     */
    private static final int minCall_TIMEOUT = 3000;
    /**
     * Http连接池
     */
    private static final int connectionPoolSize = 1000;
//    /**
//     * 静态Http请求池
//     */
//    private static OkHttpClient client=null;
    /**
     * 静态连接池对象
     */
    private static ConnectionPool mConnectionPool=new ConnectionPool(connectionPoolSize, 30, TimeUnit.MINUTES);
    //executor = new ThreadPoolExecutor(0, 2147483647, ...这个是静态的,21亿连接数量
//    private static RealConnectionPool mConnectionPool=new RealConnectionPool(connectionPoolSize, 30, TimeUnit.MINUTES);
    /**
     * ContentType
     */
    private static final String ContentType="application/json;charset=utf-8";
    /**
     * AcceptType
     */
    private static final String AcceptType="application/json;charset=utf-8";
    /**
     * Content-Type
     */
    private static final MediaType MediaType_ContentType = MediaType.parse(ContentType);

    /**
     * 获取Http Client对象
     * 降低连接时间
     * @return
     */
    public static OkHttpClient getHttpClient(){
        OkHttpClient client = new OkHttpClient.Builder()
//                .addInterceptor(new RetryIntercepter(3))//重试3次
//                .addInterceptor(new GzipRequestInterceptor())//gzip压缩
                .connectTimeout(minCONNECT_TIMEOUT, TimeUnit.MILLISECONDS) //连接超时
                .readTimeout(minREAD_TIMEOUT, TimeUnit.MILLISECONDS) //读取超时
                .writeTimeout(minWRITE_TIMEOUT, TimeUnit.MILLISECONDS) //写超时
                .callTimeout(minCall_TIMEOUT, TimeUnit.MILLISECONDS)
                // okhttp默认使用的RealConnectionPool初始化线程数==2147483647,在服务端会导致大量线程TIMED_WAITING
                //ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue(), Util.threadFactory("OkHttp ConnectionPool", true));
                .connectionPool(mConnectionPool)
                .build();
        return client;
    }
  1. 使用okhttp下载百度logo
//import java.nio.file.*;

public static void main(String[] args) {
		//百度的Logo
        String imgUrl = "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png";
        try {
            OkHttpClient client = HttpUtil.getHttpClient();
            Request request = new Request.Builder()
                    //访问路径
                    .url(imgUrl)
                    .build();
            Response response = null;
            response = client.newCall(request).execute();
            //转化成byte数组
            byte[] bytes = response.body().bytes();
            //本地文件夹目录(下载位置)
            String folder = "D:/q/w/e/r/";
            //切割出图片名称==》PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png
            String filename = StringUtils.substringAfterLast(imgUrl, "/");
            Path folderPath = Paths.get(folder);
            boolean desk = Files.exists(folderPath);
            if (!desk) {
                //不存在文件夹 => 创建
                Files.createDirectories(folderPath);
            }
            //完整图片路径==》D:/q/w/e/r/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png
            Path filePath = Paths.get(folder + filename);
            boolean exists = Files.exists(filePath, LinkOption.NOFOLLOW_LINKS);
            if (!exists) {
                //不存在文件 => 创建
                Files.write(filePath, bytes, StandardOpenOption.CREATE);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
  1. 效果
    使用okhttp下载文件 、传统方式下载文件,简介okhttp使用(Java)_第1张图片

2 传统的URLConnection下载文件:

  1. demo
	//import java.net.URL;
    //import java.net.URLConnection;
    
    public void download() {
        String downLoadUrl = "https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png";
        try {
            // 构造URL
            URL url = new URL(downLoadUrl);
            // 打开连接
            URLConnection con = url.openConnection();
            // 输入流
            InputStream is = con.getInputStream();
            // 1K的数据缓冲
            byte[] bs = new byte[1024];
            // 读取到的数据长度
            int len;
            //图片的完整路径
            String filename = "D:/a/b/1.jpg";
            // 输出的文件流
            File file = new File(filename);
            //是否存在目录
            isChartPathExist("D:/a/b/");
            FileOutputStream os = new FileOutputStream(file, true);
            // 开始读取
            while ((len = is.read(bs)) != -1) {
                os.write(bs, 0, len);
            }
            // 完毕,关闭所有链接
            os.close();
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //java判断指定路径文件夹是否存在,若不存在则创建新的文件夹
    private static void isChartPathExist(String dirPath) {
        File file = new File(dirPath);
        if (!file.exists()) {
            file.mkdirs();
        }
    }
  1. 效果
    使用okhttp下载文件 、传统方式下载文件,简介okhttp使用(Java)_第2张图片

3 okhttp简介:

1. 说明:

HTTP是现代应用常用的一种交换数据和媒体的网络方式,高效地使用HTTP能让资源加载更快,节省带宽。OkHttp是一个高效的HTTP客户端,它有以下默认特性:

  • 支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接
  • 连接池减少请求延时
  • 透明的GZIP压缩减少响应数据的大小
  • 缓存响应内容,避免一些完全重复的请求

2. 使用okhttp来访问请求(GET),是使用 .string()

 //例如:
 OkHttpClient client = HttpUtil.getHttpClient();
 Request request = new Request.Builder()
          .addHeader("访求球头")
          .url("访问地址")
          .build();
          //默认get方法
  Response response = client.newCall(request).execute();
  result = response.body().string();
  //输出json(string)

3. okhttp的其他基本使用-demo

01、同步get请求

  /**
     * 同步get请求
     */
     //import org.junit.jupiter.api.Test;
    @Test
    public void syncGet01() throws IOException {
        String urlBaidu = "http://www.baidu.com/";
        OkHttpClient okHttpClient = new OkHttpClient(); // 创建OkHttpClient对象
        Request request = new Request.Builder().url(urlBaidu).build(); // 创建一个请求
        Response response = okHttpClient.newCall(request).execute(); // 返回实体
        if (response.isSuccessful()) { // 判断是否成功
            /**
             * 获取返回的数据,可通过response.body().string()获取,默认返回的是utf-8格式;
             * string()适用于获取小数据信息,如果返回的数据超过1M,建议使用stream()获取返回的数据,
             * 因为string() 方法会将整个文档加载到内存中
             */
            System.out.println(response.body().string()); // 打印数据
        } else {
            System.out.println("失败"); // 链接失败
        }
    }

02、亦步get请求

  /**
     * 异步Get请求
     */
    @Test
    public void asyncGet02() {
        String urlBaidu = "http://www.baidu.com/";
        // 创建OkHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
        // 创建一个请求
        Request request = new Request.Builder().url(urlBaidu).build();
        // 回调
        okHttpClient.newCall(request).enqueue(new Callback() {
            public void onResponse(Call call, Response response)  {
                // 请求成功调用,该回调在子线程
                try {
                    System.out.println("ok");
                    String result = response.body().string();
                    System.out.println(result);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            public void onFailure(Call call, IOException e) {
                // 请求失败调用
                System.out.println(e.getMessage());
            }
        });
       //测试时候,保证主线程活着。
       Thread.sleep(1000000);
    }

03、post提交表单数据

/**
     * Post提交表单
     */
    public  void asyncPost_Form() {
        //表单参数
        String name = "";
        //访问地址
        String url = "";
        // OkHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
        //设置数据
        RequestBody formBody = new FormBody.Builder()
                //表单键值对
                .add("name", name)
                .build();
        // post请求
        Request request = new Request
                .Builder()
                .url(url)
                .post(formBody)
                .build();
        // 回调
        okHttpClient.newCall(request).enqueue(new Callback() {
            public void onResponse(Call call, Response response) throws IOException {
                //成功后的回调
                System.out.println(response.body().string());
            }

            public void onFailure(Call call, IOException e) {
                //失败后的回调
                System.out.println(e.getMessage());
            }
        });
    }

04、post提交字符串

 /**
     * Post提交字符串
     */
    @Test
    public  void post_StringParam(){
        MediaType MEDIA_TYPE = MediaType.parse("text/text; charset=utf-8");
        // 请求链接
        String url = "";
        // OkHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
        String string = "name=zhangsan"; // 要发送的字符串
        /**
         * RequestBody.create(MEDIA_TYPE, string)
         * 第二个参数可以分别为:byte[],byteString,File,String。
         */
        Request request = new Request.Builder()
                //地址
                .url(url)
                //参数
                .post(RequestBody.create(MEDIA_TYPE,string))
                .build();
        okHttpClient.newCall(request).enqueue(new Callback() {
            //成功
            public void onResponse(Call call, Response response) throws IOException {
                System.out.println(response.body().string());
                //这里可以把string转成json
                //jackson,gson...
                /**
                 * 步骤
				 * 创建一个字段对应的实体类Vo
				 * gson的方式-> gson.fromJson(response.body().string(), 实体类.class)
				 */
            }
            //失败
            public void onFailure(Call call, IOException e) {
                System.out.println(e.getMessage());
            }
        });
    }

最后在附上一个示例

	/**
     * 使用用例
     * @param args
     */
    public static void main(String[] args) throws InterruptedException {
        //测试地址
        String mUrl="";
        //测试数据
        //TODO: 建议byte[]直接传输,避免Base64数据长度及Chartset编码问题
        byte[] mData=new byte[0];
        String mDataStr="测试是大法师大法是";
        mData=Usual.toBytes(mDataStr);
        
        //getHttpClient()是文章开头封装那个okhttp的方法
        OkHttpClient client = getHttpClient();
        
        //可以为空
        RequestBody body = RequestBody.create(null, mData);
        //在Request中统一设置Header
        //如果Request的header中用户加了header("Accept-Encoding")的话,那么Okhttp不会帮你处理Gzip的解压,需要你自己去处理
        Request request = new Request.Builder()
                .addHeader("Content-Type",ContentType)
                .addHeader("Accept",AcceptType)
//                .addHeader("Accept-Encoding", "gzip")
                .addHeader("Connection","keep-alive")
                .cacheControl(new CacheControl.Builder().noCache().build())     //不做缓存
                .url(mUrl)
                .post(body)                                                     //这里指定了POST
                .build();
        Call call = client.newCall(request);

        //这里定义异步返回后,同步参数

        //TODO: 建议模式 A->自己->C,并顺序返回情况
//        //同步调用
//        try{
//            Response response = call.execute();
//        }catch(IOException exp){
//
//        }
//        finally{
//
//        }

        //TODO: 建议模式 自己->[C,并返回情况A]->自己->C并返回自己;
        //TODO: Android不受该影响
        
        //异步回调
        Lock cht_stLock = new ReentrantLock();
        final TestBean mBean=new TestBean();

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
//                log.error(e.getMessage());
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //TODO: 建议byte[]直接回传,避免Base64数据长度及Chartset编码问题
                //Stream处理用例,使用pipe管道
//                mReturnData=Streams.readAll(response.body().byteStream());
                //默认编码处理用例
//                String result = response.body().string();
//                log.info(result);
                byte[] mReturnData=new byte[0];
                //byte[]处理用例
                mReturnData=response.body().bytes();
                if(Usual.isNullOrZeroBytes(mReturnData)==false){
                    String result =Usual.fromBytes(mReturnData);
                }
                mBean.setByteData(mReturnData);

                //最后再设置curState
                cht_stLock.lock();
                try{
                    mBean.setCurState(true);
                }finally{
                    cht_stLock.unlock();
                }
            }
        });

        //TODO: A->自己->C,并顺序返回情况,使用final TestBean方式
        //阻塞进行等待
        while(mBean.getCurState()!=true){
            Thread.sleep(30);
        }
        //返回后,可以同步返回,其他调用的Http

    }
//=================================================================================
	//实体类
    public class TestBean {
    private String strData;
    private byte[] byteData;
    private Boolean curState;
	//省略get/set。。。
}

完结

你可能感兴趣的:(大杂烩,java,http,okhttp,文件下载)