安卓Http协议学习(详细)

41 篇文章 2 订阅
27 篇文章 0 订阅

HTTP协议

  • http协议就是超文本传输协议;
  • 协议是约定的意思,内容是http相关的格式;
  • http协议是基于TCP/IP协议之上的应用层协议

流程:客户端发起请求,服务器端响应请求

1.http的八种请求方式:

  • get //请求
  • post //提交
  • put //更新
  • delete //删除
  • head
  • trace
  • options
  • connect

2.http 状态码

类别原因短语
1XXInformational(信息性状态码)接受的请求正在处理
2XXSuccess(成功状态码)请求正常处理完毕
3XXRedirection(重定向状态码)需要进行附加操作以完成请求
4XXClient Error(客户端错误状态码)服务器无法处理请求
5XXServer Error(服务器错误状态码)服务器处理请求出错

3.基于http协议使用JAVAapi来获取数据

1.创建一个按钮;
2.在.java文件中编写代码;
private static final String TAG = "MainActivity";

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

    //java API获取json
    public void loadJson(View view){
        //不能在主线程中运行,必须新开一个线程
        new Thread(){
            @Override
            public void run() {
                //try-catch捕捉异常
                try {
                    //首先获取一个要获取数据的URL
                    URL url = new URL("https://wanandroid.com/wxarticle/chapters/json ");
                    //设置一个连接
                    HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
                    //设置连接时间
                    httpURLConnection.setConnectTimeout(10000);
                    //这一步很重要,设置连接方式(有八种连接方式)
                    httpURLConnection.setRequestMethod("GET");
                    //设置语言和时区
                    httpURLConnection.setRequestProperty("Accept-language","zh-CN,zh;q=0.9");
                    //建立连接
                    httpURLConnection.connect();
                    //结果码
                    int code = httpURLConnection.getResponseCode();
                    //如果结果码是200,说明正常访问
                    if (code == 200){
                        Map<String, List<String>> headerFields = httpURLConnection.getHeaderFields();
                        Set<Map.Entry<String, List<String>>> entries = headerFields.entrySet();
                        //foreach输出获取到的内容
                        for (Map.Entry<String,List<String>> entry: entries) {
                            Log.d(TAG,entry.getKey()+" == "+entry.getValue());
                        }
                        //使用输入流来读取获取到json文件的内容
                        InputStream inputStream = httpURLConnection.getInputStream();
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                        String line = bufferedReader.readLine();
                        Log.d(TAG, "run: "+line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

代码详解请看注释

3.处理返回的数据
1.修改主活动xml文件,最上面是按钮,点击后会在下方RecycleView中显示接收到的数据;
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="load json!"
        android:textAllCaps="false"
        android:onClick="loadJson" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/result_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
2.设置一个类来处理接收到的json数据,使用插件GsonForMat一键解析;
public class GetTextItem {

    private List<DataDTO> data;
    private Integer errorCode;
    private String errorMsg;
    public static class DataDTO {
        private List<?> children;
        private Integer courseId;
        private Integer id;
        private String name;
        private Integer order;
        private Integer parentChapterId;
        private Boolean userControlSetTop;
        private Integer visible;
        public List<?> getChildren() {
            return children;
        }
        public void setChildren(List<?> children) {
            this.children = children;
        }
        public Integer getCourseId() {
            return courseId;
        }
        public void setCourseId(Integer courseId) {
            this.courseId = courseId;
        }
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Integer getOrder() {
            return order;
        }
        public void setOrder(Integer order) {
            this.order = order;
        }
        public Integer getParentChapterId() {
            return parentChapterId;
        }
        public void setParentChapterId(Integer parentChapterId) {
            this.parentChapterId = parentChapterId;
        }
        public Boolean getUserControlSetTop() {
            return userControlSetTop;
        }
        public void setUserControlSetTop(Boolean userControlSetTop) {
            this.userControlSetTop = userControlSetTop;
        }
        public Integer getVisible() {
            return visible;
        }
        public void setVisible(Integer visible) {
            this.visible = visible;
        }
    }
    public List<DataDTO> getData() {
        return data;
    }
    public void setData(List<DataDTO> data) {
        this.data = data;
    }
    public Integer getErrorCode() {
        return errorCode;
    }
    public void setErrorCode(Integer errorCode) {
        this.errorCode = errorCode;
    }
    public String getErrorMsg() {
        return errorMsg;
    }
    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }
}

3.设置RecycleView的数据适配器;
public class GetResultListAdapter extends RecyclerView.Adapter<GetResultListAdapter.InnerHolder> {
    private List<GetTextItem.DataDTO> mdata = new ArrayList<>();
    //设置数据
    public void setData(GetTextItem getTextItem) {
        //调用此方法后先清空,然后再添加数据
        mdata.clear();
        mdata.addAll(getTextItem.getData());
        notifyDataSetChanged();
    }

    public class InnerHolder extends RecyclerView.ViewHolder {
        public InnerHolder(@NonNull  View itemView) {
            super(itemView);
        }
    }

    @Override
    //绑定布局(每个列表的样式布局)
    public InnerHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_get_text, parent, false);
        return new InnerHolder(itemView);
    }

    @Override
    //绑定控件,然后设置TextView
    public void onBindViewHolder(@NonNull GetResultListAdapter.InnerHolder holder, int position) {
        View itemView = holder.itemView;
        //绑定控件
        TextView courseId = itemView.findViewById(R.id.nameid);
        //获取位置
        GetTextItem.DataDTO dataDTO = mdata.get(position);
        //设置值
        courseId.setText(dataDTO.getName());
    }

    @Override
    public int getItemCount() {
        return mdata.size();
    }

}
4.添加一个布局,为每个子项的样式
<?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="wrap_content"
    android:orientation="horizontal">

    <ImageView
        android:layout_width="90dp"
        android:layout_height="90dp"
        android:background="#03A9F4"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:id="@+id/nameid"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="名字"
            android:layout_margin="10dp"
            android:textSize="18sp"/>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_marginTop="15dp">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="课程id"
                android:textSize="16sp"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="id"
                android:textSize="18sp"
                android:layout_marginLeft="50dp"/>
        </LinearLayout>
    </LinearLayout>
</LinearLayout>
5.修改主活动.java文件
public class MainActivity extends AppCompatActivity {


    private static final String TAG = "MainActivity";
    private GetResultListAdapter madapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    //绑定控件方法
    private void initView() {
        RecyclerView recyclerView = this.findViewById(R.id.result_list);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        //把每个RecycleView设置一个分割线
        recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
            @Override
            public void getItemOffsets(@NonNull  Rect outRect, int itemPosition, @NonNull  RecyclerView parent) {
                outRect.top = 5;
                outRect.bottom = 5;
            }
        });
        madapter = new GetResultListAdapter();
        recyclerView.setAdapter(madapter);
    }

    //java API获取json
    public void loadJson(View view){
        //不能在主线程中运行,必须新开一个线程
        new Thread(){
            @Override
            public void run() {
                //try-catch捕捉异常
                try {
                    //首先获取一个要获取数据的URL
                    URL url = new URL("https://wanandroid.com/wxarticle/chapters/json ");
                    //设置一个连接
                    HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
                    //设置连接时间
                    httpURLConnection.setConnectTimeout(10000);
                    //这一步很重要,设置连接方式(有八种连接方式)
                    httpURLConnection.setRequestMethod("GET");
                    //设置语言和时区
                    httpURLConnection.setRequestProperty("Accept-language","zh-CN,zh;q=0.9");
                    //建立连接
                    httpURLConnection.connect();
                    //结果码
                    int code = httpURLConnection.getResponseCode();
                    //如果结果码是200,说明正常访问
                    if (code == 200){
                        Map<String, List<String>> headerFields = httpURLConnection.getHeaderFields();
                        Set<Map.Entry<String, List<String>>> entries = headerFields.entrySet();
                        //foreach输出获取到的内容
                        for (Map.Entry<String,List<String>> entry: entries) {
                            Log.d(TAG,entry.getKey()+" == "+entry.getValue());
                        }
                        //使用输入流来读取获取到json文件的内容
                        InputStream inputStream = httpURLConnection.getInputStream();
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                        String json = bufferedReader.readLine();

                        //Gosn解析json文件
                        Gson gson = new Gson();
                        GetTextItem getTextItem = gson.fromJson(json, GetTextItem.class);
                        //在UI上面显示出来
                        updateUI(getTextItem);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
    //更新UI不能在子线程里面,只能在UI线程里面更新
        private void updateUI(final GetTextItem getTextItem) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                madapter.setData(getTextItem);
            }
        });
    }
}

最终实现效果:点击按钮后会将从服务器接收到的数据在UI上显示出来

4.api 27之后不能直接访问http协议的解决办法

1.直接在manifest中配置一个文件
android:usesCleartextTraffic="true"
2.在res/xml文件夹下创建名为network-Security-Config的xml文件
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

然后在manifest文件中配置

android:networkSecurityConfig="@xml/network_security_config"

5.使用javaAPI请求图片内容

1.创建一个新的活动用来加载图片;
2.在主活动xml文件中添加按钮和图片控件;
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activity.PicLoadActivity"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="loadPic"
        android:textAllCaps="false"
        android:onClick="LoadPic"
        tools:ignore="OnClick" />

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/result_image"/>

</LinearLayout>

点击按钮,下方显示从服务器拿到的图片

3.在.java文件中编写代码
public class PicLoadActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pic_load);
    }

    //加载图片的方法,在一个新线程里面操作
    public void LoadPic(View view){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //实例化URL对象时参数是图片的网址
                    URL url = new URL("https://wanandroid.com/resources/image/pc/logo.png");
                    HttpURLConnection connection = (HttpURLConnection)url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(10000);
                    connection.setRequestProperty("Accept-language","zh-CN,zh;q=0.9");
                    connection.connect();
                    int response = connection.getResponseCode();
                    if(response == 200){
                        //获取图片输入流
                        InputStream inputStream = connection.getInputStream();
                        //把流转成位图
                        final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                        //更新UI时必须在主线程内,使用runOnUiThread()方法进入主线程
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                ImageView imageView = findViewById(R.id.result_image);
                                imageView.setImageBitmap(bitmap);
                            }
                        });
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
4.效果图

