使用ChannelSftp上传文件,并展示进度
- 前端页面
- 工具类 FTPUtils
- 自定义定时监听器**FileProgressMonitor **
- 进程单例类**ScheduleSingLeTon**
- Controller
前端页面
点击上传按钮后,异步递归获取文件上传进度
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="js/jquery-1.7.1.min.js"></script>
</head>
<style type="text/css">
progress {
background-color: #56BE64;
}
progress::-webkit-progress-bar {
background: #ccc;
}
progress::-webkit-progress-value {
background: #56BE64;
}
percentage{
position: fixed;
left: 160px;
}
</style>
<body>
<h1>Spring Boot file upload example</h1>
<form id="FileuploadForm" method="POST" action="/upload" enctype="multipart/form-data">
<input type="file" name="uploadFile" id="file"/><br />
<br /> <input type="button" value="上传文件" onclick="upload()" />
<div id="msg"></div>
</form>
<!--进度条部分(默认隐藏)-->
<div style="display: none" class="progress-body">
<div>
<progress></progress><percentage>0%</percentage>
</div>
<div>
<span style="width: 100px; display: inline-block; text-align: right">上传速度:</span>
<span style="margin-bottom: 10px; margin-left: 30px; width: 300px;" class="progress-speed">0 M/S, 0/0M</span>
</div>
<div>
<span style="width: 100px; display: inline-block; text-align: right">上传状态:</span>
<span style="margin-bottom: 10px; margin-left: 30px; width: 300px;" class="progress-info">请选择文件并点击上传文件按钮</span>
</div>
</div>
</body>
</html>
<script>
var percent = 0;
// 上传文件
function upload(){
$("#msg").text("");
var checkFile = $("#uploadFile").val();
var msgInfo = "";
if(null==checkFile || ""==checkFile){
$("#msg").text("文件为空,请选择文件!");
}else{
//开始显示进度条
showProgress();
//递归获取上传进度
completeHandle();
var formData = new FormData(document.getElementById("FileuploadForm"));
$.ajax({
type: "POST",
enctype:'multipart/form-data',
url: '/myserver',
data: formData,
cache:false,
processData:false,
contentType:false,
error:function(result){
console.log("error");
console.log(result);
flag = false;
$("#msg").text("访问服务器错误,请重试!");
},
success: function(result){
console.log("success");
$('.progress-body percentage').html("100.00%");
$('.progress-body .progress-info').html("上传文件完成。");
//定时,2秒后执行hideProgress方法
setTimeout(hideProgress, 2000);
},
/*从前端页面上传至后台的进度展示
xhr: function () {
var xhr = $.ajaxSettings.xhr();
if (xhr.upload) {
//处理进度条的事件
xhr.upload.addEventListener("progress", progressHandle, false);
//加载完成的事件
xhr.addEventListener("load", completeHandle, false);
//加载出错的事件
xhr.addEventListener("error", failedHandle, false);
//加载取消的事件
xhr.addEventListener("abort", canceledHandle, false);
//开始显示进度条
showProgress();
return xhr;
}
}*/
}, 'json');
}
}
var start = 0;
//显示进度条的函数
function showProgress() {
start = new Date().getTime();
$(".progress-body").css("display", "block");
}
//隐藏进度条的函数
function hideProgress() {
$("#uploadFile").val('');
percent = 0;
$('.progress-body progress').attr({value: 0, max: 0});
$('.progress-body .progress-speed').html("0 M/S, 0/0M");
$('.progress-body percentage').html("0%");
$('.progress-body .progress-info').html("请选择文件并点击上传文件按钮");
$(".progress-body").css("display", "none");
}
//进度条更新
function progressHandle(e) {
/* $('.progress-body progress').attr({value: e.loaded, max: e.total});
var percent = e.loaded / e.total * 100;
var time = ((new Date().getTime() - start) / 1000).toFixed(3);
if(time == 0){
time = 1;
}
$('.progress-body .progress-speed').html(((e.loaded / 1024) / 1024 / time).toFixed(2) + "M/S, " + ((e.loaded / 1024) / 1024).toFixed(2) + "/" + ((e.total / 1024) / 1024).toFixed(2) + " MB. ");
$('.progress-body percentage').html(percent + "%");
if (percent == 100) {
$('.progress-body .progress-info').html("上传完成,后台正在处理...");
} else {
$('.progress-body .progress-info').html("文件上传中...");
}*/
};
//上传完成处理函数
/* function completeHandle() {
$('.progress-body .progress-info').html("上传文件完成。");
setTimeout(hideProgress, 2000);
};*/
function completeHandle(){
//if(percent == 100 ){
//$('.progress-body .progress-info').html("上传文件完成。");
//return;
//}
var url = "/getprogressMonitor";
$.ajax({
type: 'get',
url: url,
dataType: "json",
contentType:"application/json;charset=utf-8",
success: function(json){
percent = json.plan;
$('.progress-body progress').attr({value: json.transfered, max: json.fileSize});
$('.progress-body percentage').html(percent + "%");
$('.progress-body .progress-info').html("上传中");
if(son.transfered == json.fileSize && json.fileSize != 0){
$('.progress-body percentage').html("100%");
$('.progress-body .progress-info').html("上传文件完成。");
return;
}
completeHandle();
},
error: function(data){
}
});
}
//上传出错处理函数
function failedHandle(e) {
$('.progress-body .progress-info').html("上传文件出错, 服务不可用或文件过大。");
};
//上传取消处理函数
function canceledHandle(e) {
$('.progress-body .progress-info').html("上传文件取消。");
};
</script>
工具类 FTPUtils
再上传文件时 通过实现SftpProgressMonitor接口来获取文件上传进度
import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.Properties;
import java.util.Vector;
public class FTPUtils {
private static final Logger LOG = LoggerFactory.getLogger(FTPUtil.class);
private static ChannelSftp sftp = null;
public FTPUtils() {
}
public static FTPUtils getConnect(String ftphost, String ftpusername, String ftppassword, int ftpport) {
FTPUtils ftp = new FTPUtils();
try {
JSch jsch = new JSch();
Session sshSession = jsch.getSession(ftpusername, ftphost, ftpport);
sshSession.setPassword(ftppassword);
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
sshSession.setConfig(sshConfig);
sshSession.connect();
Channel channel = sshSession.openChannel("sftp");
channel.connect();
sftp = (ChannelSftp)channel;
} catch (Exception var9) {
var9.printStackTrace();
}
return ftp;
}
public String upload(String uploadFile, String directory, String filename) {
File file = null;
String fileName = null;
FileInputStream in = null;
OutputStream outputStream = null;
FileProgressMonitor fileProgressMonitor = null;
try {
sftp.cd(directory);
file = new File(uploadFile);
in = new FileInputStream(file);
/*byte[] bytes = new byte[1024];
outputStream = sftp.put(filename);
int aa = 0;
while ((aa = in.read(bytes)) != -1) {
outputStream.write(bytes, 0, aa);
}*/
fileProgressMonitor = new FileProgressMonitor(file.length());
sftp.put(uploadFile,filename,fileProgressMonitor,ChannelSftp.OVERWRITE);
} catch (Exception var47) {
var47.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
if(outputStream != null){
outputStream.close();
}
} catch (IOException var45) {
var45.printStackTrace();
} finally {
in = null;
}
}
}
return (String)(file == null ? null : fileName);
}
public void download(String ftpdir, String downloadFileName, String localfilepath) {
FileOutputStream out = null;
try {
sftp.cd(ftpdir);
File file = new File(localfilepath);
out = new FileOutputStream(file);
sftp.get(downloadFileName, out);
out.flush();
} catch (Exception var45) {
var45.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException var43) {
var43.printStackTrace();
} finally {
out = null;
}
}
}
}
public Vector listFiles(String directory) throws SftpException {
return sftp.ls(directory);
}
public void disconnect() {
sftp.quit();
sftp.exit();
sftp.disconnect();
}
}
自定义定时监听器**FileProgressMonitor **
import com.jcraft.jsch.SftpProgressMonitor;
import com.web.model.ScheduleSingLeTon;
import java.text.DecimalFormat;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class FileProgressMonitor extends TimerTask implements SftpProgressMonitor {
// 默认间隔时间为5秒
private long progressInterval = 5 * 1000;
private boolean isEnd = false; // 记录传输是否结束
private long transfered; // 记录已传输的数据总大小
private long fileSize; // 记录文件总大小
private ScheduledThreadPoolExecutor scheduled; // 定时器对象
private boolean isScheduled = false; // 记录是否已启动timer记时器
//自定义的进度单例类(前端查询进度时,返回该对象)
//有其他好的方法欢迎留言
ScheduleSingLeTon insteans = ScheduleSingLeTon.getInsteans();
public FileProgressMonitor(long fileSize) {
this.fileSize = fileSize;
insteans.setFileSize(fileSize);
}
@Override
public void run() {
if (!isEnd()) { // 判断传输是否已结束
System.out.println("Transfering is in progress.");
long transfered = getTransfered();
if (transfered != fileSize) { // 判断当前已传输数据大小是否等于文件总大小
System.out.println("Current transfered: " + transfered + " bytes");
sendProgressMessage(transfered);
} else {
System.out.println("File transfering is done.");
setEnd(true); // 如果当前已传输数据大小等于文件总大小,说明已完成,设置end
}
} else {
System.out.println("Transfering done. Cancel timer.");
stop(); // 如果传输结束,停止timer记时器
return;
}
}
public void stop() {
System.out.println("Try to stop progress monitor.");
if (scheduled != null) {
scheduled.shutdownNow();
scheduled = null;
isScheduled = false;
}
System.out.println("Progress monitor stoped.");
}
public void start() {
System.out.println("Try to start progress monitor.");
if (scheduled == null) {
scheduled = new ScheduledThreadPoolExecutor(1);
}
scheduled.scheduleAtFixedRate(this,0,1000, TimeUnit.MILLISECONDS);
insteans.setTransfered(0L);
insteans.setPlan("0.00");
isScheduled = true;
System.out.println("Progress monitor started.");
}
/**
* 打印progress信息
* @param transfered
*/
private void sendProgressMessage(long transfered) {
if (fileSize != 0) {
double d = ((double)transfered * 100)/(double)fileSize;
DecimalFormat df = new DecimalFormat( "#.##");
System.out.println("Sending progress message: " + df.format(d) + "%");
insteans.setPlan(df.format(d));
} else {
System.out.println("Sending progress message: " + transfered);
}
}
/**
* 实现了SftpProgressMonitor接口的count方法
*/
@Override
public boolean count(long count) {
if (isEnd()){
return false;
}
if (!isScheduled) {
start();
}
add(count);
return true;
}
/**
* 实现了SftpProgressMonitor接口的end方法
*/
@Override
public void end() {
setEnd(true);
insteans.setFileSize(0L);
insteans.setTransfered(0L);
insteans.setPlan("0.00");
System.out.println("transfering end.");
}
private synchronized void add(long count) {
transfered = transfered + count;
insteans.setTransfered(transfered);
}
private synchronized long getTransfered() {
return transfered;
}
public synchronized void setTransfered(long transfered) {
this.transfered = transfered;
}
private synchronized void setEnd(boolean isEnd) {
this.isEnd = isEnd;
}
private synchronized boolean isEnd() {
return isEnd;
}
@Override
public void init(int op, String src, String dest, long max) {
// Not used for putting InputStream
}
}
进程单例类ScheduleSingLeTon
public class ScheduleSingLeTon {
private static final ScheduleSingLeTon INSTEANS = new ScheduleSingLeTon();
private long transfered; // 记录已传输的数据总大小
private long fileSize; // 记录文件总大小
//进度
private String plan ="0.00";
public long getTransfered() {
return transfered;
}
public void setTransfered(long transfered) {
this.transfered = transfered;
}
public long getFileSize() {
return fileSize;
}
public void setFileSize(long fileSize) {
this.fileSize = fileSize;
}
public String getPlan() {
return plan;
}
public void setPlan(String plan) {
this.plan = plan;
}
private ScheduleSingLeTon(){
}
public static ScheduleSingLeTon getInsteans(){
return INSTEANS;
}
}
Controller
@Controller
@RequestMapping("/upload")
public class UploadCtrl {
private static final String TMP_PATH = "f:/projects/tmp";
ScheduleSingLeTon insteans = ScheduleSingLeTon.getInsteans();
@RequestMapping(value = "", method = RequestMethod.GET)
public String fileUploadInit() {
// InfoMsg infoMsg = new InfoMsg();
return "upload";
}
@RequestMapping(value = "", method = RequestMethod.POST)
@ResponseBody
public ResultDto fileUpload(@RequestParam("uploadFile") MultipartFile multipartFile) {
ResultDto resultDto = new ResultDto();
if (multipartFile.isEmpty()) {
resultDto.setErrorCode("error");
resultDto.setErrorMessage("Please select a file to upload");
return resultDto;
}
try {
File localDirectorFile = new File(TMP_PATH);
if (localDirectorFile.isDirectory() && !localDirectorFile.exists()) {
localDirectorFile.mkdirs();
}
System.out.println(multipartFile.getOriginalFilename());
String pathName = multipartFile.getOriginalFilename();
FileCopyUtils.copy(multipartFile.getBytes(), new FileOutputStream(pathName));
FTPUtils ftpJSch = FTPUtils.getConnect("", "", "", 22);
int index = pathName.lastIndexOf('\\');
String newPathName = pathName.substring(index+1);
ftpJSch.upload("", "", "");
} catch (Exception e) {
e.printStackTrace();
}
return resultDto;
}
/*
* 获取上传进度
* */
@GetMapping("/getprogressMonitor")
public ScheduleSingLeTon getprogressMonitor(){
return insteans;
}
}