HTTP协议
- http协议就是超文本传输协议;
- 协议是约定的意思,内容是http相关的格式;
- http协议是基于TCP/IP协议之上的应用层协议
流程:客户端发起请求,服务器端响应请求
1.http的八种请求方式:
- get //请求
- post //提交
- put //更新
- delete //删除
- head
- trace
- options
- connect
2.http 状态码
类别 | 原因短语 | |
1XX | Informational(信息性状态码) | 接受的请求正在处理 |
2XX | Success(成功状态码) | 请求正常处理完毕 |
3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 |
5XX | Server 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 类是流的父类,不管是输入还是输出流都能传进去