断点上传 水平较菜 ,多包涵
完善之后的代码:(不再通过发起多次url请求来分段上传,而是仅仅一次请求)
客户端:
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import com.lubansoft.test.upload.po.UploadRecord;
import com.lubansoft.test.upload.utils.ConfigFileUtils;
public class SimpleUrlConnection {
public static void main(String[] args) {
SimpleUrlConnection suc = new SimpleUrlConnection();
suc.executeuUpload();
/*if(args != null && args.length > 0){
String path = args[0];
path = path.substring("uploadhelper://".length(), path.length());
args[0] = path;
getUploadRecord(args);
SimpleUrlConnection suc = new SimpleUrlConnection(args[0]);
suc.executeuUpload();
}else{
if(!RegistryUtils.isRegistered()){
RegistryUtils.register();
}
}*/
}
private HttpURLConnection conn;
boolean isShowRate = false;
int streamLength = 10240;
private String[] fileNames;
private Map<String,String> params;
private UploadRecord[] uploadRecords;
public SimpleUrlConnection(){
}
public SimpleUrlConnection(String[] pathNames){
this.fileNames = pathNames;
}
//上传文件
private void executeuUpload() {
//设定参数
params = new HashMap<String, String>();
params.put("key1", "value1");
params.put("key2", "value2");
params.put("key3", "value3");
this.fileNames= new String[]{"E:\\我的文档\\下载\\apache-tomcat-6.0.36-src.zip","E:\\我的文档\\下载\\apache-tomcat-6.0.36-windows-x86.zip",
"E:\\我的文档\\下载\\china-code.net.zhy.201238211546823200.Rar"};
// this.fileNames= new String[]{"E:\\我的文档\\下载\\commons-email-1.3.1-bin.tar.gz"};
// this.fileNames= new String[]{"E:\\我的文档\\下载\\commons-email-1.3.1-bin.tar.gz","E:\\我的文档\\下载\\commons-email-1.3.1-src.tar.gz"};
// this.fileNames= new String[]{"E:\\我的文档\\下载\\apache-tomcat-6.0.36-src.zip","E:\\我的文档\\下载\\apache-tomcat-6.0.36-windows-x86.zip"};
/**
* 上传文件之前先获取所有文件上传记录
*/
uploadRecords = getUploadRecord(fileNames);
/**
* 上传文件
*/
upload(params,uploadRecords, fileNames);
}
/**
*
* Created on 2013-5-13
* <p>Discription:查询文件上传记录</p>
* @author:田超辉 tianchaohui@dev.com
* @update:[日期YYYY-MM-DD] [更改人姓名]
* @return UploadRecord[]
*/
public UploadRecord[] getUploadRecord(String[] fileNames){
UploadRecord[] records = null;
if(fileNames == null || fileNames.length<=0){
return null;
}
records = new UploadRecord[fileNames.length];
OutputStream out = null;
InputStream in = null;
File f = null;
try {
URL url = new URL("http://localhost:8080/upload/getUploadHistory");
conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("Charsert", "UTF-8");
out = conn.getOutputStream();
StringBuilder sb = new StringBuilder();
int length = fileNames.length;
for(int i=0;i<length;i++){
f = new File(fileNames[i]);
sb.append("fileName="+f.getName()+"&fileSize="+f.length());
if(i == length-1){
sb.append("\n");
}else{
sb.append(";");
}
}
String request = sb.substring(0, sb.length()-1);
out.write(request.getBytes("utf-8"));
out.flush();
in = conn.getInputStream();
String line = null;
for(int i=0;i<fileNames.length;i++){
line = ConfigFileUtils.readLine(in);
records[i] = getUploadRecoreFromString(line);
}
isShowRate = true;
}catch(Exception e){
e.printStackTrace();
}finally{
try {
if(in != null){
in.close();
in = null;
}
if(out != null){
out.close();
out = null;
}
f = null;
} catch (IOException e) {
e.printStackTrace();
}
}
return records;
}
/**
*
* Created on 2013-5-13
* <p>Discription:从字符串中提取出UploadRecord对象 :</p>
* <p>"fileName="+f.getName()+"&fileSize="+f.length()+"&uploadSize="f.getUploadSize()</p>
* @author:田超辉 tianchaohui@dev.com
* @update:[日期YYYY-MM-DD] [更改人姓名]
* @return UploadRecord
*/
private UploadRecord getUploadRecoreFromString(String line) {
return ConfigFileUtils.getUploadRecoreFromString(line);
}
/**
*
* Created on 2013-5-13
* <p>Discription:根据服务器返回的UploadRecord[] uploadRecords,开始从断点处上传</p>
* @author:田超辉 tianchaohui@dev.com
* @update:[日期YYYY-MM-DD] [更改人姓名]
* @return void
*/
public void upload(Map<String,String> params,UploadRecord[] uploadRecords,String[] paths){
RandomAccessFile in = null;
File file = null;
try {
String url = "http://localhost:8080/upload/uploadServlet";
URL u = new URL(url);
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("Charsert", "UTF-8");
//指定流的大小,当内容达到这个值的时候就把流输出
conn.setChunkedStreamingMode(1024*1024);
OutputStream out = conn.getOutputStream();
if(params != null){
StringBuilder sb = new StringBuilder();
for(Map.Entry<String, String> entry:params.entrySet()){
sb.append(entry.getKey() + "=" + entry.getValue() + "&");
}
String param = sb.substring(0, sb.length()-1);
/**
* 首先告诉服务器要传输的是参数
*/
out.write("--parameters--\n".getBytes("utf-8"));
out.write(param.getBytes("utf-8"));
out.write("\n".getBytes("utf-8"));
}
if(uploadRecords != null && uploadRecords.length>0){
/**
* 接下来告诉服务器传递的是文件
*/
UploadRecord uploadRecord = null;
/**
* 通过for循环来上传多个文件,每个文件的上传过程为:
* 第一行:--file begin--
* 第二行:fileName=ddd&fileSize=xxx&uploadSize=aaa
* 第三行:开始上传文件内容
*/
for(int i=0;i<uploadRecords.length;i++){
uploadRecord = uploadRecords[i];
if(uploadRecord.getFileSize() <= uploadRecord.getUploadSize()){
continue;
}
out.write("--file begin--\n".getBytes("utf-8"));
out.write(("fileName="+uploadRecord.getFileName()+"&fileSize="+uploadRecord.getFileSize()+"&uploadSize="+uploadRecord.getUploadSize()).getBytes("utf-8"));
out.write("\n".getBytes("utf-8"));
file = new File(paths[i]);
in = new RandomAccessFile(file, "r");
byte[] b = null;
int n = -1;
/**
* 将指针移动到断点位置
*/
in.seek(uploadRecords[i].getUploadSize());
b = new byte[2048];
/**
* 上传文件内容
*/
while ((n = in.read(b)) != -1) {
out.write(b, 0, n);
}
out.flush();
in.close();
}
}
BufferedReader reader = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(in != null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
in = null;
}
if(file != null){
file = null;
}
}
}
}
服务器端servlet:
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.lubansoft.test.upload.po.UploadRatePercent;
import com.lubansoft.test.upload.po.UploadRecord;
import com.lubansoft.test.upload.utils.ConfigFileUtils;
//文件上传的servlet
public class FixedFileUpload extends HttpServlet {
private static final long serialVersionUID = 1L;
private int blockSize ;
private MathContext mc_rate = new MathContext(4, RoundingMode.HALF_DOWN);
private MathContext mc_percent = new MathContext(4, RoundingMode.HALF_DOWN);
public FixedFileUpload() {
try {
Properties prop = new Properties();
prop.load(this.getClass().getResourceAsStream("/blockSize.properties"));
blockSize = Integer.parseInt(prop.getProperty("blockSize"));
if(blockSize == 0){
blockSize = 20480;
}
} catch (IOException e) {
e.printStackTrace();
}
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
try {
InputStream in = new BufferedInputStream(request.getInputStream(),10240);
String requestHeader = readLine(in);
String line = null;
/**
* 判断是否是文件/参数
*/
if("--parameters--".equals(requestHeader)){
Map<String,String> param = new HashMap<String, String>();
line = readLine(in);
if(line != null){
String[] params = line.split("&");
if(params!=null && params.length>0){
for(String keyValue : params){
param.put(keyValue.split("=")[0], keyValue.split("=")[1]);
}
}
}
System.out.println(param);
if("--file begin--".equals(line=readLine(in))){
Timer timer = new Timer();
UploadRateTimerTask task = new UploadRateTimerTask(request);
//指定每隔0.5s执行一次定时器
timer.schedule(task, 0 , 500);
saveFile(in, request, task);
//取消定时器
timer.cancel();
}
}else if("--file begin--".equals(requestHeader)){
Timer timer = new Timer();
UploadRateTimerTask task = new UploadRateTimerTask(request);
//指定每隔0.5s执行一次定时器
timer.schedule(task, 0 , 500);
saveFile(in, request, task);
//取消定时器
timer.cancel();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
private String readLine(InputStream in) {
return ConfigFileUtils.readLine(in);
}
//用于显示上传速度和百分比
class UploadRateTimerTask extends TimerTask{
private long pre_uploadSize = 0,total_uploadSize = 0;
UploadRatePercent uploadRatePercent = new UploadRatePercent();
UploadRecord uploadRecord;
double rate = 0 ,uploadPercent = 0;
private HttpServletRequest request;
public UploadRateTimerTask(HttpServletRequest request){
this.request = request;
}
@Override
public void run() {
if(pre_uploadSize <= total_uploadSize && uploadRecord != null){
//rate=2*(当前上传的大小 - 上一时刻上传的大小)/1024 k/s
//uploadPercent = 100*(当前上传文件的大小/文件总的大小) %
rate = new BigDecimal(total_uploadSize+"").subtract(new BigDecimal(pre_uploadSize+"")).multiply(new BigDecimal(2+""))
.divide(new BigDecimal(1024+""),mc_rate).doubleValue();
uploadPercent = new BigDecimal(100+"").multiply(new BigDecimal(uploadRecord.getUploadSize()+total_uploadSize+""))
.divide(new BigDecimal(uploadRecord.getFileSize()+""),mc_percent).doubleValue();
System.out.println("fileName: " + uploadRecord.getFileName() + " " + rate+" k/s " + uploadPercent +" %");
uploadRatePercent.setPercent(uploadPercent);
uploadRatePercent.setRate(rate);
ConfigFileUtils.updateRateInfoFile(request, uploadRecord.getFileName(), uploadRatePercent);
pre_uploadSize = total_uploadSize;
}else{
pre_uploadSize = total_uploadSize;
}
}
public void setTaskComplete(){
if(pre_uploadSize <= total_uploadSize && uploadRecord != null){
//rate=2*(当前上传的大小 - 上一时刻上传的大小)/1024 k/s
//uploadPercent = 100*(当前上传文件的大小/文件总的大小) %
rate = 0;
uploadPercent = new BigDecimal(100+"").multiply(new BigDecimal(uploadRecord.getUploadSize()+total_uploadSize+""))
.divide(new BigDecimal(uploadRecord.getFileSize()+""),mc_percent).doubleValue();
System.out.println("fileName: " + uploadRecord.getFileName() + " " + rate+" k/s " + uploadPercent +" %");
uploadRatePercent.setPercent(uploadPercent);
uploadRatePercent.setRate(rate);
ConfigFileUtils.updateRateInfoFile(request, uploadRecord.getFileName(), uploadRatePercent);
pre_uploadSize = total_uploadSize;
}
}
public void setUploadRecord(UploadRecord uploadRecord){
this.uploadRecord = uploadRecord;
}
public UploadRecord getUploadRecord(){
return uploadRecord;
}
public long getTotal_uploadSize() {
return total_uploadSize;
}
public void setTotal_uploadSize(long totalUploadSize) {
total_uploadSize = totalUploadSize;
}
}
//保存文件
public void saveFile(InputStream in ,HttpServletRequest request,UploadRateTimerTask task){
String line=null;
String fileName=null;
String fileSize = null;
String uploadSize=null;
RandomAccessFile raf = null;
UploadRecord uploadRecord = null;
try {
task.setTotal_uploadSize(0);
//先读到该文件的信息头“fileName=ddd&fileSize=xxx&uploadSize=aaa”
line = readLine(in);
if(line != null){
String[] info = line.split("&");
if(info != null && info.length>0){
for(String s: info){
if("fileName".equals(s.split("=")[0])){
fileName = s.split("=")[1];
}else if("fileSize".equals(s.split("=")[0])){
fileSize = s.split("=")[1];
}else if("uploadSize".equals(s.split("=")[0])){
uploadSize = s.split("=")[1];
}
}
HttpSession session = request.getSession();
String folder = session.getServletContext().getRealPath("/uploadFiles");
String filepath = folder+File.separator + fileName;
File file = new File(filepath);
if(! file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
if(! file.exists()){
file.createNewFile();
}
String config_path = session.getServletContext().getRealPath("/uploadConfig") + File.separator + request.getRemoteAddr() + "-" + fileName + ".properties";
File config_file = new File(config_path);
if(! config_file.getParentFile().exists()){
config_file.getParentFile().mkdirs();
}
if (! config_file.exists()) {
config_file.createNewFile();
}
raf = new RandomAccessFile(file, "rwd");
if(file.length() != Long.parseLong(fileSize)){
raf.setLength(Long.parseLong(fileSize));
}
//将读取文件的指针移动到断点位置
raf.seek(Long.parseLong(uploadSize));
//计算出从断点位置到文件结尾,还剩下的文件大小
long leftSize = Long.parseLong(fileSize)-Long.parseLong(uploadSize);
//本次上传,上传完成的文件大小
long completeSize = 0l;
/**
* 接下来是文件的内容
*/
int n=-1;
byte[] b = new byte[2048];
int total = 0;
int addSize = 0;
uploadRecord = new UploadRecord();
uploadRecord.setFileName(fileName);
uploadRecord.setFileSize(Long.parseLong(fileSize));
uploadRecord.setIp(request.getRemoteAddr());
uploadRecord.setUploadSize(Long.parseLong(uploadSize));
/**
* 在上传文件的时候,再去判断一下是否已经有程序在上传该文件
* 作为确认,防止万一
*/
boolean isStarted = false;
if(ConfigFileUtils.isUploadStarted(request, fileName)){
isStarted = true;
}
/**
* 为定时器动态绑定uploadRecord对象
*/
task.setUploadRecord(uploadRecord);
/**
* 判断文件从断点开始,还有多大文件需要传输,如果太小(小于 1 k )就要特殊处理
* 因为这时候不能使用 in.read(b) ,而只能使用 in.read(b,0,leftSize)
*/
if((completeSize + b.length) <= leftSize){
while((n=in.read(b)) != -1){
raf.write(b,0,n);
total += n;
completeSize += n;
addSize += n;
task.setTotal_uploadSize(completeSize);
if(addSize >= blockSize){
ConfigFileUtils.updateUploadSize(request, uploadRecord, addSize);
addSize = 0;
}
//判断是否已经到达最后一部分
if((completeSize + b.length) >= leftSize){
n = (int)(leftSize-completeSize);
in.read(b, 0, n);
raf.write(b,0,n);
total += n;
completeSize += n;
addSize += n;
raf.close();
task.setTotal_uploadSize(completeSize);
ConfigFileUtils.updateUploadSize(request, uploadRecord, addSize);
addSize = 0;
//完成一个文件的上传,将该文件的完成百分比改为100%
task.setTaskComplete();
//完成一个文件的上传,将该文件的isStopped改为stopped
ConfigFileUtils.setConfigFileStoped(request, uploadRecord);
line = readLine(in);
if("--file begin--".equals(line)){
saveFile(in, request,task);
}
break;
}
}
}else{//判断文件从断点开始,如果剩余文件太小(小于 1 k )就要特殊处理
in.read(b, 0, (int)leftSize);
if(!isStarted){
raf.write(b, 0, (int)leftSize);
}
raf.close();
task.setTotal_uploadSize(leftSize);
ConfigFileUtils.updateUploadSize(request, uploadRecord, leftSize);
//完成一个文件的上传,将该文件的完成百分比改为100%
task.setTaskComplete();
//完成一个文件的上传,将该文件的isStopped改为stopped
ConfigFileUtils.setConfigFileStoped(request, uploadRecord);
line = readLine(in);
if("--file begin--".equals(line)){
saveFile(in, request,task);
}
}
/**
* 文件上传完成,将状态修改为 “stoped”
*/
if(uploadRecord != null){
ConfigFileUtils.setConfigFileStoped(request, uploadRecord);
}
}
}
} catch (IOException e) {
/**
* 上传过程中出现异常,将状态修改为 “stoped”
*/
e.printStackTrace();
}finally{
/**
* 上传过程中出现异常,将状态修改为 “stoped”
*/
if(uploadRecord != null){
ConfigFileUtils.setConfigFileStoped(request, uploadRecord);
}
if(raf != null){
try {
raf.close();
} catch (IOException e1) {
e1.printStackTrace();
}
raf = null;
}
}
}
}
最大的不同是:1:conn.setChunkedStreamingMode(1024*1024);
//取得序列化对象的大小
或者2:
/*ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(record);
oos.flush();
//流的大小为文件大小 + 序列化对象大小 - 已上传的文件大小
int stream_size = (int)(file.length()+bos.size()-begin);
conn.setFixedLengthStreamingMode(stream_size);*/
以上两种方法都可以实现获取真正的输出流,而不是缓冲到本地,等getInputstream的时候才输出,这样就不会出现大文件时,内存溢出的情况了
查询断点记录servlet:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.lubansoft.test.upload.po.UploadRecord;
import com.lubansoft.test.upload.utils.ConfigFileUtils;
//查询文件上传历史记录的servlet
public class GetUploadHistory extends HttpServlet {
private static final long serialVersionUID = 1L;
private int blockSize ;
public GetUploadHistory(){
try {
Properties prop = new Properties();
prop.load(this.getClass().getResourceAsStream("/blockSize.properties"));
blockSize = Integer.parseInt(prop.getProperty("blockSize"));
if(blockSize == 0){
blockSize = 20480;
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Properties prop = null;
OutputStream out = null;
InputStream is = null;
File dir = null;
File file = null;
try {
InputStream in = request.getInputStream();
String line = ConfigFileUtils.readLine(in);
if(line == null){
return;
}
String[] keyValues = line.split(";");
if(keyValues == null || keyValues.length<=0){
return;
}
int length = keyValues.length;
//先拿到要查询的文件名
UploadRecord[] uploadRecords = new UploadRecord[length];
for(int i=0;i<length;i++){
uploadRecords[i] = ConfigFileUtils.getUploadRecoreFromString(keyValues[i]);
}
UploadRecord r = null;
if(uploadRecords != null && uploadRecords.length>0){
for(int i=0;i<uploadRecords.length;i++){
r = uploadRecords[i];
prop = new Properties();
r.setIp(request.getRemoteAddr());
HttpSession session = request.getSession();
//指定配置文件的文件夹
String serverPath = session.getServletContext().getRealPath(
"/uploadConfig");
dir = new File(serverPath);
if (!dir.exists()) {
dir.mkdirs();
}
//指定配置文件名
String path = serverPath + File.separator + r.getIp() + "-" + r.getFileName()
+ ".properties";
file = new File(path);
if (!file.exists()) {
file.createNewFile();
}
is = new FileInputStream(file);
prop.load(is);
String uploadSize = prop.getProperty("uploadSize") == null ? 0+"" : prop.getProperty("uploadSize");
String fileName = prop.getProperty("fileName") == null ? r.getFileName() : prop.getProperty("fileName");
String fileSize = prop.getProperty("fileSize") == null ? r.getFileSize()+"" : prop.getProperty("fileSize");
String isStarted = prop.getProperty("isStarted") == null ? "false" : prop.getProperty("isStarted");
String ip = request.getRemoteAddr();
prop.setProperty("uploadSize", uploadSize);
prop.setProperty("fileName", fileName);
prop.setProperty("fileSize", fileSize);
prop.setProperty("ip", ip);
prop.setProperty("isStarted", isStarted);
out = new FileOutputStream(file);
prop.store(out, "comments");
out.flush();
out.close();
out = null;
r.setUploadSize(Long.parseLong(uploadSize));
r.setFileName(fileName);
r.setFileSize(Long.parseLong(fileSize));
r.setIp(ip);
r.setIsStarted(isStarted);
uploadRecords[i] = r;
}
}
StringBuilder sb = new StringBuilder();
for(int i=0;i<length;i++){
sb.append("fileName="+uploadRecords[i].getFileName()+"&fileSize="+uploadRecords[i].getFileSize()+"&uploadSize="+uploadRecords[i].getUploadSize());
if(i != length){
sb.append("\n");
}
}
OutputStream outputStream = response.getOutputStream();
outputStream.write(sb.toString().getBytes("utf-8"));
outputStream.flush();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}finally{
if(out != null){
out.flush();
out.close();
out = null;
}
if(is != null){
is.close();
is = null;
}
if(prop != null){
prop.clear();
prop = null;
}
if(dir != null){
dir = null;
}
if(file != null){
file = null;
}
}
}
}
查询上传速度和百分比servlet:
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lubansoft.test.upload.utils.ConfigFileUtils;
//获取上传速度和百分比的servlet
public class GetUploadRateAndPercent extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String filepath = request.getParameter("filepath");
if(filepath != null && !"".equals(filepath)){
String filename = filepath.substring(filepath.lastIndexOf("\\")+1);
String isStarted = "false";
if("true".equals(ConfigFileUtils.isUploadStarted(request, filename))){
isStarted = "true";
}else if("false".equals(ConfigFileUtils.isUploadStarted(request, filename))){
isStarted = "false";
}
String[] rateAndPercent = ConfigFileUtils.getUploadRate(request,filename);
/**
* 返回给页面一个字符串:
* "{fileName:\""+ filename + "\",isStarted:\"" + isStarted + "\",rate:\"" + rateAndPercent[0] +"\",percent:\"" + rateAndPercent[1] +"\"}"
*/
String result = "{fileName:\""+ filename + "\",isStarted:\"" + isStarted + "\",rate:\"" + rateAndPercent[0] +"\",percent:\"" + rateAndPercent[1] +"\"}";
response.setCharacterEncoding("utf-8");
response.getWriter().write(result);
response.getWriter().flush();
response.getWriter().close();
}
}
}
用到的util:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import com.lubansoft.test.upload.po.UploadRatePercent;
import com.lubansoft.test.upload.po.UploadRecord;
public class ConfigFileUtils {
//更新上传文件的上传速度和百分比
public static void updateRateInfoFile(HttpServletRequest request ,String fileName, UploadRatePercent uploadRatePercent){
FileInputStream in = null;
File rateInfoFie = null;
Properties prop = null;
try {
HttpSession session = request.getSession();
String folder = session.getServletContext().getRealPath("/uploadRate");
String filepath = folder+File.separator+request.getRemoteAddr()+"-"+fileName+"-"+"RateAndPercent.properties";
rateInfoFie = new File(filepath);
if(! rateInfoFie.getParentFile().exists()){
rateInfoFie.getParentFile().mkdirs();
}
if(! rateInfoFie.exists()){
rateInfoFie.createNewFile();
}
prop = new Properties();
in = new FileInputStream(rateInfoFie);
prop.load(in);
prop.setProperty("fileName", prop.getProperty("fileName") == null ? fileName : prop.getProperty("fileName"));
prop.setProperty("rate", uploadRatePercent.getRate()+"");
prop.setProperty("percent", uploadRatePercent.getPercent()+"");
FileOutputStream o = new FileOutputStream(rateInfoFie);
prop.store(o, "comments");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(in != null){
try {
in.close();
in = null;
rateInfoFie = null;
prop = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//更新已经上传文件大小
public static void updateUploadSize(HttpServletRequest request ,UploadRecord uploadRecord , long addSize) {
FileInputStream in = null;
File rateInfoFie = null;
Properties prop = null;
try {
HttpSession session = request.getSession();
String folder = session.getServletContext().getRealPath("/uploadConfig");
String filepath = folder+File.separator+request.getRemoteAddr()+"-"+uploadRecord.getFileName() + ".properties";
rateInfoFie = new File(filepath);
if(! rateInfoFie.getParentFile().exists()){
rateInfoFie.getParentFile().mkdirs();
}
if(! rateInfoFie.exists()){
rateInfoFie.createNewFile();
}
prop = new Properties();
in = new FileInputStream(rateInfoFie);
prop.load(in);
String old_uploadSize = prop.getProperty("uploadSize");
if(old_uploadSize == null){
old_uploadSize = "0";
}
long uploadSize = Long.parseLong(old_uploadSize);
prop.setProperty("uploadSize", uploadSize + addSize + "");
prop.setProperty("isStarted", "true");
FileOutputStream o = new FileOutputStream(rateInfoFie);
prop.store(o, "comments");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(in != null){
try {
in.close();
in = null;
rateInfoFie = null;
prop = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//更新该用户该文件的上传状态为“已停止”
public static void setConfigFileStoped(HttpServletRequest request ,UploadRecord uploadRecord){
FileInputStream in = null;
File rateInfoFie = null;
Properties prop = null;
try {
HttpSession session = request.getSession();
String folder = session.getServletContext().getRealPath("/uploadConfig");
String filepath = folder+File.separator+request.getRemoteAddr()+"-"+uploadRecord.getFileName() + ".properties";
rateInfoFie = new File(filepath);
if(! rateInfoFie.getParentFile().exists()){
rateInfoFie.getParentFile().mkdirs();
}
if(! rateInfoFie.exists()){
rateInfoFie.createNewFile();
}
prop = new Properties();
in = new FileInputStream(rateInfoFie);
prop.load(in);
prop.setProperty("isStarted", "false");
FileOutputStream o = new FileOutputStream(rateInfoFie);
prop.store(o, "comments");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(in != null){
try {
in.close();
in = null;
rateInfoFie = null;
prop = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
*
* Created on 2013-5-10
* <p>Discription:查询上传的速度和百分比</p>
* @author:田超辉 tianchaohui@dev.com
* @update:[日期YYYY-MM-DD] [更改人姓名]
* @return String[]
*/
public static String[] getUploadRate(HttpServletRequest request ,String fileName){
FileInputStream in = null;
File rateInfoFie = null;
Properties prop = null;
try {
HttpSession session = request.getSession();
String folder = session.getServletContext().getRealPath("/uploadRate");
String path = folder+File.separator+request.getRemoteAddr()+"-"+fileName+"-"+"RateAndPercent.properties";
rateInfoFie = new File(path);
if(! rateInfoFie.getParentFile().exists()){
rateInfoFie.getParentFile().mkdirs();
}
if(! rateInfoFie.exists()){
rateInfoFie.createNewFile();
}
prop = new Properties();
in = new FileInputStream(rateInfoFie);
prop.load(in);
String rate = prop.getProperty("rate") == null ? "0" : prop.getProperty("rate");
String percent = prop.getProperty("percent") == null ? "0" : prop.getProperty("percent");
return new String[]{rate,percent};
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(in != null){
try {
in.close();
in = null;
rateInfoFie = null;
prop = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
return new String[]{"",""};
}
/**
*
* Created on 2013-5-10
* <p>Discription:查询该用户 该文件 的上传状态为“已启动”</p>
* @author:田超辉 tianchaohui@dev.com
* @update:[日期YYYY-MM-DD] [更改人姓名]
* @return boolean
*/
public static boolean isUploadStarted(HttpServletRequest request ,String fileName){
FileInputStream in = null;
File rateInfoFie = null;
Properties prop = null;
try {
HttpSession session = request.getSession();
String folder = session.getServletContext().getRealPath("/uploadConfig");
String filepath = folder+File.separator+request.getRemoteAddr()+"-"+ fileName + ".properties";
rateInfoFie = new File(filepath);
if(! rateInfoFie.getParentFile().exists()){
rateInfoFie.getParentFile().mkdirs();
}
if(! rateInfoFie.exists()){
rateInfoFie.createNewFile();
}
prop = new Properties();
in = new FileInputStream(rateInfoFie);
prop.load(in);
if("true".equals(prop.getProperty("isStarted"))){
return true;
}else if("false".equals(prop.getProperty("isStarted"))){
return false;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(in != null){
try {
in.close();
in = null;
rateInfoFie = null;
prop = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}
/**
*
* Created on 2013-5-13
* <p>Discription:读取一行内容</p>
* @author:田超辉 tianchaohui@dev.com
* @update:[日期YYYY-MM-DD] [更改人姓名]
* @return String
*/
public static String readLine(InputStream in){
String result = null;
try {
byte[] b = new byte[1];
int n = -1;
while((n = in.read()) != -1){
if(n == '\r' || n == '\n'){
break;
}else{
b[b.length-1] = (byte)n;
b = Arrays.copyOf(b, b.length+1);
}
}
if(b.length <= 1){
return null;
}
b = Arrays.copyOf(b, b.length-1);
return new String(b,"utf-8");
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
/**
* 从字符串中提取出UploadRecord对象
* "fileName="+f.getName()+"&fileSize="+f.length()+"&uploadSize="f.getUploadSize()
*/
public static UploadRecord getUploadRecoreFromString(String line) {
UploadRecord record = null;
if(line == null){
return null;
}
String[] keyValues = line.split("&");
if(keyValues == null || keyValues.length<=0){
return null;
}
record = new UploadRecord();
int length = keyValues.length;
for(int i=0;i<length;i++){
if("fileName".equals(keyValues[i].split("=")[0])){
record.setFileName(keyValues[i].split("=")[1]);
}else if("fileSize".equals(keyValues[i].split("=")[0])){
record.setFileSize(Long.parseLong(keyValues[i].split("=")[1]));
}else if("uploadSize".equals(keyValues[i].split("=")[0])){
record.setUploadSize(Long.parseLong(keyValues[i].split("=")[1]));
}
}
return record;
}
}
优化之前:
客户端代码:
package com.lubansoft.test.upload.client;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;
import com.lubansoft.test.upload.po.UploadRecord;
public class SimpleUrlConnection {
private HttpURLConnection conn;
private OutputStream out = null;
private File file = null;
private UploadRecord record = null;
private MathContext mc_rate = new MathContext(4, RoundingMode.HALF_DOWN);
private MathContext mc_percent = new MathContext(3, RoundingMode.HALF_DOWN);
private static long total_uploadSize = 0;
boolean isShowRate = false;
public SimpleUrlConnection(String pathname){
file = new File(pathname);
}
//分块上传begin该块的起点,end该块的终点,blockSize每块的大小
public void upload(long begin,long end,long blockSize){
try {
String url = "http://localhost:8080/upload/uploadServlet";
URL u = new URL(url);
conn = (HttpURLConnection) u.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("Charsert", "UTF-8");
out = conn.getOutputStream();
//RandomAccessFile是断点上传的关键(其实也是断点下载的关键),可以从文件任意位置随机读写r,rw,rwd(读写时用),rws
RandomAccessFile in = new RandomAccessFile(file, "r");
byte[] b = null;
int n = -1;
int total = 0;
in.seek(begin);
b = new byte[2048];
record = new UploadRecord();
record.setUploadSize(begin);
record.setFileName(file.getName());
record.setFileSize(file.length());
record.setBlockSize(blockSize);
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(record);
long begin_timemilis = System.currentTimeMillis();
while ((n = in.read(b)) != -1) {
total += n;
if((total+begin)<=end){
out.write(b, 0, n);
total_uploadSize += n;
}else{
if((total+begin)<(end+b.length)){
total-=n;
n=(int) (end-total-begin);
total+=n;
out.write(b,0,n);
total_uploadSize += n;
}else{
total-=n;
break;
}
}
}
//该http请求真正发送出去的地方conn.getInputStream(),如果不调用该方法,则不发出请求
BufferedReader reader = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
// System.out.println(line);
}
// BigDecimal cost_time = new BigDecimal(System.currentTimeMillis()-begin_timemilis+"").divide(new BigDecimal(1000+""),mc);
// BigDecimal send_file_size = new BigDecimal(end-begin+"").divide(new BigDecimal(1024+""));
// double rate = send_file_size.divide(cost_time,mc).doubleValue();
// System.out.println(rate + " k/s"+ " 所用时间为:"+(System.currentTimeMillis()-begin_timemilis)/1000+" s "+" 传输的文件大小为: " +(end-begin)/1024+" k "+((end-begin)==total)+" " +
// " begin: "+begin+" b end: "+end+" b");
// double percent = new BigDecimal((total+begin)*100+"").divide(new BigDecimal(record.getFileSize()+""),mc).doubleValue();
// System.out.println(percent+" %");
}catch(ArithmeticException e){
//e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
SimpleUrlConnection suc = new SimpleUrlConnection("E:\\我的文档\\下载\\jetty-6.1.26.zip");
suc.method();
}
//用于显示上传速度和百分比
class uploadRateTimerTask extends TimerTask{
private long pre_uploadSize = 0;
private double rate = 0;
private double uploadPercent;
private long fileSize = (file == null ? 0 :file.length());
@Override
public void run() {
if(pre_uploadSize <= total_uploadSize && fileSize != 0 && isShowRate){
rate = new BigDecimal(total_uploadSize+"").subtract(new BigDecimal(pre_uploadSize+"")).divide(new BigDecimal(1024+""),mc_rate).doubleValue();
// rate = 2*(total_uploadSize - pre_uploadSize)/1024;
// uploadPercent = 100.0*total_uploadSize/fileSize;
uploadPercent = new BigDecimal(100+"").multiply(new BigDecimal(total_uploadSize+"")).divide(new BigDecimal(fileSize+""),mc_percent).doubleValue();
System.out.println(rate+" k/s " + uploadPercent +" %");
pre_uploadSize = total_uploadSize;
}
}
}
private void method() {
//上传文件之前先获取上传记录
record = getUploadRecord();
Timer timer = new Timer();
uploadRateTimerTask task = new uploadRateTimerTask();
//指定每隔0.5s执行一次定时器
timer.schedule(task, 0 , 500);
long fileSize = record.getFileSize();
long uploadSize = record.getUploadSize();
long blockSize = record.getBlockSize();
int num = (int) ((fileSize-uploadSize)%blockSize == 0 ? (fileSize-uploadSize)/blockSize : (fileSize-uploadSize)/blockSize + 1);
long begin=0,end=0;
//开始分段上传文件(如果以前有上传记录,则从断点处开始上传,从而实现断点上传)
for(int i = 0;i<num ;i++){
//uploadSize:已上传的文件大小
begin = i*blockSize+uploadSize;
end =((i+1)*blockSize+uploadSize)<=fileSize ? (i+1)*blockSize+uploadSize : fileSize;
//开始分块上传文件
upload(begin, end,blockSize);
}
System.out.println("100 %");
//取消定时器
timer.cancel();
}
//获取上传记录
public UploadRecord getUploadRecord(){
try {
URL url = new URL("http://localhost:8080/upload/getUploadHistory");
conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("Charsert", "UTF-8");
out = conn.getOutputStream();
record = new UploadRecord();
record.setFileName(file.getName());
record.setFileSize(file.length());
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(record);
ObjectInputStream ois = new ObjectInputStream(conn.getInputStream());
record = (UploadRecord) ois.readObject();
isShowRate = true;
total_uploadSize = record.getUploadSize();
oos.close();
ois.close();
oos=null;
ois = null;
}catch(Exception e){
e.printStackTrace();
}
return record;
}
}
获取上传历史记录的servlet:
package com.lubansoft.test.upload.web.servlet;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.lubansoft.test.upload.po.UploadRecord;
//查询文件上传历史记录的servlet
public class GetUploadHistory extends HttpServlet {
private static final long serialVersionUID = 1L;
private int blockSize = 204800;//200k
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
InputStream in = request.getInputStream();
ObjectInputStream ois = new ObjectInputStream(in);
UploadRecord r = (UploadRecord) ois.readObject();
Properties prop = new Properties();
r.setIp(request.getRemoteAddr());
HttpSession session = request.getSession();
//指定配置文件的文件夹
String serverPath = session.getServletContext().getRealPath(
"/uploadConfig");
File dir = new File(serverPath);
if (!dir.exists()) {
dir.mkdirs();
}
//指定配置文件名
String path = serverPath + "/" + r.getIp() + "-" + r.getFileName()
+ "-" + r.getFileSize() + ".properties";
File file = new File(path);
if (!file.exists()) {
file.createNewFile();
}
prop.load(new FileInputStream(file));
String uploadSize = prop.getProperty("uploadSize") == null ? 0+"" : prop.getProperty("uploadSize");
String fileName = prop.getProperty("fileName") == null ? r.getFileName() : prop.getProperty("fileName");
String fileSize = prop.getProperty("fileSize") == null ? r.getFileSize()+"" : prop.getProperty("fileSize");
String ip = request.getRemoteAddr();
/*if(uploadSize != null && ! "0".equals(uploadSize) && !uploadSize.equals(fileSize)){
long uploadSize_value = Long.parseLong(uploadSize);
uploadSize_value -= blockSize;
uploadSize = uploadSize_value+"";
}*/
prop.setProperty("uploadSize", uploadSize);
prop.setProperty("fileName", fileName);
prop.setProperty("fileSize", fileSize);
prop.setProperty("blockSize", blockSize+"");
prop.setProperty("ip", ip);
r.setUploadSize(Long.parseLong(uploadSize));
r.setFileName(fileName);
r.setFileSize(Long.parseLong(fileSize));
r.setBlockSize(blockSize);
r.setIp(ip);
OutputStream o = new FileOutputStream(file);
prop.store(o, "comments");
o.flush();
o.close();
ObjectOutputStream oos = new ObjectOutputStream(response.getOutputStream());
oos.writeObject(r);
oos.flush();
oos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
文件上传的servlet:
package com.lubansoft.test.upload.web.servlet;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.lubansoft.test.upload.po.UploadRecord;
//文件上传的servlet
public class FileUpload extends HttpServlet {
private static final long serialVersionUID = 1L;
int i = 0;
public FileUpload() {
super();
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
RandomAccessFile randomAccessFile = null;
Properties prop = null;
File file = null;
String path = null;
String serverPath = null;
UploadRecord r = null;
HttpSession session = request.getSession();
OutputStream o = null;
boolean isConfigFileChanged = false;
try {
InputStream in = request.getInputStream();
ObjectInputStream ois = new ObjectInputStream(in);
r = (UploadRecord) ois.readObject();
//指定保存文件的文件夹
serverPath = session.getServletContext()
.getRealPath("/uploadFiles");
File dir = new File(serverPath);
if (!dir.exists()) {
dir.mkdirs();
}
//指定保存的文件名
path = serverPath + "/" + r.getFileName();
file = new File(path);
if (!file.exists()) {
file.createNewFile();
}
// 开始位置
long begin = r.getUploadSize();
// 随机读写操作rwd
randomAccessFile = new RandomAccessFile(file, "rwd");
if (file.length() != r.getFileSize()) {
randomAccessFile.setLength(r.getFileSize());
}
// 指定读写操作的开始位置
randomAccessFile.seek(begin);
int n = -1;
byte[] b = new byte[2048];
int total = 0;
while ((n = in.read(b)) != -1) {
total += n;
randomAccessFile.write(b, 0, n);
}
System.out.println("begin+total: " + (begin + total)
+ " begin: " + begin + " -- total: " + total
+ " -- ------------");
i += total;
System.out.println(i);
prop = new Properties();
r.setIp(request.getRemoteAddr());
serverPath = session.getServletContext().getRealPath(
"/uploadConfig");
dir = new File(serverPath);
if (!dir.exists()) {
dir.mkdirs();
}
path = serverPath + "/" + r.getIp() + "-" + r.getFileName() + "-"
+ r.getFileSize() + ".properties";
file = new File(path);
if (!file.exists()) {
file.createNewFile();
}
prop.load(new FileInputStream(file));
System.out.println(file.getAbsolutePath());
String uploadSize = prop.getProperty("uploadSize");
if (uploadSize == null) {
uploadSize = "0";
}
long temp = Long.parseLong(uploadSize) + total;
prop.setProperty("uploadSize", temp + "");
//执行到这里的话,如果出了异常,则需要将这次操作回滚
isConfigFileChanged = true;
o = new FileOutputStream(file);
prop.store(o, "comments");
response.getWriter().write("OK");
} catch (Exception e) {
if (r != null && isConfigFileChanged) {
updateConfigFile(r, request, response);
}
e.printStackTrace();
} finally {
if (randomAccessFile != null) {
randomAccessFile.close();
randomAccessFile = null;
}
}
}
//出异常的时候,配置文件回滚
private void updateConfigFile(UploadRecord r, HttpServletRequest request,
HttpServletResponse response) {
try {
Properties prop = new Properties();
String serverPath = request.getSession().getServletContext()
.getRealPath("/uploadConfig");
r.setIp(request.getRemoteAddr());
String path = serverPath + "/" + r.getIp() + "-" + r.getFileName()
+ "-" + r.getFileSize() + ".properties";
File file = new File(path);
FileInputStream in = new FileInputStream(file);
prop.load(in);
if (r != null) {
prop.setProperty("uploadSize", (r.getUploadSize() - r.getBlockSize()) + "");
FileOutputStream o = new FileOutputStream(file);
prop.store(o, "comments");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 查询上传历史记录 -->
<servlet>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>com.lubansoft.test.upload.web.servlet.FileUpload</servlet-class>
</servlet>
<servlet>
<servlet-name>GetUploadHistory</servlet-name>
<servlet-class>com.lubansoft.test.upload.web.servlet.GetUploadHistory</servlet-class>
</servlet>
<!-- 文件上传的servlet -->
<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/uploadServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>GetUploadHistory</servlet-name>
<url-pattern>/getUploadHistory</url-pattern>
</servlet-mapping>
</web-app>
jar包,可能有多余的: