http请求不支持断点续传,需要在客户端手动切分文件
基于httpClient的请求
package com.dj.test.payorder;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.*;
import java.util.Date;
/**
* Created by zjx on 2021/3/17
*/
public class HttpClientTest {
public static void main(String[] args) {
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
FileOutputStream fos=null;
RandomAccessFile rw=null;
try {
httpClient = HttpClients.createDefault();
// 把一个普通参数和文件上传给下面这个地址 是一个servlet
HttpPost httpPost = new HttpPost("http://localhost:8082/register/httpTest.do");
// File file = new File("F:\\测试文件.txt");
File file = new File("F:\\安装包.rar");//源文件
long length = file.length();
//每次请求发送文件的大小
int size = 10485760;
// int size = 1024;
//根据文件大小计算请求次数
int round = (int)Math.ceil((double)length/size);
//创建文件对象,此对象可以在指定位置读取文件,也可以在指定位置写入文件
rw = new RandomAccessFile(file, "rw");
//文件上传起始位置
Long start = 0l;
for(int i =0 ;i<round ;i++){
Date startDate = new Date();
//一次请求的结束位置
Long end = start+size;
//判断此次请求结束是否大于文件的总大小,如果大于就用文件总大小减去起始位置,得到最后一次请求的结束位置
if(end>length){
size = (int)(length-start);
end=start+size;
}
//设置此次请求的数据范围
httpPost.addHeader("Range","bytes="+start+"-"+end);
//读取源文件时跳到此次请求的起始位置
rw.seek(start);
byte[] bytes = new byte[size];
//读取源文件,从起始位置到本次请求的结束位置
int read = rw.read(bytes);
//创建临时文件,请求时放入请求体上传临时文件
File tmpFile = new File("F:\\tmp.file");
fos = new FileOutputStream(tmpFile);
fos.write(bytes,0,read);
fos.flush();
fos.close();
// 把文件转换成流对象FileBody
FileBody bin = new FileBody(tmpFile);
//传入请求的其他参数和临时文件
StringBody userName = new StringBody("data", ContentType.create("text/plain", Consts.UTF_8));
StringBody userName1= new StringBody("zhujixiang", ContentType.create("text/plain", Consts.UTF_8));
StringBody password= new StringBody("64a62d49999fb141855f51ed3d58b5d0", ContentType.create("text/plain", Consts.UTF_8));
HttpEntity reqEntity = MultipartEntityBuilder.create()
// 相当于<input type="file" name="file"/>
.addPart("file", bin)
// 相当于<input type="text" name="userName" value=userName>
.addPart("list", userName)
.addPart("username", userName1)
.addPart("password", password)
.build();
httpPost.setEntity(reqEntity);
// 发起请求 并返回请求的响应
response = httpClient.execute(httpPost);
System.out.println("The response value of token:" + response.getFirstHeader("token"));
// 获取响应对象
HttpEntity resEntity = response.getEntity();
// if (resEntity != null) {
// // 打印响应长度
// System.out.println("Response content length: " + resEntity.getContentLength());
// // 打印响应内容
// System.out.println(EntityUtils.toString(resEntity, Charset.forName("UTF-8")));
// }
// 销毁
EntityUtils.consume(resEntity);
//需要删除本次请求头,不然下次请求会拿原来的Range的值
httpPost.removeHeaders("Range");
//删除临时文件
tmpFile.delete();
//将本次请求的结束位置,替换成下次请求的开始位置
start=start+size;
Date endDate = new Date();
Long shijian = endDate.getTime()-startDate.getTime();
System.out.println("用时===="+shijian);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭流
close(httpClient,response,fos,rw);
}
}
private static void close(Closeable... closeables) {
if (closeables == null || closeables.length == 0) {
return;
}
for (Closeable closeable : closeables) {
if (closeable == null) {
continue;
}
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
服务器端Controller代码
@RequestMapping(value = "/httpTest",method = RequestMethod.POST,produces = {"application/json;charset=UTF-8"})
public @ResponseBody Object httpTest( MultipartFile file, String list, HttpServletRequest request, HttpServletResponse response) {
Map<String,Object> resoultMap = new HashedMap();
try {
String range = request.getHeader("Range");
String[] split = range.split("-");
File targfile = getByName("F://ConcurrentWrite.rar");
byte[] bytes = null;
Date statDate = new Date();
RandomAccessFile randFile = null;
FileChannel channel = null;
InputStream inputStream=null;
try {
inputStream = file.getInputStream();
int lenth;
bytes=new byte[1024*1024*10];
Long from = Long.valueOf(split[0].split("=")[1]);
Long end = Long.valueOf(split[1]);
// inputStream.skip(from);
int i=0;
MappedByteBuffer mbb = null;
FileLock fileLock = null;
randFile = new RandomAccessFile(targfile, "rw");
channel = randFile.getChannel();
while ((lenth=inputStream.read(bytes))!=-1){
// System.out.println(new String(bytes,0,lenth));
System.out.println("from=="+from);
int sliceLen = lenth;
if((from+lenth)>end){
sliceLen = (int)(end-from);
}
byte[] slice = new byte[sliceLen];
System.arraycopy(bytes, 0, slice, 0, sliceLen);
try {
mbb = channel.map(FileChannel.MapMode.READ_WRITE, from, sliceLen);
fileLock = channel.lock(from, sliceLen, true);
while (fileLock == null || !fileLock.isValid()) {
fileLock = channel.lock(from, sliceLen, true);
System.out.print("锁无效,重复获取");
}
mbb.put(slice);
mbb.force();
release(fileLock);
forceClose(mbb);
} catch (IOException e) {
e.printStackTrace();
} catch (OverlappingFileLockException e) {
e.printStackTrace();
throw new IllegalArgumentException("程序设计不合理,加锁区域相互重叠");
} catch (Exception e) {
e.printStackTrace();
System.out.println("from=="+from);
System.out.println("sliceLen=="+sliceLen);
}
from = lenth+from;
if(from>end){
break;
}
}
Date endDate = new Date();
Long shijian = endDate.getTime()-statDate.getTime();
System.out.println("用时===="+shijian/1000);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}finally{
close(channel, randFile,inputStream);
}
} catch (Exception e) {
e.printStackTrace();
resoultMap.put("status",false);
}
return resoultMap;
}
private File getByName(String path) {
File file = new File(path);
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
throw new IllegalArgumentException("create file failed", e);
}
}
if (file.isDirectory()) {
throw new IllegalArgumentException("not a file");
}
return file;
}
private void release(FileLock fileLock) {
if (fileLock == null) {
return;
}
try {
fileLock.release();
} catch (IOException e) {
e.printStackTrace();
}
}
private void close(Closeable... closeables) {
if (closeables == null || closeables.length == 0) {
return;
}
for (Closeable closeable : closeables) {
if (closeable == null) {
continue;
}
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 强制关闭MappedByteBuffer
* @param mbb
*/
private void forceClose(MappedByteBuffer mbb) {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
Method getCleanerMethod = mbb.getClass().getMethod("cleaner", new Class[0]);
getCleanerMethod.setAccessible(true);
sun.misc.Cleaner cleaner = (sun.misc.Cleaner)
getCleanerMethod.invoke(mbb, new Object[0]);
cleaner.clean();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
}
欢迎各位提出改进意见,共同进步
原创不易,转载请注明出处