6.加载大图片处理(面试题)

1.错误处理方法(很常见)
public void LoadPic(View view){
        new Thread(new Runnable() {
            @Override
            public void run() {
                //获取图片资源
               final Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.women);
                //在UI 中更新
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        ImageView imageView = findViewById(R.id.result_image);
                        imageView.setImageBitmap(bitmap);
                    }
                });
            }
        }).start();
    }

会报错,错误信息为图片过大,造成溢出,内存不够,无法正常加载

2.正确处理(重要)
  • 算法:根据控件大小来动态计算inSampleSize的值。获取图片的宽高、控件的宽高,然后将Sample的值设置为两者比值的最小值,这样就可以实现大图片的加载且省内存。

我理解的流程:

1.添加一个Options;

2.将inJustDecodeBounds的值设置为true;

3.默认一个inSampleSize的值;

4.获取图片和控件的宽高;

5.将两者的值作比;

6.将二者较小的设置为inSampleSize的值;

7.解码位图,获取资源;

8.加载图片(imageView.setImageBitmap(bitmap);)

 //加载图片的方法,在一个新线程里面操作
    public void LoadPic(View view){
        //添加一个options
        BitmapFactory.Options options = new BitmapFactory.Options();
        //如果inJustDecoedBounds设置为true的话,解码bitmap时可以只返回其高、宽和Mime类型,而不必为其申请内存,从而节省了内存空间。
        options.inJustDecodeBounds = true;
        //找到控件
        ImageView imageView = findViewById(R.id.result_image);
        //获取图片的宽高
        int height = options.outHeight;
        int width = options.outWidth;
        //先默认一个Sample的值
        options.inSampleSize = 2;
        //获取控件的宽高
        int ImgHeight = imageView.getMeasuredHeight();
        int ImgWidth = imageView.getMeasuredWidth();
        //比较,将sample的值设置为两者比值的最小值
        if(height > ImgHeight || width > ImgWidth){
            int subHeight = height/ImgHeight;
            int subWidth = width/ImgWidth;
            options.inSampleSize = subHeight>subWidth?subWidth:subHeight;
        }
        //将inJustDecodeBounds设为false
        options.inJustDecodeBounds = false;
        //解码位图
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.women,options);
        //进行设置
        imageView.setImageBitmap(bitmap);
    }

