java 预览zip_java压缩包上传,解压,预览(利用editor.md和Jstree实现)和下载
java压缩包上传,解压,预览(利用editor.md和Jstree实现)和下载
实现功能:zip文件上传,后台自动解压,Jstree树目录(遍历文件),editor.md预览
采用Spring+SpringMVC+Maven+Jstree+editor.md实现,主要功能:
zip压缩文件的上传
后台自动解压
Jstree自动获取最上层目录,每次仅仅会获取当前层的文件或者文件夹,然后点击文件夹或者文件,通过ajax与服务器交换数据,减轻检索和数据传输压力
后台通过文件路径遍历文件夹
通过editor.md将文本代码高亮显示
图片的解析预览
总体项目目录结构:
预览:
点击提交后:
并提供下载功能
1. 分析代码
上传压缩包的html代码,使用velocity模板渲染引擎:
上传压缩项目包
提示:压缩包内请勿包含中文!
$(window).load(function() {
//当鼠标移出输入框
$('#file-name').on('blur', function(){
var fileName = document.getElementById("file-name").value;
if(fileName==''){
$('.file-name-check').html('');
$('.file-name-check').append("请输入项目名!")
}
});
$("#file-zip").bind("change",function(){
var imgArr = ["zip"];
if($(this).val() == "")
{
alert("请选择文件!");
}
else{
var file = $(this).val();
var len = file.length;
var ext = file.substring(len-3,len).toLowerCase();
if($.inArray(ext,imgArr) == -1)
alert("不是zip格式");
}
});
$('#upload-zip').on('click', function(){
var form = document.getElementById("zipForm");
if(document.getElementById("file-name").value==''){//当项目名为空时
alert("请输入项目名!");
return false;
}
if(document.getElementById("file-zip").value==''){//当项目为空时
alert("请上传项目!");
return false;
}
var formdata = new FormData(form);
$.ajax({
url:"/admin/file/zip/upload",
data: formdata,
type:"post",
//预期服务器返回的数据类型,自动解析json返回值,不设置的话可能要执行oResult = JSON.parse(oResult);进行解析
dataType:"json",
//默认值: true。默认情况下,通过data选项传递进来的数据,如果是一个对象(技术上讲只要不是字符串),
// 都会处理转化成一个查询字符串,以配合默认内容类型 "application/x-www-form-urlencoded"。如果要发送 DOM 树信息或其它不希望转换的信息,请设置为 false。
processData: false,
//contentType: false,避免 JQuery 对data操作,可能失去分界符,而使服务器不能正常解析文件。
contentType: false,
success: function(oResult) {
// console.log(oResult);
if(oResult.success==1){
window.location.href="/admin/file/zip/show?file-path="+oResult.url;
}else{
alert(oResult.message);
}
}
})
// .done(function(oResult) { //注意done表示成功,fail表示失败,always表示不论成功还是失败,会执行的函数,
// //但是在低版本jquery不兼容,是高版本jquery推荐
// if(oResult.success==1){
// window.location.href="/";
// alert(oResult.message);
// }else{
// alert(oResult.message);
// }
// }).fail(function () {
// alert('出现错误,请重试');
// });
})
});
预览自动解压后文件夹的html代码,使用velocity模板渲染引擎:
项目展示
Search
下载
##支持markdown快速解析
##支持代码高亮
对应的JS文件,file-node.js:
$(function() {
var filePath = document.getElementById("filePathRem").value;
//注意这里面只能处理寻找文件夹的子文件或者子文件夹事件,可以把文件的读取写到 $('#container').on("changed.jstree", function (e, data)函数中
$('#container').jstree({
'core': {
'data':
//node为点击的节点,cd为输出结果的函数
function (node, cb) {
var formdata = new FormData();
formdata.append("file-path",filePath);
formdata.append("id",node.id);
//通过表单对象上传文件或者数据,设置
// processData: false,表示不要对data参数进行序列化处理
//contentType: false,避免 JQuery 对data操作,可能失去分界符,而使服务器不能正常解析文件。
$.ajax({
//不要用get方法,因为#在浏览器中有特殊含义,
// #代表网页中的一个位置。其右面的字符,就是该位置的标识符。比如,http://www.example.com/index.html#print就代表网页index.html的print位置。
// 浏览器读取这个URL后,会自动将print位置滚动至可视区域。
//并且在发送的请求中,自动忽略#,而首次打开页面的第一次请求id=#
//url: "/admin/file/zip/show.action?lazy&file-path=" + filePath + "&id=" + node.id,
url:"/admin/file/zip/show.action",
data:formdata,
type:"post",
dataType:"json",
processData: false,
contentType: false,
success: function (oResult) {
if (oResult.result.success == 1) {
cb(oResult.array);
} else {
alert(oResult.result.message);
}
}
})
}
},
//0为文件夹,即默认,1为文件
"types" : {
0 : {
"icon" : "glyphicon glyphicon-folder",
"valid_children" : []
},
1 : {
"icon" : "glyphicon glyphicon-file"
}
},
//搜索功能插件和类别插件,以对文件夹和文有不同的图标
"plugins" : ["search","types"]
});
//上面的表单s和本函数都用于搜索,模糊搜索,不区分大小写
$("#s").submit(function(e) {
e.preventDefault();
$("#container").jstree(true).search($("#q").val());
});
//注意changed与click的区别,前者只要状态不变,点击多少次都加载一次,后者每次点击都重新加载
$('#container').on("changed.jstree", function (e, data) {
// console.log("The selected nodes are:");
// //显示被选择节点id编号
// console.log(data.selected);
// //显示被选择节点的命名
// console.log(data.node.text);
var name=String(data.selected);
//如果包含.则为请求文件
if(name.search("\\.")>1){
//判断是否是图片,其他文件都是读取Json字符串的形式
if(!isImage(name)){
var formdata = new FormData();
formdata.append("file-path",filePath);
formdata.append("id",name);
$.ajax({
url:"/admin/file/zip/show.action",
data:formdata,
type:"post",
dataType:"json",
processData: false,
contentType: false,
success: function (oResult) {
if (oResult.result.success == 1) {
//首先把页面中的可能存在的图片清空
document.getElementById("image-panel").innerHTML ='';
//由于editor.md每次更新内容之后都会将删除,那么每次更新前都需要添加
document.getElementById("markdown-editor").innerHTML='';
document.getElementById("append-test").value="```\n"+oResult.fileContent+"\n```";
//用于将markdown文本转化为html格式
editormd.markdownToHTML("markdown-editor", {
});
} else {
alert(oResult.result.message);
}
}
})
}else { //对于图片,我们要显示为图片,而不是文本的字符流
document.getElementById("markdown-editor").innerHTML='';
document.getElementById("image-panel").innerHTML = '';
document.getElementById("img-circle").src = "/admin/file/zip/image.action?file-path="+filePath+"&id="+name;
}
}
});
//判断请求文件是否是图片,仅支持常用类型
function isImage(objFile) {
var objtype = objFile.substring(objFile.lastIndexOf(".")).toLowerCase();
var fileType = new Array(".png", ".jpg", ".jpeg", ".gif", ".bmp", ".ico");
for (var i = 0; i < fileType.length; i++) {
if (objtype == fileType[i]) {
return true;
break;
}
}
return false;
}
});
对应Controller层代码,FileController.java:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.demo.fileTree.model.FileHandleResponse;
import com.demo.fileTree.model.JstreeNode;
import com.demo.fileTree.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;
/**
* 实现项目zip压缩包的上传,自动解压,解压后的预览,包括文本和字符串,项目的压缩下载,
* 由于java.util.zip包不支持汉字的问题,在项目压缩包内请勿包含中文文件名,但是在页面中的项目名可以起名为中文,
* 可以用org.apache.tools.zip压缩/解压缩zip文件,解决中文乱码问题。
*
* @author xie
* @version 1.0
* @Date 2017/5/26
*/
@Controller
public class FileController {
@Autowired
FileService fileService;
/**
* 主页
* @return
*/
@RequestMapping(path = {"/"}, method = {RequestMethod.GET, RequestMethod.POST})
public String index() {
return "upload_zip";
}
/**
* 上传压缩zip项目文件
* @param file zip压缩文件
* @param fileName 项目的命名,我们将解压缩的文件放到以项目名命名的文件夹内,为了保证项目名重复的也可以上传,项目名文件夹外部还有一个32位UUID命名的文件夹,
* 只不过取出项目时没有显示
* @return 结果的json字符串
*/
@RequestMapping(path = {"/admin/file/zip/upload"}, method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public String uploadZipFile(@RequestParam("file-zip") MultipartFile file,@RequestParam("file-name")String fileName) {
FileHandleResponse fileHandleResponse = new FileHandleResponse();
try {
if(file.isEmpty()){
fileHandleResponse.setSuccess(0);
fileHandleResponse.setMessage("上传压缩文件为空");
return JSON.toJSONString(fileHandleResponse);
}
fileHandleResponse = fileService.uploadFileZip(file,fileName);
return JSON.toJSONString(fileHandleResponse);
}catch (Exception e) {
fileHandleResponse.setSuccess(0);
fileHandleResponse.setMessage("服务器异常!");
fileHandleResponse.setUrl(null);
return JSON.toJSONString(fileHandleResponse);
}
}
/**
* 展示上传的zip项目解压缩后的文件结构
* @param filePath 项目的路径,比如,C:\home\myblog\project\2d76c7aa844b4585a53d982d205099e2\123\其中123为项目名,
* @param model
* @return
*/
@RequestMapping(path = {"/admin/file/zip/show"}, method = {RequestMethod.GET, RequestMethod.POST})
public String showZipFile(@RequestParam("file-path")String filePath, Model model) {
model.addAttribute("filePath",filePath);
//filePath地址大概样子,C:\home\myblog\project\2d76c7aa844b4585a53d982d205099e2\123\,windows和linux不同,
// 包含文件名,我们提取出来,作为fileName,分隔符可能为/或\或\\,其中\要转意为\\
String fileName = filePath.split("\\|\\\\|/")[filePath.split("\\|\\\\|/").length-1];
model.addAttribute("fileName",fileName);
return "show_zip";
}
/**
* 项目展示页面
* @param filePath 项目路径
* @param relativePath 节点相比项目路径的相对路径,比如项目路径:
* C:/home/myblog/project/dccb182a7ded477483362ce46be1eb5c/123/
* 那么节点路径src/main/java/表示
* C:/home/myblog/project/dccb182a7ded477483362ce46be1eb5c/123/src/main/java/
* @return 对于文件,返回字符内容的json字符串,对于文件夹,返回文件夹的下一级所有子文件和子文件夹,其实若文件是图片,我们在下面的getImage()方法中处理
*/
@RequestMapping(path = {"/admin/file/zip/show.action"}, method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public String showZipFileDetail(@RequestParam("file-path") String filePath, @RequestParam("id") String relativePath, Model model) {
FileHandleResponse fileHandleResponse = new FileHandleResponse();
try {
if (relativePath.equals("#")) { //表示第一次打开页面的请求,relativePath为#,没什么意义,设为空字符串
relativePath = "";
}
File file = new File(filePath+relativePath);
//如果请求路径存在,即文件或者目录存在
if (file.exists()) {
//分为文件或者文件夹两种情况
if (file.isFile()) {
BufferedReader bufferedReader;
try {
StringBuilder stringBuilder = new StringBuilder();
//将字节流向字符流的转换,并创建字符流缓冲区
bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
// 每次读入一行
String read;
//每读入一行,要加一个换行符
String lineText="\n";
while ((read = bufferedReader.readLine()) != null) {
stringBuilder.append(read+lineText);
}
bufferedReader.close();
fileHandleResponse.setSuccess(1);
fileHandleResponse.setMessage("请求成功!");
model.addAttribute("result", fileHandleResponse);
model.addAttribute("fileContent", stringBuilder.toString());
return JSON.toJSONString(model);
} catch (Exception e1) {
e1.printStackTrace();
}
} else {
List list = fileService.getAllChildrenNode(filePath,relativePath);
JSONArray jsonArray = new JSONArray();
for(JstreeNode jstreeNode : list){
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", jstreeNode.getId());
jsonObject.put("text", jstreeNode.getText());
jsonObject.put("children", jstreeNode.isHasChildren());
jsonObject.put("type",jstreeNode.getType());
jsonArray.add(jsonObject);
}
fileHandleResponse.setSuccess(1);
fileHandleResponse.setMessage("请求成功!");
model.addAttribute("result", fileHandleResponse);
//最好不要直接传递list,前端不可以很好的解析
model.addAttribute("array", jsonArray);
return JSON.toJSONString(model);
}
} else { //如果请求路径不存在
fileHandleResponse.setSuccess(0);
fileHandleResponse.setMessage("请求路径不存在!");
model.addAttribute("result",fileHandleResponse);
return JSON.toJSONString(model);
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 将项目压缩后以字节流的方式发送
* @param filePath 项目路径
* @param response
*/
@RequestMapping(path = {"/admin/file/zip/download"}, method = {RequestMethod.GET})
public void downloadZipFile(@RequestParam("file-path")String filePath, HttpServletResponse response) {
FileHandleResponse fileHandleResponse;
try {
fileHandleResponse = fileService.downloadFileZip(filePath);
//地址大概样子,C:\home\myblog\project\2d76c7aa844b4585a53d982d205099e2\123.zip,windows和linux不同,
// 包含文件名,我们提取出来,作为fileName,分隔符可能为/或\或\\,其中\要转意为\\
String fileName = fileHandleResponse.getUrl().split("\\|/|\\\\")[fileHandleResponse.getUrl().split("\\|/|\\\\").length-1];
response.setContentType("application/zip");
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Disposition","attachment;filename="+fileName);
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
byte[] data = fileService.toByteArray(fileHandleResponse.getUrl());
outputStream.write(data);
outputStream.flush();
outputStream.close();
}catch (Exception e) {
e.printStackTrace();
}
}
/**
* 按照图片路径查找图片
* @param filePath 项目路径
* @param relativePath 节点相比项目路径的相对路径,比如项目路径:
* C:/home/myblog/project/dccb182a7ded477483362ce46be1eb5c/123/
* 那么节点路径src/main/java/表示
* C:/home/myblog/project/dccb182a7ded477483362ce46be1eb5c/123/src/main/java/
* @param response
*/
@RequestMapping(path = "/admin/file/zip/image.action")
public void getImage(@RequestParam("file-path") String filePath,
@RequestParam("id") String relativePath,
HttpServletResponse response) {
try {
byte[] data = fileService.toByteArray(filePath+relativePath);
response.setCharacterEncoding("UTF-8");
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
outputStream.write(data);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
对应Service层代码,FileService.java:
import com.demo.fileTree.configuration.GlobalConfig;
import com.demo.fileTree.model.FileHandleResponse;
import com.demo.fileTree.model.JstreeNode;
import com.demo.fileTree.utils.ZipUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.LinkedList;
import java.util.List;
/**
* 压缩文件上传,并且解压缩后放到服务器响应目录下,
* 为什么不直接放压缩包,因为别人看一次,需要解压缩一次,也很浪费系统资源
*
* @author xie
* @version 1.0
* @Date 2017/5/27
*/
@Service
public class FileService {
@Autowired
ZipUtils zipUtils;
/**
* 默认上传zip压缩格式
* @param file 上传的文件
* @return 上传的结果UploadResponse对象
* @throws IOException
*/
public FileHandleResponse uploadFileZip(MultipartFile file, String fileName) throws IOException {
FileHandleResponse fileHandleResponse;
try {
fileHandleResponse = zipUtils.unZipFiles(zipUtils.getZipDir(), fileName, file);
return fileHandleResponse;
} catch (Exception e) {
// 请求失败时打印的异常的信息
fileHandleResponse = new FileHandleResponse();
fileHandleResponse.setSuccess(0);
fileHandleResponse.setMessage("服务器异常!");
return fileHandleResponse;
}
}
/**
* 下载压缩后的项目文件
*
* @param filePath 项目路径
* @return 文件处理结果实体,其中url表示项目压缩后的路径
* @throws IOException
*/
public FileHandleResponse downloadFileZip(String filePath) throws IOException {
FileHandleResponse fileHandleResponse;
try {
fileHandleResponse = zipUtils.zipFiles(filePath);
return fileHandleResponse;
} catch (Exception e) {
// 请求失败时打印的异常的信息
fileHandleResponse = new FileHandleResponse();
fileHandleResponse.setSuccess(0);
fileHandleResponse.setMessage("服务器异常!");
return fileHandleResponse;
}
}
/**
* 返回某一结点(即文件夹)的下一级所有子节点,注意这里输入的不是具体文件或者不存在的路径,是已经判定存在的文件夹路径,
* 如果是请求具体文件或者不存在的路径,在上一层controller层就应该将文件内容读取并返回或者返回错误信息
*
* @param filePath 项目路径
* @param relativePath 节点相比项目路径的相对路径,比如项目路径:
* C:/home/myblog/project/dccb182a7ded477483362ce46be1eb5c/123/
* 那么节点路径src/main/java/表示
* C:/home/myblog/project/dccb182a7ded477483362ce46be1eb5c/123/src/main/java/
* 但是由于files[i].getName()只会获得abc这样的单层目录名或者abc.java这样的文件名,因此我们要设置下一级的相对路径为;
* relativePath+files[i].getName()(如果是路径,还要包含/)
*
* @return 所有子节点的列表
* @throws IOException
*/
public List getAllChildrenNode(String filePath,String relativePath) throws IOException {
File file = new File(filePath+relativePath);
List list = new LinkedList<>();
try {
//对于文件夹,我们要遍历它的下一级子节点
File[] files = file.listFiles();
JstreeNode jstreeNode;
for (int i = 0; i < files.length; i++) {
//目录
if (files[i].isDirectory()) {
jstreeNode = new JstreeNode();
jstreeNode.setId(relativePath+files[i].getName() + "/");
jstreeNode.setText(files[i].getName());
jstreeNode.setHasChildren(true);
jstreeNode.setType(GlobalConfig.TYPE_FLODER);
list.add(jstreeNode);
}
//文件
else {
jstreeNode = new JstreeNode();
jstreeNode.setId(relativePath+files[i].getName());
jstreeNode.setText(files[i].getName());
jstreeNode.setHasChildren(false);
jstreeNode.setType(GlobalConfig.TYPE_FILE);
list.add(jstreeNode);
}
}
return list;
} catch (Exception e) {
// 请求失败时打印的异常的信息
e.printStackTrace();
}
return null;
}
/**
* NIO方式读取file文件为byte[]
*
* @param filename 文件名,要求包含文件绝对路径
* @return 文件的byte[]形式
* @throws IOException
*/
public byte[] toByteArray(String filename) throws IOException {
File file = new File(filename);
/*
Java NIO中的FileChannel是一个连接到文件的通道。可以通过文件通道读写文件。FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下。
在使用FileChannel之前,必须先打开它。但是,我们无法直接打开一个FileChannel,需要通过使用一个InputStream、OutputStream或RandomAccessFile来获取一个FileChannel实例。
FileChannel实例的size()方法将返回该实例所关联文件的大小。
*/
FileChannel channel = null;
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
channel = fileInputStream.getChannel();
//所分配的ByteBuffer的容量
ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size());
/*
FileChannel.read()方法。该方法将数据从FileChannel读取到Buffer中。read()方法返回的int值表示了有多少字节被读到了Buffer中。
如果返回-1,表示到了文件末尾。
*/
while ((channel.read(byteBuffer)) > 0) {
// do nothing
// System.out.println("reading");
}
return byteBuffer.array();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
工具类,ZipUtils.java:
import com.demo.fileTree.model.FileHandleResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* 文件或者文件夹的压缩和解压缩,详细看java核心技术卷II,P27,
* 注意,如果是更新项目,要将原来文件夹及文件夹中的内容全部删除,重新生成UUID及文件夹,在这里由于没有到数据库,就不执行这一步了
*
* @author xie
* @version 1.0
* @Date 2017/5/30
*/
@Service
public class ZipUtils {
/** 头像图片的放置路径*/
@Value("${zipPath.home}")
private String ZipDir;
/**
* 获得图片存储路径
* @return
*/
public String getZipDir(){
return ZipDir;
}
/**
* 压缩文件-由于out要在递归外调用,所以封装一个方法
* 压缩后的压缩文件的路径和命名,比如 File zipFile = new File("C:/home/myblog/project/32位UUID/test.zip"),
* 但注意解压缩后的文件夹的名字与压缩文件的名字不一定相同,test.zip只是压缩包的名字,
* 在这里我们将test.zip设为fileName.zip,放在32位UUID目录下面,和解压后的项目相同层次,
* 下载完成后也不删除,防止多人下载,服务器每次都要压缩文件
*
* @param filePath 要压缩的项目的路径
* @throws IOException
* @return FileHandleResponse 表示压缩结果实体对象
*/
public static FileHandleResponse zipFiles(String filePath) throws IOException{
FileHandleResponse fileHandleResponse = new FileHandleResponse();
//将压缩文件和原项目放到相同目录下,并且相同命名,除了压缩文件以.zip结尾,但注意filePath以/结尾,要处理一下
File zipFile = new File(filePath.substring(0,filePath.length()-1)+".zip");
File noZipFile = new File(filePath);
if(zipFile.exists()){
fileHandleResponse.setMessage("压缩文件存在");
}else if(!noZipFile.exists()){
fileHandleResponse.setSuccess(0);
fileHandleResponse.setMessage("请求文件夹或文件不存在!");
return fileHandleResponse;
}else{
try {
//创建一个将压缩数据写出到指定的OutputStream的ZipOutputStream
ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile));
zipFiles(zipOutputStream, "", noZipFile);
zipOutputStream.close();
System.out.println("*****************压缩完毕*******************");
fileHandleResponse.setMessage("压缩成功");
} catch (Exception e) {
fileHandleResponse.setSuccess(0);
fileHandleResponse.setMessage("服务器异常");
e.printStackTrace();
return fileHandleResponse;
}
}
fileHandleResponse.setSuccess(1);
fileHandleResponse.setUrl(zipFile.getAbsolutePath());
return fileHandleResponse;
}
/**
* 压缩文件,
* 如果是目录,则对目录里的文件重新调用ZipFiles方法,一级目录一级目录的压缩
*
* @param zipOutputStream 压缩文件输出流
* @param fileParentPath 压缩文件的上级目录
* @param srcFiles 要压缩的文件,可以压缩1到多个文件,通过写数组的方式或者一个个写到参数列表里面
*/
public static void zipFiles(ZipOutputStream zipOutputStream,String fileParentPath,File... srcFiles){
//将目录中的1个或者多个\置换为/,因为在windows目录下,以\或者\\为文件目录分隔符,linux却是/
if(fileParentPath!=""){
fileParentPath = fileParentPath.replaceAll("\\+", "/");
if(!fileParentPath.endsWith("/")){
fileParentPath+="/";
}
}
byte[] bytes = new byte[4096];
try {
/*
希望放入zip文件的每一项,都应该创建一个ZipEntry对象,然后将文件名传递给ZipEntry的构造器,它将设置文件日期,解压缩方法等参数,
并且需要调用putNextEntry方法来开始写出新文件,并将文件数据放松到zip流中,当完成时,需要调用closeEntry方法。所有文件都重复这一过程。
*/
for(int i=0;i
//对于目录,递归
if(srcFiles[i].isDirectory()){
File[] files = srcFiles[i].listFiles();
String srcPath = srcFiles[i].getName();
srcPath = srcPath.replaceAll("\\+", "/");
if(!srcPath.endsWith("/")){
srcPath+="/";
}
zipOutputStream.putNextEntry(new ZipEntry(fileParentPath+srcPath));
zipFiles(zipOutputStream,fileParentPath+srcPath,files);
}
//对于文件,发送到ZIP流中,利用4KB的缓冲区,可以考虑使用BufferedInputStream()流过滤器
else{
FileInputStream fileInputStream = new FileInputStream(srcFiles[i]);
zipOutputStream.putNextEntry(new ZipEntry(fileParentPath + srcFiles[i].getName()));
int len;
while((len=fileInputStream.read(bytes))>0){
zipOutputStream.write(bytes,0,len);
}
zipOutputStream.closeEntry();
fileInputStream.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 解压文件到指定目录
* @param unZipPath 解压路径,比如C:\\home\\myblog\\project\\
* @param fileName 解压后的文件名,一般命名为项目名,强制要求用户输入,并且保证不为空,
* fileName的上层目录为一个随机生成的32位UUID,以保证项目名重复的依然可以保存到服务器
* @param multipartFile 上传压缩文件
*
* @return FileHandleResponse 表示上传结果实体对象
*/
@SuppressWarnings("rawtypes")
public static FileHandleResponse unZipFiles(String unZipPath, String fileName, MultipartFile multipartFile)throws IOException{
FileHandleResponse fileHandleResponse = new FileHandleResponse();
String unZipRealPath = unZipPath +UUID.randomUUID().toString().replaceAll("-", "")+ "/"+fileName + "/";
//如果保存解压缩文件的目录不存在,则进行创建,并且解压缩后的文件总是放在以fileName命名的文件夹下
File unZipFile = new File(unZipRealPath);
if (!unZipFile.exists()) {
unZipFile.mkdirs();
}
//ZipInputStream用来读取压缩文件的输入流
ZipInputStream zipInputStream = new ZipInputStream(multipartFile.getInputStream());
//压缩文档中每一个项为一个zipEntry对象,可以通过getNextEntry方法获得,zipEntry可以是文件,也可以是路径,比如abc/test/路径下
ZipEntry zipEntry;
try {
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
String zipEntryName = zipEntry.getName();
//将目录中的1个或者多个\置换为/,因为在windows目录下,以\或者\\为文件目录分隔符,linux却是/
String outPath = (unZipRealPath + zipEntryName).replaceAll("\\+", "/");
//判断所要添加的文件所在路径或者
// 所要添加的路径是否存在,不存在则创建文件路径
File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
if (!file.exists()) {
file.mkdirs();
}
//判断文件全路径是否为文件夹,如果是,在上面三行已经创建,不需要解压
if (new File(outPath).isDirectory()) {
continue;
}
OutputStream outputStream = new FileOutputStream(outPath);
byte[] bytes = new byte[4096];
int len;
//当read的返回值为-1,表示碰到当前项的结尾,而不是碰到zip文件的末尾
while ((len = zipInputStream.read(bytes)) > 0) {
outputStream.write(bytes, 0, len);
}
outputStream.close();
//必须调用closeEntry()方法来读入下一项
zipInputStream.closeEntry();
}
zipInputStream.close();
fileHandleResponse.setSuccess(1);
fileHandleResponse.setMessage("解压完毕");
fileHandleResponse.setUrl((unZipRealPath).replaceAll("\\+", "/"));
System.out.println("******************解压完毕********************");
} catch (Exception e) {
fileHandleResponse.setSuccess(0);
fileHandleResponse.setMessage("服务器异常");
e.printStackTrace();
return fileHandleResponse;
}
return fileHandleResponse;
}
}
对应的model层,FileHandleResponse.java:
/**
* 文件处理后回显提示的实体类
*
* @author xie
* @version 1.0
* @Date 2017/5/25
*/
public class FileHandleResponse {
/** 上传状态,0:失败,1:上传成功 */
private int success;
/** 图片上传提示信息,包括上传成功或上传失败及错误信息等 */
private String message;
/** 图片上传成功后返回的地址 */
private String url;
public int getSuccess() {
return success;
}
public void setSuccess(int success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
JstreeNode.java
/**
* Jstree节点实体
*
* @author xie
* @version 1.0
* @Date 2017/5/31
*/
public class JstreeNode {
/** id并没有实际的意义,仅仅用于唯一标识节点,为了掌握节点之间的上下级关系,我们将id设为节点对file-path的相对路径 */
private String id;
/** 节点的显示名字,我们设为文件名 */
private String text;
/** 节点是否有孩子节点 */
private boolean hasChildren;
/** 节点类型,即文件还是文件夹,设置文件夹为0,文件为1 */
private int type;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public boolean isHasChildren() {
return hasChildren;
}
public void setHasChildren(boolean hasChildren) {
this.hasChildren = hasChildren;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}
java 预览zip_java压缩包上传,解压,预览(利用editor.md和Jstree实现)和下载相关推荐
- 一款动态跑路html源码,简单实用,上传解压就完事了
介绍: 一款动态跑路源码,简单实用,上传解压就完事了 搭建教程: 1.领取主机 2.二级域名 3.上传源码到主机文件夹,解压 4.绑定域名,搭建完成 网盘下载地址: http://kekewangLu ...
- Java springboot压缩文件上传,解压,删除压缩包
1. 配置文件 在application.yml里 file-server:path: \material-main\# 自己随便命名.注意,不管windows还是linux,路径不需要带盘符,用代码 ...
- 2016/4/19 ①单个文件上传 ②上传图片后 预览图片
1,f1.php <!DOCTYPE html> <htmllang="en"> <head><metacharset="UTF ...
- Java实现minio文件服务web在线解压上传工具类
前言 文章中的web解压工具类结合了minio文件服务,上传解压文件过程中,先解压成文件流,再将解压的文件又上传到minio文件服务器上.(不同本地文件服务,可以直接用文件copy的方式,cpoy到服 ...
- java批量上传图片预览_SpringMVC批量上传图片,实现上传前图片预览
最近有个功能需要实现批量上传图片,然后实现图片预览,因为项目比较老,同时对界面和用户操作体验也要求不太高,就没去找网上的开源插件,直接写了个简单的功能,这里做个记录备份 因为这个是实验性的小代码,就没 ...
- 【SpringBoot项目实战】图片压缩包上传、解压、存储等等一套流程教学
[SpringBoot项目实战]图片压缩包上传.解压.存储等等一套流程教学 前言 一.压缩包上传 1.接口实现 2.获取压缩包的文件名和文件路径 二.压缩包解压并保存 1.处理压缩包文件方法 解压缩步 ...
- vue本地上传并预览php,vue.js 实现图片本地预览 裁剪 压缩 上传功能
以下代码涉及 Vue 2.0 及 ES6 语法. 目标 纯 javascrpit 实现,兼容ie9及以上浏览器,在本地做好文件格式.长宽.大小的检测,减少浏览器交互. 现实是残酷的,为了兼容Ie9 还 ...
- js上传视频,预览视频
js上传视频,预览视频 <videostyle="width:300px; height:auto;object-fit: fill;"playsinlinecontrols ...
- html上传头像及预览,js实现头像上传并且可预览提交
在用户注册账号或者修改资料的时候会需要用户在本地选择一张图片作为头像,并同时预览, 常见的思路有两种:一是将图片上传至服务器的临时文件夹中,并返回该图片的url,然后渲染在html页面:另一种思路是, ...
最新文章
- 实用的人工智能 但数据 Python 速查表
- 2021东营市地区高考成绩排名查询,东营高中学校实力排名,2021年东营所有的高中分数线排名...
- python中split的用法取第二个分片_python中split()函数的用法
- 俺的新书《Sencha Touch实战》终于出版了
- Educational Codeforces Round 25 C. Multi-judge Solving
- protractor端到端测试简介
- c#动态编译并执行字符串
- Omi v1.0震撼发布 - 令人窒息的Web组件化框架
- cmake安装更新(解决cmake报错:CMake 3.8 or higher is required. You are running version 3.5.1
- Python入门学习笔记(5)
- mysql游标是什么特性_[转]MySQL游标特性
- 盘点Mac最受欢迎的优化清理软件2020|最新|集合|排行榜
- Instantiation of Chaincode using Fabric Node manifest for hyperledger/fabric-ccenv:latest not found
- 游戏必备组件有哪些_微信广告将升级小程序、小游戏开发者收入方案
- python优化网站_小旋风网站优化 - 致力于Python高品质站群系统的产品研发
- 专访弘玑Cyclone贾岿、吴楠:超自动化+流程挖掘,助力企业深度掌控完整数字业务流程走势
- WordPress系列教程(一)----WordPress环境准备与安装
- S7-1200 PLC 激活系统时钟存储位后,相应的位没有工作?
- 新浪云计算平台应用开发
- Power BI 筛选器函数---Window实例详解