1,JQuery代码
#页面代码
<div id="uploader" class="wu-example" style="text-align: right">
<div id="thelist" class="uploader-list"></div>
<div class="btns">
<div id="picker" style="display: none;"></div>
</div>
<!-- <button id="ctlBtn" class="btn btn-default">开始上传</button>-->
<!-- <button id="stopBtn" class="btn btn-default">暂停</button>-->
<!-- <button id="restart" class="btn btn-default">开始</button>-->
</div>
#方法代码
$('.container').click(function(event) {
$("#picker").find('input').click();
});
var $btn = $('#ctlBtn');
var $thelist = $('#thelist');
var startDate;
// HOOK 这个必须要再uploader实例化前面
WebUploader.Uploader.register({
// 在文件发送之前执行
'before-send-file': 'beforeSendFile',
// 在文件分片(如果没有启用分片,整个文件被当成一个分片)后,上传之前执行
'before-send': 'beforeSend',
// 在文件所有分片都上传完后,且服务端没有错误返回后执行
"after-send-file": "afterSendFile"
}, {
beforeSendFile: function (file) {
startDate = new Date();
console.log("开始上传时间" + startDate)
console.log("beforeSendFile");
// Deferred对象在钩子回掉函数中经常要用到,用来处理需要等待的异步操作。
var deferred = WebUploader.Deferred();
//1、计算文件的唯一标记MD5,用于断点续传
uploader.md5File(file, 0, 3 * 1024 * 1024).progress(function (percentage) {
// 上传进度
console.log('上传进度:', percentage);
// getProgressBar(file, percentage, "MD5", "MD5");
}).then(function (val) { // 完成
console.log('File MD5 Result:', val);
file.md5 = val;
file.uid = WebUploader.Base.guid();
// 判断文件是否上传过,是否存在分片,断点续传
$.ajax({
type: "POST",
url: Feng.ctxPath + "bigfile/check",
async: false,
data: {
fileMd5: val,
groupId: group
},
success: function (data) {
var resultCode = data.resultCode;
// 秒传
if (resultCode == -1) {
// 文件已经上传过,忽略上传过程,直接标识上传成功;
uploader.skipFile(file);
file.pass = true;
} else {
//文件没有上传过,下标为0
//文件上传中断过,返回当前已经上传到的下标
file.indexcode = resultCode;
}
}, error: function () {
}
});
//获取文件信息后进入下一步
deferred.resolve();
});
return deferred.promise();
},
beforeSend: function (block) {
//获取已经上传过的下标
var indexchunk = block.file.indexcode;
var deferred = WebUploader.Deferred();
if (indexchunk > 0) {
if (block.chunk > indexchunk) {
//分块不存在,重新发送该分块内容
deferred.resolve();
} else {
//分块存在,跳过
deferred.reject();
}
} else {
//分块不存在,重新发送该分块内容
deferred.resolve();
}
//返回Deferred的Promise对象。
return deferred.promise();
}
, afterSendFile: function (file) {
//如果所有分块上传成功,则通知后台合并分块
$.ajax({
type: "POST",
url: Feng.ctxPath + "bigfile/merge",
data: {
fileName: file.name,
fileMd5: file.md5,
groupId: group
},
success: function (data) {
}, error: function () {
}
});
}
});
var uploader = WebUploader.create({
auto: true,
swf: Feng.ctxPath + '/static/js/plugins/webuploader/Uploader.swf',
server: Feng.ctxPath + 'bigfile/upload', // 服务器端处理上传的地址
dnd: '#addFile',
// pick: {
// id: '#picker',
// multiple: true,
// label: "点击选择文件上传"
// },
pick: '#picker',
chunked: true, // 开启分片上传
chunkSize: 5 * 1024 * 1024, // 切片大小为5MB
chunkRetry: 3, // 分片上传失败后的重试次数
threads: 3,// 上传并发数
disableGlobalDnd: true,
prepareNextFile: true, // 是否允许在文件传输时提前把下一个文件准备好。 对于一个文件的准备工作比较耗时,比如图片压缩,md5序列化。 如果能提前在当前文件传输期处理,可以节省总体耗时。
accept: {
title: 'Doc',
},
fileNumLimit: 1024,
fileSizeLimit: 50 * 1024 * 1024 * 1024,//50G 验证文件总大小是否超出限制, 超出则不允许加入队列
fileSingleSizeLimit: 10 * 1024 * 1024 * 1024 //10G 验证单个文件大小是否超出限制, 超出则不允许加入队列
});
// 当有文件被添加进队列的时候
uploader.on('fileQueued', function (file) {
$thelist.append('<div id="' + file.id + '" class="item">' +
'<h4 class="info">' + file.name + '</h4>' +
'<p class="state">等待上传...</p>' +
'</div>');
$("#stopBtn").click(function () {
uploader.stop(true);
});
$("#restart").click(function () {
uploader.upload(file);
});
});
//当某个文件的分块在发送前触发,主要用来询问是否要添加附带参数,大文件在开起分片上传的前提下此事件可能会触发多次。
uploader.onUploadBeforeSend = function (obj, data) {
//console.log("onUploadBeforeSend");
var file = obj.file;
data.md5 = file.md5 || '';
data.uid = file.uid;
};
// 上传中
uploader.on('uploadProgress', function (file, percentage) {
getProgressBar(file, percentage, "FILE", "上传进度");
});
// 上传返回结果
uploader.on('uploadSuccess', function (file) {
var endDate = new Date();
console.log("文件上传耗时:" + (endDate - startDate) / 1000 + "s")
var text = '已上传';
if (file.pass) {
text = "文件妙传功能,文件已上传。"
}
$('#' + file.id).find('p.state').text(text);
// 刷新页面
TDoc.table.refresh();
});
uploader.on('uploadError', function (file) {
$('#' + file.id).find('p.state').text('上传出错');
});
uploader.on('uploadComplete', function (file) {
// 隐藏进度条
fadeOutProgress(file, 'MD5');
fadeOutProgress(file, 'FILE');
});
// 文件上传
$btn.on('click', function () {
uploader.upload();
});
/**
* 生成进度条封装方法
*/
function getProgressBar(file, percentage, id_Prefix, titleName) {
var $li = $('#' + file.id), $percent = $li.find('#' + id_Prefix + '-progress-bar');
// 避免重复创建
if (!$percent.length) {
$percent = $('<div id="' + id_Prefix + '-progress" class="progress progress-striped active">' +
'<div id="' + id_Prefix + '-progress-bar" class="progress-bar" role="progressbar" style="width: 0%">' +
'</div>' +
'</div>'
).appendTo($li).find('#' + id_Prefix + '-progress-bar');
}
var progressPercentage = parseInt(percentage * 100) + '%';
$percent.css('width', progressPercentage);
$percent.html(titleName + ':' + progressPercentage);
}
/**
* 隐藏进度条
*/
function fadeOutProgress(file, id_Prefix) {
$('#' + file.id).find('#' + id_Prefix + '-progress').fadeOut();
}
2,Java代码(该代码中包含了上传压缩包到服务器,后进行解压;包括多文件下载自动打成压缩包的各种处理方式)
@Value("${breakpoint.upload.dir}")
private String fileStorePath;
private final ITDocService docService;
private final ITUserDocService userDocService;
@Autowired
public BigFileController(ITDocService docService, ITUserDocService userDocService) {
this.docService = docService;
this.userDocService = userDocService;
}
/**
* 秒传检查
*
* @param fileMd5 文件的MD5值
* @Title: 判断文件是否上传过,是否存在分片,断点续传
* 文件已存在,下标:-1
* 文件没有上传过,下标:0
* 文件上传中断过,返回当前已经上传到的下标
*/
@PostMapping("/check")
public Object checkBigFile(String fileMd5,Integer groupId) {
JsonResult jr = new JsonResult();
// 秒传检查
File mergeMd5Dir = new File(fileStorePath + "/" + "merge" + "/" + fileMd5);
// 判断文件夹存在
if (mergeMd5Dir.exists()) {
//mergeMd5Dir.mkdirs(); // 创建多层级文件夹
jr.setResultCode(-1); // 文件已存在,下标为-1
return new SuccessTip(200,"该文件已上传!无需再次上传!");
} else {
// 文件夹不存在
File dir = new File(fileStorePath + "/" + fileMd5);
File[] childs = dir.listFiles(); // 读取目录里的所有文件
if (childs == null) {
jr.setResultCode(0); // 文件没有上传过,下标为零
} else {
jr.setResultCode(childs.length - 1); // 文件上传中断过,返回当前已经上传到的下标
}
}
return jr;
}
/**
* 分片上传文件 - 断点续传
*
* @param param 上传文件的参数信息
*/
@PostMapping("/upload")
public void filewebUpload(MultipartFileParam param, HttpServletRequest request) {
// 上传的文件名
String fileName = param.getName();
// 文件每次分片的下标
int chunkIndex = param.getChunk();
// 工具方法: 判断是不是多部分内容
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
File file = new File(fileStorePath + "/" + param.getMd5());
if (!file.exists()) { // 第n个分片的文件夹是否存在
file.mkdir(); // 如果不存在 , 则创建这个分片的文件夹
}
File chunkFile = new File(fileStorePath + "/" + param.getMd5() + "/" + chunkIndex);
try {
FileUtils.copyInputStreamToFile(param.getFile().getInputStream(), chunkFile); // 将上传的流的内容(文件分片) 转为本地的文件
} catch (Exception e) {
e.printStackTrace();
}
}
log.info("文件-:{}的小标-:{},上传成功", fileName, chunkIndex);
}
/**
* 分片上传成功之后,合并文件
*/
@Transactional(rollbackFor = Exception.class)
@PostMapping("/merge")
public JsonResult filewebMerge(HttpServletRequest request) throws IOException {
Integer userId = ShiroKit.getUser().getId();
// 获取请求参数
String fileName = request.getParameter("fileName"); // 该请求是application/x-www-form-urlencoded(表单提交) , 不能在请求体中拿到数据
String fileMd5 = request.getParameter("fileMd5");
String groupId = request.getParameter("groupId");
System.err.println(groupId);
String realPath = fileStorePath + "/" + "merge" + "/" + fileMd5;
// 读取目录里的所有文件
File dir = new File(fileStorePath + "/" + fileMd5);
File[] childs = dir.listFiles();
if (childs == null || childs.length == 0) {
return null;
}
// 转成文件集合
List<File> fileList = new ArrayList<>(Arrays.asList(childs));
// 排序
fileList.sort((o1, o2) -> {
if (Integer.parseInt(o1.getName()) < Integer.parseInt(o2.getName())) {
return -1;
}
return 1;
});
// 合并后的文件
File outputFile = new File(realPath + "/" + fileName);
// 创建文件
if (!outputFile.exists()) { // 正常情况下 应该不存在该文件
File mergeMd5Dir = new File(realPath);
if (!mergeMd5Dir.exists()) {
mergeMd5Dir.mkdirs();
}
log.info("创建文件");
outputFile.createNewFile();
}
// 使用nio进行快速的文件拷贝
FileChannel outChannel = new FileOutputStream(outputFile).getChannel(); // 输出流
FileChannel inChannel = null; // 输入流
try {
for (File file : fileList) {
inChannel = new FileInputStream(file).getChannel(); // 遍历每个分片文件
inChannel.transferTo(0, inChannel.size(), outChannel);
inChannel.close();
// 删除分片
file.delete();
}
// 如果是压缩包,进行解压
String suffix = fileName.substring(fileName.lastIndexOf("."));
if(".zip".equals(suffix) || ".7z".equals(suffix)){
List<TDocUnzipResp> tDocUnzipRespList = ZipUtil.unZip(outputFile, realPath);
System.err.println(tDocUnzipRespList);
// 上下级关系,如果有word或者excel进行转换,然后上传
List<TDoc> tDocList = new ArrayList<>();
for (TDocUnzipResp tDocUnzipResp : tDocUnzipRespList) {
String zipFileSizeStr = null;
if(Objects.nonNull(tDocUnzipResp.getFileSize())){
Long zipFileSize = outputFile.length() / 1024;
if(docSize>1024){
zipFileSizeStr = zipFileSize / 1024 + "MB";
}else {
zipFileSizeStr = zipFileSize + "KB";
}
}
String zipFileName = tDocUnzipResp.getFileName();
// TODO 添加至数据库
}
} catch (Exception e) {
e.printStackTrace();
outputFile.delete(); // 发生异常,文件合并失败 ,删除创建的文件
dir.delete(); // 删除文件夹
} finally {
if (inChannel != null) { // 遍历完需要关闭输入流
inChannel.close();
}
outChannel.close();
}
dir.delete(); //删除分片所在的文件夹
return null;
}
/**
* 分片上传成功之后,合并文件
*/
@Transactional(rollbackFor = Exception.class)
@GetMapping("/download")
public void download(String fileName,String fileMd,String docId,HttpServletRequest request, HttpServletResponse response) {
// String fileName = request.getParameter("fileName"); //获取请求参数
// String fileMd5 = request.getParameter("fileMd5");
// String docId = request.getParameter("docId");
Integer userId = ShiroKit.getUser().getId();
//使用字节输入流加载文件进内存
FileInputStream fis = null; //使用字节输入流读取文件
OutputStream sos = null;
File file = new File(fileStorePath + "/" + "merge" + "/" + fileMd + "/" + fileName);
try {
fis = new FileInputStream(file);
//设置response响应头
response.setContentType("application/octet-stream;charset=UTF-8");
response.setHeader("content-disposition","attachment;filename=" + fileName);
response.setHeader("Content-Length", String.valueOf(file.length()));
//将输入流的事件写出到输出事件
sos = response.getOutputStream();
byte[] buffer = new byte[1024 * 8];
int length = 0;
while((length = fis.read(buffer)) != -1){
sos.write(buffer,0,length);
}
} catch (Exception e) {
log.error("文件下载失败!:{}",e.getMessage());
e.printStackTrace();
}finally {
try {
if(null != sos){
sos.close();
}
} catch (IOException e) {
log.error("流关闭失败!:{}",e.getMessage());
e.printStackTrace();
}
}
}
/**
* 批量下载打成压缩包
* @param request 获取客户机提交过来的数据,只需要找request对象
* @param response 向客户机输出数据,只需要找response对象
* @param ids 文件ids
*/
@Transactional(rollbackFor = Exception.class)
@GetMapping("/batchExport")
public void batchExport(String ids, HttpServletRequest request, HttpServletResponse response) throws IOException {
Integer userId = Objects.requireNonNull(ShiroKit.getUser()).getId();
String str = "";
// 如果id不等于空 并且 ID的长度不等于0
if (ids != null && ids.length() != 0) {
// indexOf 方法可返回某个指定的字符串值在字符串中首次出现的位置,没有找到,返回 -1。
int index = ids.indexOf("=");
// 把id中的值截取到str中,substring 截取字符串的某部分
str = ids.substring(index + 1);
// 使用逗号分割成多个字符存到ids中,split 分割成多个字符的数组
String[] idss = str.split(",");
List<TDoc> fileList = new ArrayList<>();
// 获取当前时间,把当前时间 转换格式更改为年月日时分秒
long time = System.currentTimeMillis();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd:HH-mm-ss");
String day = dateFormat.format(time);
//设置压缩包的名字
String zipName = day+"download.zip";
//解决不同浏览器压缩包名字含有中文时乱码的问题 APPLICATION/OCTET-STREAM .*( 二进制流,不知道下载文件类型)
response.setContentType("application/octet-stream");
//Content-Disposition 的作用:当Content-Type 的类型为要下载的类型时 , 这个信息头会告诉浏览器这个文件的名字和类型
response.setHeader("Content-Disposition", "attachment; filename=" + zipName);
ZipOutputStream zipos = null;
//设置压缩流:直接写入response,实现边压缩边下载
try {
zipos = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
zipos.setMethod(ZipOutputStream.DEFLATED);//设置压缩方法
} catch (Exception e) {
e.printStackTrace();
}
DataOutputStream os = null;
//循环将文件写入压缩流
for (int i = 0; i < fileList.size(); i++) {
// downLoadPath 文件下载的路径 Constans.getUploadDir() 获取文档上传的根路径; File.separator[是分隔符\\] fmFile.getFilePath() 获取文件的路径
String downLoadPath = fileStorePath + "/" + "merge" + "/" + fileList.get(i).getFileMd() + "/" + fileList.get(i).getDocName();
File file = new File(downLoadPath);//要下载文件的路径
try {
//添加ZipEntry,并ZipEntry中写入文件流
//这里,加上i是防止要下载的文件有重名的导致下载失败
zipos.putNextEntry(new ZipEntry(fileList.get(i).getDocName()));
os = new DataOutputStream(zipos);
InputStream is = new FileInputStream(file);
byte[] b = new byte[100];
int length = 0;
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
}
is.close();
zipos.closeEntry();
} catch (Exception e) {
e.printStackTrace();
}
}
//关闭流
try {
os.flush();
os.close();
zipos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3,word文件转PDF
/**
* word 转 pdf
*
* @param url
*/
public static String wordToPdf(String url,String filePath, String fileName) {
try {
DocumentType documentType = DocumentType.DOC;
if(url.contains(".docx")){
documentType = DocumentType.DOCX;
}
if(url.contains(".doc")){
documentType = DocumentType.DOC;
}
if(url.contains(".xlsx")){
documentType = DocumentType.XLSX;
}
if(url.contains(".xls")){
documentType = DocumentType.XLS;
}
InputStream inputStream = new URL(url).openStream();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
IConverter converter = LocalConverter.builder().build();
converter.convert(inputStream)
.as(documentType)
.to(stream)
.as(DocumentType.PDF).execute();
//上传图片
byte2File(stream.toByteArray(),filePath + "/" + "pdf",fileName.substring(0,fileName.lastIndexOf(".")) + ".pdf");
stream.close();
inputStream.close();
return filePath + "/" + "pdf" + "/" + fileName.substring(0,fileName.lastIndexOf(".")) + ".pdf";
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* file转byte
*/
public static byte[] file2byte(File file){
byte[] buffer = null;
try{
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1)
{
bos.write(b, 0, n);
}
fis.close();
bos.close();
buffer = bos.toByteArray();
}catch (FileNotFoundException e){
e.printStackTrace();
}
catch (IOException e){
e.printStackTrace();
}
return buffer;
}
/**
* byte 转file
*/
public static File byte2File(byte[] buf, String filePath, String fileName){
BufferedOutputStream bos = null;
FileOutputStream fos = null;
File file = null;
try{
File dir = new File(filePath);
if (!dir.exists() && dir.isDirectory()){
dir.mkdirs();
}
file = new File(filePath +File.separator + fileName);
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(buf);
}catch (Exception e){
e.printStackTrace();
}
finally{
if (bos != null){
try{
bos.close();
}catch (IOException e){
e.printStackTrace();
}
}
if (fos != null){
try{
fos.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
return file;
}
/**
* multipartFile转File
**/
public static File multipartFile2File(MultipartFile multipartFile){
File file = null;
if (multipartFile != null){
try {
file= File.createTempFile("tmp", null);
multipartFile.transferTo(file);
System.gc();
file.deleteOnExit();
}catch (Exception e){
e.printStackTrace();
log.warn("multipartFile转File发生异常:"+e);
}
}
return file;
}
4,文件在线预览(包含打印功能)
1)前端JQuery代码(在线预览)
<!DOCTYPE html>
<html>
<head>
<meta name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style media="print">
@media print {@page {
/* 纵向展示(高度展示内容更多) */
size: portrait;
/* 横向(宽度展示内容更大) */
/*size: landscape;*/
/* 打印的边距 上右下左 */
margin: 1cm 2cm 1cm 2cm;}
}
</style>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<OBJECT classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2" height=0 id=factory name=factory width=3></OBJECT>
<div>
<iframe id="file" src="http://127.0.0.1:8020/static/img/德盛数据库新增字段记事本.txt" style="height: 1000px;width: 100%"></iframe>
</div>
</body>
<script type="text/javascript">
function GetQueryString(name){
var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if(r!=null)return unescape(r[2]); return null;
}
$(function(){
var id=GetQueryString("id");
console.log(id)
$.ajax({
url: "http://127.0.0.1:8020/tDoc/look?id="+id,
async: false,
success: function(data){
console.log(data)
var url = data.data;
var fileName = url.substring(url.lastIndexOf("/")+1,url.lastIndexOf("."));
console.log(fileName)
var fileNameUri = encodeURIComponent(fileName);
var fileSrc = url.substring(0,url.lastIndexOf("/")+1) + fileNameUri + url.substring(url.lastIndexOf("."));
console.log(fileSrc)
document.getElementById("file").src = fileSrc;
}
});
});
</script>
</html>
2)预览并打印
<!DOCTYPE html>
<html>
<head>
<meta name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<meta charset="utf-8" />
<style media="print">
@media print {@page {
/* 纵向展示(高度展示内容更多) */
size: portrait;
/* 横向(宽度展示内容更大) */
/*size: landscape;*/
/* 打印的边距 上右下左 */
margin: 1cm 2cm 1cm 2cm;}
}
</style>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<OBJECT classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2" height=0 id=factory name=factory width=3></OBJECT>
<div>
<iframe id="file" src="" style="height: 1000px;width: 100%"></iframe>
</div>
</body>
<script type="text/javascript">
function GetQueryString(name){
var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if(r!=null)return unescape(r[2]); return null;
}
$(function(){
var fileMd=GetQueryString("fileMd");
var fileName=GetQueryString("fileName");
console.log(fileMd)
console.log(fileName)
$.ajax({
url: "http://127.0.0.1:8020/tDoc/print?fileMd="+fileMd+"&fileName="+fileName,
async: false,
success: function(data){
console.log(data.data)
document.getElementById("file").src = data.data
}
});
printorder();
});
function printorder() { //gettime();
setTimeout(function(){
var iframe = document.getElementById("file").contentWindow;
iframe.focus();
iframe.print();
},1500);
// setTimeout(function(){
// window.close();
// },5000);
}
</script>
</html>
3)对该文件进行新页面跳转
#跳转新的页面,作为预览并且打印的页面
var operation = function(){
window.open(Feng.ctxPath + "/static/modular/system/html/tDocPrint.html?fileMd="+fileMd+"&fileName="+fileName);
}
本人亲测有效并且在使用中,朋友们有问题可在评论中咨询,看到即回复
都是比较干硬的硬货,复制就可使用,感谢观看,欢迎大佬的指正