01_post方式提交数据的中文乱码解决
解决办法:保证客户端和服务器端使用的字符集编码一致。
Tomcat默认的字符集编码是iso-8859-1,默认是iso-8859-1进行转码
String username = request.getParameter("username");
String password = request.getParameter("password");
Tomcat默认的字符集编码是iso-8859-1,默认是iso-8859-1进行转码,当它发现使用iso-8859-1不能编码中文的时候,会使用操作系统使用的本地码表(字符集编码)进行编码,所以我们需要自己编码response.getOutputStream().write("登陆成功".getBytes("UTF-8"));
02_get提交数据乱码的解决
04_使用HttpClient向服务器端提交数据
HttpClient : apache子项目
HttpClient 轻量级的浏览器
步骤:
1、创建一个浏览器
2、输入一个网址
3、按回车
模版代码GET方式:
//1、创建一个浏览器
HttpClient client = new DefaultHttpClient();
//2、输入一个网址
HttpGet httpGet = new HttpGet(path);
//3、按回车
HttpResponse response = client.execute(httpGet);
//4、获取服务器端返回的响应数据,判断响应码,200ok,404找不到资源、503服务器内部错误,然后获取输入流;
int code = response.getStatusLine().getStatusCode();
if(code == 200){
//获取返回的二进制数据流
InputStream is = response.getEntity().getContent();
模版代码POST方式:
//1、创建一个浏览器
HttpClient client = new DefaultHttpClient();
// 2、输入一个网址
HttpPost httpPost = new HttpPost(path);
//封装提交的数据
//类似map的数据结构
BasicNameValuePair username = new BasicNameValuePair("username", qq);
BasicNameValuePair password = new BasicNameValuePair("password", pwd);
List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
list.add(username);
list.add(password);
//默认是使用iso-8859-1转码的
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list,"UTF-8");
httpPost.setEntity(entity);
//3、按回车
HttpResponse response = client.execute(httpPost);
//4、获取服务器端返回的响应数据,判断响应码,200ok,404找不到资源、503服务器内部错误,然后获取输入流;
int code = response.getStatusLine().getStatusCode();
if(code == 200){
//获取返回的二进制数据流
InputStream is = response.getEntity().getContent();
05使用开源项目Asynchttpclient的GETPOST访问网络
-
使用GET方式发送请求:
public void login(View view){ String qq = et_qq.getText().toString().trim(); String pwd = et_pwd.getText().toString().trim(); try { path = "http://192.168.13.41:8080/web/servlet/LoginServlet?username="+URLEncoder.encode(qq,"UTF-8")+"&password="+URLEncoder.encode(pwd, "UTF-8"); AsyncHttpClient client = new AsyncHttpClient(); client.get(path, new AsyncHttpResponseHandler() { /** * 请求成功,服务器端正常响应调用这个方法 * statusCode 响应码 * headers 响应头信息 * * responseBody 服务器端返回的数据实体的字节数组 */ @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { Toast.makeText(MainActivity.this, new String(responseBody), 0).show(); } /** * 请求成功,服务器端正常响应调用这个方法 * statusCode 响应码 * headers 响应头信息 * responseBody 服务器端返回的数据实体的字节数组 * error 服务器端抛出来的异常信息 */ @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { Toast.makeText(MainActivity.this, "处理失败;"+new String(responseBody), 0).show(); } }); } catch (Exception e) { e.printStackTrace(); }
}
-
使用POST方式发送请求:
path = "http://192.168.13.41:8080/web/servlet/LoginServlet"; //1、创建一个浏览器 AsyncHttpClient client = new AsyncHttpClient(); //2、设置参数 RequestParams params = new RequestParams(); params.put("username", qq); params.put("password", pwd); //3、发送请求 client.post(path, params, new AsyncHttpResponseHandler() { /** * 请求成功,服务器端正常响应调用这个方法 * statusCode 响应码 * headers 响应头信息 * * responseBody 服务器端返回的数据实体的字节数组 */ @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { Toast.makeText(MainActivity.this, new String(responseBody), 0).show(); } /** * 请求成功,服务器端正常响应调用这个方法 * statusCode 响应码 * headers 响应头信息 * responseBody 服务器端返回的数据实体的字节数组 * error 服务器端抛出来的异常信息 */ @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { Toast.makeText(MainActivity.this, "处理失败;"+new String(responseBody), 0).show(); } });
06_上传文件
代码:
AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
File file = new File(path);
//创建一个文件,作为一个参数提交给服务器端
params.put("file", file);
client.post("http://192.168.13.41:8080/web/servlet/UploadServlet", params, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
Toast.makeText(MainActivity.this, new String(arg2), 0).show();
}
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) {
Toast.makeText(MainActivity.this, "处理失败;", 0).show();
arg3.printStackTrace();
}
});
07_多线程加速下载的原理
08_多线程下载的原理
需要解决问题:
1、在客户端创建一个与服务器端一样大小的空文件:content-length;RandomAccessFile
2、根据线程的个数等分文件,计算出每个线程下载的数据块大小:length/threadcount=blocksize
3、计算每个子线程下载数据的开始位置和结束位置:
开始位置:threadid*blocksize 结束位置:(threadid+1)*blocksize-1
最后一个子线程的开始为位置:threadid*blocksize ,结束位置:length-1
4、确定每个子线程从什么开始写数据:seek()
5、创建子线程,开始下载数据;
6、确定每个子线程都下载完毕,以此来确定每个文件下载完成;
09_javase多线程下载的逻辑
代码:MultiThreadDownLoader.java
package com.itheima;
import java.io.File;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
public class MultiThreadDownLoader {
private static int threadCount = 3;
public static void main(String[] args) {
try {
String path = "http://192.168.13.41:8080/sogou.exe";
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(3000);
int code = conn.getResponseCode();
if(code == 200){
//1、在客户端创建一个与服务器端一样大小的空文件:content-length;RandomAccessFile
int length = conn.getContentLength();
File file = new File("temp.exe");
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.setLength(length);
// 2、根据线程的个数等分文件,计算出每个线程下载的数据块大小:length/threadcount=blocksize
int blockSize = length/threadCount;
// 3、计算每个子线程下载数据的开始位置和结束位置:
// 开始位置:threadid*blocksize 结束位置:(threadid+1)*blocksize-1
// 最后一个子线程的开始为位置:threadid*blocksize ,结束位置:length-1
for(int threadId=0; threadId<threadCount; threadId++){
//开始位置
int startIndex = threadId * blockSize;
//结束位置
int endIndex = (threadId+1)*blockSize-1;
//最后一个线程下载的结束位置
if(threadId==threadCount-1){
endIndex = length-1;
}
// 4、确定每个子线程从什么开始写数据:seek()
// 5、创建子线程,开始下载数据;
new ChildThreadDownLoader(startIndex,endIndex,threadId,path).start();
}
//
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
子线程下载:ChildThreadDownLoader.java
package com.itheima;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
public class ChildThreadDownLoader extends Thread {
private static int runningThreadCount = 3;
private int startIndex;
private int endIndex;
private int threadId;
private String path;
public ChildThreadDownLoader(int startIndex, int endIndex, int threadId,
String path) {
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
this.path = path;
}
@Override
public void run() {
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(3000);
//设置请求数据的数范围 bytes=0-3
conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
int code = conn.getResponseCode();
//成功返回部分数据code=206 200表示返回全部数据
if(code == 206){
//1、在客户端创建一个与服务器端一样大小的空文件:content-length;RandomAccessFile
InputStream is = conn.getInputStream();
File file = new File("temp.exe");
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
System.out.println("线程"+threadId+"开始下载:"+startIndex+","+endIndex);
// 4、确定每个子线程从什么开始写数据:seek()
raf.seek(startIndex);
//开始下载数据
byte[] buffer = new byte[1024*20];
int len = -1;
while((len = is.read(buffer)) != -1){
raf.write(buffer, 0, len);
}
is.close();
raf.close();
System.out.println("线程"+threadId+"下载完成..............");
//6、确定每个子线程都下载完毕,以此来确定每个文件下载完成;
synchronized (ChildThreadDownLoader.class) {
runningThreadCount--;
if(runningThreadCount == 0){
System.out.println("文件下载完毕........................");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
10_javase多线程断点下载
1、知道每个子线程上次下载到了什么位置
实时的记录每个子线程下载到的位置,写到一个文件里;
2、获取没格子线程上次下载到的位置,下次下载时接着上一次下载:
读取文件,得到上次下载到的位置,接着下载;
代码:
package com.itheima;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
public class ChildThreadDownLoader extends Thread {
private static int runningThreadCount = 3;
private int startIndex;
private int endIndex;
private int threadId;
private String path;
public ChildThreadDownLoader(int startIndex, int endIndex, int threadId,
String path) {
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
this.path = path;
}
@Override
public void run() {
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(3000);
//2、获取没格子线程上次下载到的位置,下次下载时接着上一次下载:读取文件,得到上次下载到的位置,接着下载;
File info = new File(threadId+".txt");
if(info.exists() && info.length()>0){
FileReader fr = new FileReader(info);
BufferedReader br = new BufferedReader(fr);
String lastDownPosition = br.readLine();
startIndex = Integer.valueOf(lastDownPosition);
}
//设置请求数据的数范围 bytes=0-3
conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
int code = conn.getResponseCode();
//成功返回部分数据code=206 200表示返回全部数据
if(code == 206){
//1、在客户端创建一个与服务器端一样大小的空文件:content-length;RandomAccessFile
InputStream is = conn.getInputStream();
File file = new File("temp.exe");
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
System.out.println("线程"+threadId+"开始下载:"+startIndex+","+endIndex);
// 4、确定每个子线程从什么开始写数据:seek()
raf.seek(startIndex);
//开始下载数据
byte[] buffer = new byte[1024*20];
int len = -1;
int total=0;
while((len = is.read(buffer)) != -1){
raf.write(buffer, 0, len);
//把当前下载到的位置记录到文件里
total = total + len;
int currentPosition = startIndex + total;
RandomAccessFile f = new RandomAccessFile(threadId+".txt","rwd");
f.write((currentPosition+"").getBytes());
f.close();
}
is.close();
raf.close();
System.out.println("线程"+threadId+"下载完成..............");
//6、确定每个子线程都下载完毕,以此来确定每个文件下载完成;
synchronized (ChildThreadDownLoader.class) {
runningThreadCount--;
if(runningThreadCount == 0){
System.out.println("文件下载完毕........................");
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
11_多线程下载的Android移植
12_开目实现多线程下载
-
示例代码:
HttpUtils http = new HttpUtils(); HttpHandler handler = http.download(path, Environment.getExternalStorageDirectory()+"/sogou.exe", true, // 如果目标文件存在,接着未完成的部分继续下载。服务器不支持RANGE时将从新下载。 true, // 如果从请求返回信息中获取到文件名,下载完成后自动重命名。 new RequestCallBack<File>() { @Override public void onStart() { tv_start.setText("conn..."); } @Override public void onLoading(long total, long current, boolean isUploading) { tv_progress.setText(current + "/" + total); } @Override public void onSuccess(ResponseInfo<File> responseInfo) { Toast.makeText(MainActivity.this, "下载完成,文件在"+responseInfo.result.getPath(), 0).show(); } @Override public void onFailure(HttpException error, String msg) { Toast.makeText(MainActivity.this, "下载失败", 0).show(); error.printStackTrace(); } });