7.post提交文本内容(评论)

我理解的流程:

1.HTTP协议的常规操作;

2.创建一个实体类;

3.创建一个Bytes【】数组,后面输出流写入时候要用;

4.OutputStream输出流;

5.获取状态码,输入流写入;

6.关闭流

2.创建一个活动,在xml文件里添加一个按钮;
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activity.PostTextActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="post text"
        android:textAllCaps="false"
        android:onClick="PostText"
        tools:ignore="OnClick" />

</LinearLayout>
3.创建一个实体类
public class CommentItem {
    private String username;
    private String password;

    public CommentItem(String username, String password) {
        this.username = username;
        this.password = password;
    }

    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;
    }
}
4.在主活动.java 文件内编译代码
public void PostText(View view){
        new Thread(new Runnable() {
            @Override
            public void run() {
                OutputStream outputStream = null;
                InputStream inputStream = null;
                try {
                    //首先是HTTP协议的常规操作
                    URL url = new URL("https://www.wanandroid.com/user/login");
                    HttpURLConnection connection = (HttpURLConnection)url.openConnection();
                    connection.setConnectTimeout(100000);
                    connection.setRequestMethod("POST");
                    connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9");
                    //实例化CommentItem类
                    CommentItem commentItem = new CommentItem("123456","112233");
                    //GSON解析
                    Gson gson = new Gson();
                    String jsonStr =  gson.toJson(commentItem);
                    //outputstream流需要写入的时候 要传一个bytes类型的数组
                    byte[] bytes = jsonStr.getBytes("UTF-8");
                    connection.setRequestProperty("Content-length",String.valueOf(bytes.length));
                    //建立连接
                    connection.connect();
                    //把数据给到服务器
                    outputStream = connection.getOutputStream();
                    //写入输出流
                    outputStream.write(bytes);
                    outputStream.flush();
                    //拿到状态码
                    int responsecode = connection.getResponseCode();
                    if(responsecode == HttpURLConnection.HTTP_OK){
                        //使用输入流来读取内容
                        inputStream = connection.getInputStream();
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    //最后要关闭流
                    if (outputStream != null) {
                        try {
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();
    }

代码详情请看注释

8.URL带参数的请求

1.get方式实现
1.xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activity.RequestTextActivity"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="get 方式实现带参数的请求"
        android:onClick="GetWith"
        tools:ignore="OnClick" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="post 方式实现带参数的请求"
        android:onClick="PostWith"
        tools:ignore="OnClick" />

</LinearLayout>
2…java文件
public class RequestTextActivity extends AppCompatActivity {

    public static final String BASE_URL = "http://10.0.2.2:9102";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_request_text);
    }

    //get 方式实现带参数的请求
    public void GetWith(View view){
        Map<String,String> map = new HashMap<>();
        map.put("key","这是我的关键字");
        map.put("page","页码");
        map.put("order","shunxu");
        startRequest(map,"GET","/get/parm");
    }

    private void startRequest(final Map<String, String> map, String method, final String api) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //拼装参数
                    StringBuilder sb = new StringBuilder();
                    sb.append("?");
                    if (map != null && map.size()>0){
                        Set<Map.Entry<String, String>> entries = map.entrySet();
                        Iterator<Map.Entry<String, String>> iterator = entries.iterator();
                        while (iterator.hasNext()) {
                            Map.Entry<String, String> next = iterator.next();
                            sb.append(next.getKey());
                            sb.append("=");
                            sb.append(next.getValue());
                            if (iterator.hasNext()){
                                sb.append("&");
                            }
                        }
                    }
                    String params = sb.toString();
                    URL url;
                    if(params != null && params.length()>0){
                        url = new URL(BASE_URL+ api + params);
                    }else{
                        url = new URL(BASE_URL+api);
                    }
                    HttpURLConnection connection =(HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(100000);
                    connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9");
                    connection.connect();
                    int responseCode = connection.getResponseCode();
                    if (responseCode == 200){
                        InputStream inputStream = connection.getInputStream();
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                        String readLine = bufferedReader.readLine();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
2.post方式
1…java 文件
private void startRequest(final Map<String, String> map, String method, final String api) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //拼装参数
                    StringBuilder sb = new StringBuilder();
                    sb.append("?");
                    if (map != null && map.size()>0){
                        Set<Map.Entry<String, String>> entries = map.entrySet();
                        Iterator<Map.Entry<String, String>> iterator = entries.iterator();
                        while (iterator.hasNext()) {
                            Map.Entry<String, String> next = iterator.next();
                            sb.append(next.getKey());
                            sb.append("=");
                            sb.append(next.getValue());
                            if (iterator.hasNext()){
                                sb.append("&");
                            }
                        }
                    }
                    String params = sb.toString();
                    URL url;
                    if(params != null && params.length()>0){
                        url = new URL(BASE_URL+ api + params);
                    }else{
                        url = new URL(BASE_URL+api);
                    }
                    HttpURLConnection connection =(HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(100000);
                    connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9");
                    connection.connect();
                    int responseCode = connection.getResponseCode();
                    if (responseCode == 200){
                        InputStream inputStream = connection.getInputStream();
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                        String readLine = bufferedReader.readLine();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    //post方式 实现带参数的请求
    public void PostWith(View view){
        Map<String,String> map = new HashMap<>();
        map.put("String","这是我提交的字符串");
        startRequest(map,"POST","/post/string");
    }
1.创建一个活动,在其xml文件内添加一个按钮:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activity.RequestTextActivity"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="post 实现单文件上传"
        android:onClick="PostFile"
        tools:ignore="OnClick" />

</LinearLayout>
2. .java 文件内
public void PostFile(View view){
        new Thread(new Runnable() {
            @Override
            public void run() {
                OutputStream outputStream = null;
                BufferedInputStream bri = null;
                try {
                    //文件流,参数为文件地址
                    File file = new File("/storage/emulated/0/Download/1.png");
                    String fileKey = "file";
                    String filename = file.getName();
                    String fileType = "image/png";
                    String BOUNDARY = "-----------------------------95454674815313215456";
                    //基操
                    URL url = new URL(BASE_URL+"/file/upload");
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    //设置参数,这些参数在转包软件中可以获取
                    connection.setConnectTimeout(100000);
                    connection.setRequestMethod("POST");
                    connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9");
                    connection.setRequestProperty("Accept","*/*");
                    connection.setRequestProperty("Connection","keep-alive");
                    connection.setDoOutput(true);
                    connection.setDoInput(true);
                    //连接
                    connection.connect();
                    outputStream = connection.getOutputStream();
                    //准备数据
                    StringBuilder headerSbInfo = new StringBuilder();
                    headerSbInfo.append("--");
                    headerSbInfo.append(BOUNDARY);
                    headerSbInfo.append("\r\n");
                    byte[] bytes = headerSbInfo.toString().getBytes();
                    outputStream.write(bytes);
                    //文件内容
                    FileInputStream fileInputStream = new FileInputStream(file);
                    bri = new BufferedInputStream(fileInputStream);
                    byte[] buffer = new byte[1024];
                    int len;
                    while (((len = bri.read(buffer, 0, buffer.length)) != -1)) {
                        outputStream.write(buffer,0,len);
                    }
                    //写尾部信息
                    StringBuilder footerSbInfo = new StringBuilder();
                    footerSbInfo.append("\r\n");
                    footerSbInfo.append("--");
                    footerSbInfo.append(BOUNDARY);
                    footerSbInfo.append("--");
                    footerSbInfo.append("\r\n");
                    outputStream.write(footerSbInfo.toString().getBytes("UTF-8"));

                    //获取返回的结果
                    int responseCode = connection.getResponseCode();
                    if ((responseCode == 200)) {
                        InputStream inputStream = connection.getInputStream();
                        BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream));
                        String result = bf.readLine();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    //关流
                    if (bri != null) {
                        try {
                            bri.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (outputStream != null) {
                        try {
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();
    }
3.在manifest中添加访问sd卡的权限
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

9.多文件上传

1.创建一个新的活动,xml文件和之前一样,添加一个按钮。
2…java文件
public void PostFiles(View view){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //文件流,参数为文件地址
                    File fileOne = new File("/storage/emulated/0/Download/1.png");
                    File fileTwo = new File("/storage/emulated/0/Download/2.png");
                    File fileThree = new File("/storage/emulated/0/Download/3.png");
                    String fileKey = "files";
                    String fileType = "image/png";
                    String BOUNDARY = "-----------------------------95454674815313215456";
                    URL url = new URL(BASE_URL+"/files/upload");
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    //设置参数,这些参数在转包软件中可以获取
                    connection.setConnectTimeout(100000);
                    connection.setRequestMethod("POST");
                    connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9");
                    connection.setRequestProperty("Accept","*/*");
                    connection.setRequestProperty("Connection","keep-alive");
                    connection.setDoOutput(true);
                    connection.setDoInput(true);
                    //连接
                    connection.connect();
                    OutputStream outputStream = connection.getOutputStream();
                    //准备数据
                    upload(fileOne, BOUNDARY, outputStream,false);
                    upload(fileTwo, BOUNDARY, outputStream,false);
                    upload(fileThree, BOUNDARY, outputStream,true);

                    //获取返回的结果
                    int responseCode = connection.getResponseCode();
                    if ((responseCode == 200)) {
                        InputStream inputStream = connection.getInputStream();
                        BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream));
                        String result = bf.readLine();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            //封装成方法
            private void upload(final File file,
                                final String BOUNDARY,
                                final OutputStream outputStream,
                                boolean isLast) throws IOException {
                StringBuilder headerSbInfo = new StringBuilder();
                headerSbInfo.append("--");
                headerSbInfo.append(BOUNDARY);
                headerSbInfo.append("\r\n");
                byte[] bytes = headerSbInfo.toString().getBytes();
                outputStream.write(bytes);
                //文件内容
                FileInputStream fileInputStream = new FileInputStream(file);
                BufferedInputStream bri = new BufferedInputStream(fileInputStream);
                byte[] buffer = new byte[1024];
                int len;
                while (((len = bri.read(buffer, 0, buffer.length)) != -1)) {
                    outputStream.write(buffer,0,len);
                }
                //写尾部信息
                StringBuilder footerSbInfo = new StringBuilder();
                footerSbInfo.append("\r\n");
                footerSbInfo.append("--");
                if (isLast) {
                    footerSbInfo.append("--");
                    footerSbInfo.append("\r\n");
                }
                footerSbInfo.append(BOUNDARY);
                outputStream.write(footerSbInfo.toString().getBytes("UTF-8"));
            }
        }).start();
    }

把上传数据的过程封装起来成为一个方法,避免代码的冗余

10.文件的下载

1.继续创建一个活动,在其xml文件内写入
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Activity.RequestTextActivity"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="文件下载"
        android:onClick="DownFile"
        tools:ignore="OnClick" />

</LinearLayout>
2 .java文件内
public void DownFile(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL(BASE_URL + "/download/10");
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setConnectTimeout(100000);
                    connection.setRequestMethod("POST");
                    connection.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.9");
                    connection.setRequestProperty("Accept", "*/*");
                    connection.setRequestProperty("Connection", "keep-alive");
                    connection.connect();
                    int responseCode = connection.getResponseCode();
                    if (responseCode == 200) {
                        //拿到文件
                        String headerField = connection.getHeaderField("Content-disposition");
                        int index = headerField.indexOf("filename=");
                        int length = "filename".length();
                        headerField.substring(index + length);

                        //存储过程
                        File picFile = DownFileActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
                        String fileName = headerField.replace("attachment;filename", "");
                        if (!picFile.exists()) {
                            picFile.mkdirs();
                        }
                        File file = new File("picFile" + File.separator + fileName);
                        if (!file.exists()) {
                            file.createNewFile();
                        }
                        FileOutputStream fileOutputStream = new FileOutputStream(file);
                        InputStream inputStream = connection.getInputStream();
                        byte[] buffer = new byte[1024];
                        int len;
                        while ((len = inputStream.read(buffer, 0, buffer.length)) != -1){
                            fileOutputStream.write(buffer,0,len);
                        }
                        fileOutputStream.flush();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

了解原理即可,后面会学到框架

3.创建一个工具类用来关闭流
public class IOUtils {
    public static void ioClose(Closeable closeable){
        try {
            closeable.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • Closeable 类是流的父类,不管是输入还是输出流都能传进去
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值