欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于Springboot+Bootstrap的文件管理全套解决方案(文件列表、上传、预览、、下载、删除打包下载等)

程序员文章站 2022-07-15 10:38:11
...

前言:

最近,不知道是不是最后一搏,事业群上层领导要求7天内完成ABS项目中保理系统的一期开发。需求评审会后,我发现各个功能模块都有大量的文件材料展示与上传,为了提高开发效率,我与组长商量,我先开发文件模块,为其他同事提供公共方法,减少重复工作。

使用的前端技术栈:Bootstrap、Bootstrap-table、layer.js、layui.js、jquery.media.js

一、设计思路:

我的想法是:文件的展示依托于表格形式,表格内展示文件的类型、名称、操作等信息,然后通过表格中或表头上的按钮完成上传、下载、预览等操作。其次,我又考虑的文件模块复用性与拓展性,我将文件类型信息存入数据字典中。这样做的好处有两点:一是、方便以后文件类型的拓展,即新增加一种文件,不需要改页面,只需要配置数据字典;二是、方便同事复用文件模块方法,即调用者,只需要传入类型后,就可以渲染相关数据。文件模块和数据字段模块图示如下:

基于Springboot+Bootstrap的文件管理全套解决方案(文件列表、上传、预览、、下载、删除打包下载等)

                                                                           图1 - 文件管理模块图片

基于Springboot+Bootstrap的文件管理全套解决方案(文件列表、上传、预览、、下载、删除打包下载等)

                                                                           图2 - 数据字典模块图片 

二、具体实现:

1.文件列表:

列表基于Bootstrap-table完成的文件展示,我在这块还做了一个优化:可以根据开发者传入的文件类型展示相应的文件,如果没有,也会展示该类,但是没有文件名称和操作。具体演示和代码如下:

演示:

基于Springboot+Bootstrap的文件管理全套解决方案(文件列表、上传、预览、、下载、删除打包下载等)

                                                                           图3 - 文件列表演示图片 

页面代码:

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head th:include="include :: header">
</head>
<body class="gray-bg">
	<div class="wrapper wrapper-content ">
		<div class="row">
			<div class="col-sm-12">
				<div class="ibox float-e-margins">
					<label class="col-sm-2 control-label">上传文件例子</label>
					<input type="hidden" id="fileIds" name="fileIds">
					<div class="ibox-content">
						<div class="columns pull-left">
							<button type="button" class="layui-btn" id="uploadFile">
								<i class="fa fa-cloud"></i>上传文件1
							</button>
							<button  type="button" class="btn  btn-primary"
									 onclick="uploadFilePage('A','fileTable')">
								<i class="fa fa-primary" aria-hidden="true"></i>上传文件2
							</button>
						</div>
						<div class="columns pull-right">
							<button class="btn btn-success" onclick="downloadZip1('1','A','')">一键打包下载1</button>
							<button class="btn btn-success" onclick="downloadZip2()">一键打包下载2</button>
						</div>
						<table class="table  table-bordered" id="fileTable"></table>
					</div>
				</div>
			</div>
		</div>
	</div>
	<div th:include="include :: footer"></div>
	<script type="text/javascript" src="/js/appjs/common/file/file.js"></script>
	<link href="/css/layui.css" rel="stylesheet">
	<script src="/js/layui.js"></script>
</body>
</html>

JS代码:考虑到文件的复用性,初始化表格的JS入参有好几个 

$(function () {
    initFileTable('1','A','','fileTable','1');
});
/**
 * 初始化文件表格
 *
 * @param belongId 所属ID (必传)
 * @param type  文件总类型 (必传)
 * @param fileTag 文件分类型
 * @param tableId 表格id (必传)
 * @param delFlag 删除表示 (必传)
 */
function initFileTable(belongId,type,fileTag,tableId,delFlag) {
    $("#"+tableId).bootstrapTable({
        striped: true, // 设置为true会有隔行变色效果
        cache: false,
        sortable: false,
        url: filePrefix+"/listByBelongIdAndTypeAndFileTag",
        method: "get",
        dataType: "json", // 服务器返回的数据类型
        queryParams: {"belongId": belongId,"type":type,"fileTag":fileTag},
        onLoadSuccess: function(data) {
        },
        columns: [
            {
                checkbox: true
            },
            {
                class: 'uid',
                title: '序号',
                align: 'center',
                formatter: function (value, row, index) {
                    return index + 1;
                }
            },
            {
                field: "id",
                visible: false
            },
            {
                field: "uuid",
                visible: false
            },
            {
                title: '上传文件',
                align: 'center',
                formatter: function (value, row, index) {
                    return uploadFileBtn(row,tableId);
                }
            },
            {
                field: "typeName",
                align: 'center',
                title: "文件总类型",
                visible: false
            },
            {
                field: "fileTagName",
                align: 'center',
                title: "文件类型"
            },
            {
                field: "fileName",
                align: 'center',
                title: "文件名"
            },
            {
                title: '操作',
                align: 'center',
                formatter: function (value, row, index) {
                    var id = row.id;
                    if(id==null){
                        return '-';
                    }
                    var p = '<a class="btn btn-warning btn-xs' + '"  title="预览"  mce_href="#" onclick="previewFile(\''
                        + row.url
                        + '\')">预览</a> ';
                    var e = '<a class="btn btn-success btn-xs' + '"  title="下载"  mce_href="#" onclick="downloadFile(\''
                        + id
                        + '\')">下载</a> ';
                    var d = '<a class="btn btn-danger btn-xs' + '" title="删除"  mce_href="#" onclick="deleteFile(\''+ id+'\',\''+tableId+ '\')">删除</a> ';


                    if(delFlag=='1'){
                        return p + e + d;
                    }else {
                        return p + e;
                    }
                }
            }
        ]
    })

}

Java代码: 

-----------------Controller------------------
   /**
	 * 文件Demo
	 *
	 * @return
	 */
	@GetMapping()
	private  String File(){
	    return "common/file/file";
	}


	/**
	 * 查询文件列表
	 *
	 * @param belongId
	 * @param type
	 * @param fileTag
	 * @return
	 */
	@GetMapping("/listByBelongIdAndTypeAndFileTag")
	@ResponseBody
	public List<FileDTO> listByTypeAndFileTag(@RequestParam("belongId") Long belongId,
											  @RequestParam("type") String type,
											  @RequestParam("fileTag") String fileTag){
		List<FileDTO> busFileDOList=new ArrayList<>();
		try {
			busFileDOList =fileService.listByBelongIdAndTypeAndFileTag(belongId,type,fileTag);
		} catch (Exception e) {
			log.info("查询文件信息,异常信息:[{}]",e.getMessage());
		}
		return busFileDOList;
	}
-----------------Service------------------
	@Override
	public List<FileDTO> listByBelongIdAndTypeAndFileTag(Long belongId, String type, String fileTag) {
		return fileDao.listByBelongIdAndTypeAndFileTag(belongId,type,fileTag);
	}

2.文件上传: 

文件上传,我这里提供了三种方式,第一种方式:我们原来项目中常用方法,它是使用了layui.js插件,这插件的作者帮助我们封装了好多前端方法和前端样式,方便我们调用;第二种方式:是我新想出来的一种方式,点击上传按钮,进入一个上传页面,在页面中有一个下拉框可以选择上传文件类型,还有一个上传按钮用来上传文件,然后点击提交;第三种方式:是原型上要求的方式,这次开发时间比较紧张,我在开发的中就没有研究和使用,它是把按钮放在了列表中,不同列代表上传不同的文件类型,用户体验感比较好。而且,我这里还做一个优化,如果上传的文件在列表中不存在文件,就在原位置插入,反之,则在这个类型文件的最后一行后边插入(因为要实现这个,我引入一个唯一标识UUID)。具体演示和代码如下:

方式一:

  • 演示:

点击上传按钮,上传文件就可以,缺点就是要在按钮的方法中固定上传的类型,单类型可以使用。

基于Springboot+Bootstrap的文件管理全套解决方案(文件列表、上传、预览、、下载、删除打包下载等)

                                                                          图4 - 文件上传方式一演示图片  

  • 页面代码: 
<button type="button" class="layui-btn" id="uploadFile"><i class="fa fa-cloud"></i>上传文件1</button>
  • JS代码: 
$(function () {
     fileUpload('A','A01','fileTable');
});

/**
 * 上传
 * 
 * @param type
 * @param fileTag
 * @param tableId
 */
function fileUpload(type,fileTag,tableId) {
    layui.use('upload', function () {
        var upload = layui.upload;
        //执行实例
        var uploadInst = upload.render({
            elem: '#uploadFile', //绑定元素
            url: filePrefix+'/uploadFile1/'+type+'/'+fileTag, //上传接口
            size: 102400,
            accept: 'file',
            done: function (data) {
                if (data.code == 0) {
                    var busFile = data.busFile;
                    //插入一条数据
                    insertFile(busFile,tableId);
                }
                layer.msg(data.msg);
            },
            error: function (data) {
                layer.msg(data.msg);
            }
        });
    });
}

/**
 * 插入文件
 * 
 * @param row
 * @param tableId
 */
function insertFile(row,tableId) {
    var table = $("#"+tableId);
    var rows = table.bootstrapTable('getData');
    var type = row.type;
    var fileTag = row.fileTag;
    var uuid=null;
    var insertIndex = rows.length-1;
    //寻找插入文件文件位置和可能需要删除的行
    $.each(rows, function (i, oldRow) {
        if(type==oldRow.type && fileTag==oldRow.fileTag){
            if(null == oldRow.id){
                uuid=oldRow.uuid;
                insertIndex=i;
            }else {
                insertIndex=i+1;
            }
        }
    });
    // 删除表格空的数据
    if(uuid!=null){
        var values = [uuid];
        table.bootstrapTable('remove', {
            field: 'uuid',
            values: values
        });
    }
    // 表格插入一条
    table.bootstrapTable('insertRow', {
        index: insertIndex,
        row: row
    });
}
  • Java代码:
-----------------Controller------------------
	/**
	 * 上传文件1
	 *
	 * @param file
	 * @param type
	 * @param fileTag
	 * @return
	 */
	@PostMapping("/uploadFile1/{type}/{fileTag}")
	@ResponseBody
	public R uploadFile1(@RequestParam("file") MultipartFile file, @PathVariable("type") String type, @PathVariable("fileTag") String fileTag) {
		log.info("上传文件开始,type:[{}],fileTag:[{}]",type,fileTag);
		if (file == null || StringUtil.isBlank(file.getOriginalFilename())) {
			log.info("未选择文件");
			return R.error("请选择需要上传的文件");
		}
		Map<String, Object> map = new HashMap<>(2);
		try {
			FileDTO busFile = fileService.uploadFile(file, type, fileTag);
			map.put("busFile", busFile);
			log.info("上传文件结束,type:[{}],fileTag:[{}],id:[{}],fileName:[{}]",type,fileTag,busFile.getId(),busFile.getFileFull());
		} catch (IOException e) {
			log.info("上传文件IO流异常:异常信息:[{}]",e.getMessage());
			return R.error("上传文件IO流异常:异常信息:"+e.getMessage());
		}catch (Exception e){
			log.info("上传文件异常:异常信息:[{}]",e.getMessage());
			return R.error("上传文件异常:异常信息:"+e.getMessage());
		}
		return R.ok(map);
	}
-----------------Service------------------

	@Override
	public FileDTO uploadFile(MultipartFile file, String type, String fileTag) throws IOException {
		FileDTO busFile = new FileDTO();
		Date now = new Date();
		String fileName = file.getOriginalFilename();
		String preName = fileName.substring(0, fileName.lastIndexOf("."));
		String extName = fileName.substring(fileName.lastIndexOf(".") + 1);

		// 上传文件到Fast
//		StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), FilenameUtils.getExtension(file.getOriginalFilename()), null);
//		String groupPath = storePath.getFullPath();
//		String serverPath = fdfsConfig.getUrl();
		String serverPath = "https://img-blog.csdnimg.cn";
		String groupPath = "/20200404131040657.png";

		String fileUrl=null;
		// 处理fileUrl
		if (serverPath.endsWith("/")) {
			fileUrl = serverPath + groupPath;
		} else {
			fileUrl = serverPath + "/" + groupPath;
		}
		//封装数据
		busFile.setFileName(preName)
				.setFileExt(extName)
				.setFileFull(fileName)
				.setUrl(fileUrl)
				.setType(type)
				.setServerPath(serverPath)
				.setGroupPath(groupPath)
				.setFileTag(fileTag)
				.setCreateTime(now)
				.setUpdateTime(now)
				.setDelFlag(0);
		fileDao.save(busFile);
		//处理数据
		DictDO dict = dictDao.getByTypeAndValue(type, fileTag);
		busFile.setTypeName(dict.getDescription());
		busFile.setFileTagName(dict.getName());
		busFile.setUuid(UUID.randomUUID().toString());
		return busFile;
	}

方式二: 

  • 演示:

点击上传按钮,进入上传页面:选择类型、上传文件、点击提交。

基于Springboot+Bootstrap的文件管理全套解决方案(文件列表、上传、预览、、下载、删除打包下载等)

                                                             图5-文件上传方式二演示图片  

基于Springboot+Bootstrap的文件管理全套解决方案(文件列表、上传、预览、、下载、删除打包下载等)

                                                           图6 - 文件上传方式二演示图片  

  • 页面代码: 
---------------------------按钮----------------------
<button  type="button" class="btn  btn-primary" onclick="uploadFilePage('A','fileTable')">
<i class="fa fa-primary" aria-hidden="true"></i>上传文件2</button>
---------------------------上传页面----------------------
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head th:include="include :: header">
</head>
<body class="gray-bg">
	<div class="wrapper wrapper-content ">
		<div class="row">
			<div class="col-sm-12">
				<div class="ibox float-e-margins">
					<div class="ibox-content">
						<form class="form-horizontal m-t" id="signupForm" method="post" enctype="multipart/form-data">

							<input type="hidden" id="type" name="type" th:value="${type}"/>
							<input type="hidden" id="tableId" name="tableId" th:value="${tableId}"/>
							<div class="form-group">
								<label class="col-sm-2 control-label">文件类型:<i style="color: red;">*</i></label>
								<div class="col-sm-4">
									<select id="fileTag" name="fileTag" data-placeholder="请选择文件类型"
											class="col-sm-4 form-control chosen-select "
											tabindex="2" style="width: 100%"> <i style="color: red;">*</i>
										<option th:each="busDict:${busDictList}"
												th:value="${busDict.value}"
												th:text="${busDict.name}"></option>
									</select>
								</div>
							</div>

							<div class="form-group">
								<label class="col-sm-2 control-label">文件名称:</label>
								<div class="col-sm-3">
									<input id="fileupload" type="file" name="file" style="display:none;" />
									<input type='text' class="form-control" name='textfield' id='textfield' readonly="readonly"/>
								</div>
								<div class="col-sm-1">
									<input id="excelImport" type="button" value="上传" class="btn btn-success"/>
								</div>
							</div>

							<div class="form-group">
								<div class="col-sm-12 col-sm-offset-6">
									<button type="button" class="btn btn-primary" onclick="uploadFile()" >提交</button>
								</div>
							</div>
						</form>
					</div>
				</div>
			</div>
		</div>
	</div>
<div th:include="include :: footer"></div>
<link href="/css/layui.css" rel="stylesheet">
<script src="/js/layui.js"></script>
<script type="text/javascript" src="/js/appjs/common/file/uploadFile.js"></script>
</body>
</html>
  • JS代码: 
---------------------------按钮JS----------------------
/**
 * 上传文件页面
 * 
 * @param type
 * @param tableId
 */
function uploadFilePage(type,tableId) {
    var index = layer.open({
        type: 2,
        title: '上传文件',
        maxmin: true,
        shadeClose: false, // 点击遮罩关闭层
        area: ['800px', '520px'],
        content: filePrefix+'/uploadFilePage/' + type+'/'+tableId
    });
    layer.full(index);
}
---------------------------页面JS----------------------
var filePrefix = "/common/file";
$(function () {
});

$("#excelImport").click(function() {
    $('#fileupload').click();
});
$('#fileupload').change(function(){
    $('#textfield').val( document.getElementById("fileupload").files[0].name);
})

function uploadFile() {
    var fileBtnId='signupForm';
    var type=$('#type').val();
    var fileTag= $('#fileTag option:selected').val();
    var tableId=$('#tableId').val();
    $.ajax({
        type: "POST",
        dataType: "json",
        cache: false,
        processData: false,
        contentType: false,
        url: filePrefix+"/uploadFile1/"+type+"/"+fileTag,
        data: new FormData($('#'+fileBtnId)[0]),
        success: function (data) {
            if (data.code == 0) {
                parent.layer.msg("操作成功");
                parent.insertFile(data.busFile,tableId);
                var index = parent.layer.getFrameIndex(window.name); // 获取窗口索引
                parent.layer.close(index);
            } else {
                parent.layer.alert(data.msg)
            }
        }
    });
}
  •  Java代码:
-----------------Controller------------------   
   /**
	 * 上传文件页面
	 *
	 * @param type
	 * @param model
	 * @return
	 */
	@GetMapping("/uploadFilePage/{type}/{tableId}")
	public String uploadFilePage(@PathVariable("type") String type,@PathVariable("tableId") String tableId, Model model) {
		List<DictDO> busDictList = dictDao.listByType(type);
		model.addAttribute("type",type);
		model.addAttribute("tableId",tableId);
		model.addAttribute("busDictList",busDictList);
		return "common/file/uploadFile";
	}

	/**
	 * 上传文件2
	 *
	 * @param file
	 * @param type
	 * @param fileTag
	 * @return
	 */
	@PostMapping("/uploadFile2")
	@ResponseBody
	public R uploadFile2(@RequestParam("file") MultipartFile file,@RequestParam("type") String type, @RequestParam("fileTag") String fileTag) {
		log.info("上传文件开始,type:[{}],fileTag:[{}]",type,fileTag);
		if (file == null  || StringUtil.isBlank(file.getOriginalFilename())) {
			log.info("未选择文件");
			return R.error("请选择需要上传的文件");
		}
		Map<String, Object> map = new HashMap<>(2);
		try {
			FileDTO busFile = fileService.uploadFile(file, type, fileTag);
			map.put("busFile", busFile);
			log.info("上传文件结束,type:[{}],fileTag:[{}],id:[{}],fileName:[{}]",type,fileTag,busFile.getId(),busFile.getFileFull());
		} catch (IOException e) {
			log.info("上传文件IO流异常:异常信息:[{}]",e.getMessage());
			return R.error("上传文件IO流异常:异常信息:"+e.getMessage());
		}catch (Exception e){
			log.info("上传文件异常:异常信息:[{}]",e.getMessage());
			return R.error("上传文件异常:异常信息:"+e.getMessage());
		}
		return R.ok(map);
	}
-----------------Service------------------
与方式一相同

 方式三: 

  • 演示:

点击上传按钮,就可以上传文件。

基于Springboot+Bootstrap的文件管理全套解决方案(文件列表、上传、预览、、下载、删除打包下载等)

                                                                          图7 - 文件上传方式三演示图片  

  • 页面代码:

没有页面代码,页面是通过js渲染的。

  • JS代码: 
/**
 * 上传文件按钮
 *
 * @param row
 * @param tableId
 * @returns {string}
 */
function uploadFileBtn(row,tableId) {
    var formId=row.uuid;
    return  '<button type="button" class="btn  btn-primary" style="width: 82px;height: 25px;position: relative">'+
        '<form  id="'+formId+'" method="post" enctype="multipart/form-data">' +
        '<input type="hidden"  name="type" value="'+row.type+'"/>'+
        '<input type="hidden"  name="fileTag" value="'+row.fileTag+'"/>'+
        '<input type="file"  name="file"  onchange="uploadFile(\''+formId+'\',\''+tableId+'\')" style="width: 100%;height: 25px;padding:0;position: absolute;font-size: 10px;left:0;top: 0;opacity: 0;z-index:2;filter:alpha(opacity=0);cursor: pointer;"/>'+
        '</form>'+
        '<span style="position: absolute;left: 10%;top: 3px;z-index: 1;" >上传文件3</span>'+
        '</button>';
}


/**
 * 上传文件按钮-上传方法
 *
 * @param formId
 * @param tableId
 */
function uploadFile(formId,tableId) {
    $.ajax({
        type: "POST",
        dataType: "json",
        cache: false,
        processData: false,
        contentType: false,
        url: filePrefix+"/uploadFile2",
        data: new FormData($('#'+formId)[0]),
        success: function (data) {
            if (data.code == 0) {
                layer.msg("上传成功");
                insertFile(data.busFile,tableId);
            } else {
                layer.alert(data.msg)
            }
        }
    });
}
  • Java代码:
-----------------Controller------------------   
 	/**
	 * 上传文件2
	 *
	 * @param file
	 * @param type
	 * @param fileTag
	 * @return
	 */
	@PostMapping("/uploadFile2")
	@ResponseBody
	public R uploadFile2(@RequestParam("file") MultipartFile file,@RequestParam("type") String type, @RequestParam("fileTag") String fileTag) {
		log.info("上传文件开始,type:[{}],fileTag:[{}]",type,fileTag);
		if (file == null  || StringUtil.isBlank(file.getOriginalFilename())) {
			log.info("未选择文件");
			return R.error("请选择需要上传的文件");
		}
		Map<String, Object> map = new HashMap<>(2);
		try {
			FileDTO busFile = fileService.uploadFile(file, type, fileTag);
			map.put("busFile", busFile);
			log.info("上传文件结束,type:[{}],fileTag:[{}],id:[{}],fileName:[{}]",type,fileTag,busFile.getId(),busFile.getFileFull());
		} catch (IOException e) {
			log.info("上传文件IO流异常:异常信息:[{}]",e.getMessage());
			return R.error("上传文件IO流异常:异常信息:"+e.getMessage());
		}catch (Exception e){
			log.info("上传文件异常:异常信息:[{}]",e.getMessage());
			return R.error("上传文件异常:异常信息:"+e.getMessage());
		}
		return R.ok(map);
	}
-----------------Service------------------
与方式一相同

3.文件预览: 

通过预览按钮进入预览页面,现在支持预览文件格式只有图片和PDF。具体演示和代码如下:

演示:

基于Springboot+Bootstrap的文件管理全套解决方案(文件列表、上传、预览、、下载、删除打包下载等)

                                                                            图8 - 文件预览演示图片   

页面代码: 

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head th:include="include :: header">
</head>
<body class="gray-bg">
	<div class="wrapper wrapper-content ">
		<div class="row">
			<div class="col-sm-12">
				<div class="ibox float-e-margins">
					<div class="ibox-content" align="center">
						<a class="media" th:href="${url}"></a>
					</div>
				</div>
			</div>
		</div>
	</div>
	<div th:include="include :: footer"></div>
	<script type="text/javascript" src="/js/media/jquery.media.js"></script>
	<script type="text/javascript">
		$(function() {
			$('a.media').media({width:1200, height:600});
			$('a.mediase').media({width:1200, height:600});
		});
	</script>
</body>
</html>

JS代码:

/**
 * 预览文件
 * 
 * @param url
 */
function previewFile(url) {
    //获取最后一个.的位置
    var index= url.lastIndexOf(".");
    //获取后缀
    var ext = url.substr(index+1);
    if(ext=='docx'||ext=='doc'||ext=='txt'||
        ext=='zip'||ext=='xlsx'||ext=='xls'||
        ext=='ppt'||ext=='pptx'){
        layer.msg("不支持此"+ext+"格式文件预览");
        return;
    }
    var index = layer.open({
        type: 2,
        title: '预览文件',
        maxmin: true,
        shadeClose: false, // 点击遮罩关闭层
        area: ['800px', '520px'],
        content: filePrefix+'/previewFile?url=' + url
    });
    layer.full(index);
}

Java代码:

	/**
	 * 预览文件
	 *
	 * @param url
	 * @param model
	 * @return
	 */
	@GetMapping("/previewFile")
	public String previewFile(@RequestParam("url") String url, Model model) {
		model.addAttribute("url",url);
		return "common/file/previewFile";
	}

 4.文件下载: 

点击下载按钮,就可下载。具体代码如下:

页面代码: 

没有页面代码,JS渲染了一个按钮。

JS代码:

/**
 * 下载文件
 * 
 * @param id
 */
function downloadFile(id) {
    window.location.href = filePrefix+"/downloadFile/" + id;
}

Java代码:

	/**
	 * 下载
	 *
	 * @param id
	 * @return
	 * @throws Exception
	 */
	@GetMapping("/downloadFile/{id}")
	public ResponseEntity<byte[]> downloadFile(@PathVariable("id") Long id){
		FileDO file = fileDao.get(id);
		log.info("下载文件开始,文件id:[{}],文件名称:[{}]",file.getId(),file.getFileFull());
		byte[] content = ZipDownloadUtil.downloadUrlConvertByte(file.getUrl());
		HttpHeaders headers = new HttpHeaders();
		try {
			headers.set("Content-Disposition", "attachment;Filename=" + URLEncoder.encode(file.getFileFull(), "UTF-8"));
		} catch (UnsupportedEncodingException e) {
			log.info("文件名编码集转换异常,异常信息[{}]",e.getMessage());
		}
		HttpStatus statusCode = HttpStatus.OK;
		ResponseEntity<byte[]> entity = new ResponseEntity<>(content, headers, statusCode);
		return entity;
	}

5.文件删除:  

点击删除按钮,弹出删除却框,点击确定后删除,我这里是逻辑删除,只更新数据删除标识,不删除数据库记录和文件服务器中的文件。具体演示和代码如下:

演示:

基于Springboot+Bootstrap的文件管理全套解决方案(文件列表、上传、预览、、下载、删除打包下载等)

                                                                            图9 - 文件删除演示图片    

页面代码: 

没有页面代码,JS渲染了一个按钮。

JS代码:

/**
 * 删除文件
 * 
 * @param id
 * @param tableId
 */
function deleteFile(id,tableId) {
    layer.confirm("确认要删除此文件吗?",
        {btn: ['确定', '取消']}, function () {
            $.ajax({
                cache: true,
                type: "get",
                url: filePrefix+"/deleteFile/" + id,
                async: false,
                error: function (request) {
                    parent.layer.alert("Connection error");
                },
                success: function (data) {
                    if (data.code == 0) {
                        var table = $("#"+tableId);
                        var values = [parseInt(id)];
                        table.bootstrapTable('remove', {
                            field: 'id',
                            values: values
                        });
                        layer.closeAll('dialog');
                        parent.layer.msg("文件删除成功");
                    } else {
                        parent.layer.alert(data.msg)
                    }

                }
            });
        })
}

Java代码:

	/**
	 * 删除文件
	 *
	 * @param id
	 * @return
	 */
	@ResponseBody
	@GetMapping("/deleteFile/{id}")
	public R deleteFile(@PathVariable("id") Long id) {
		try {
			fileDao.updateDelFlagById(id);
		} catch (Exception e) {
			log.info("删除文件信息,异常信息:[{}]",e.getMessage());
			return R.error("异常信息:"+e.getMessage());
		}
		return R.ok();
	}

6.文件打包下载:  

我这里提供了两种打包下载方法方式,第一种方式:根据文件类型和所属ID打成一个压缩包,第二种方式:根据所属id的集合批量下载,并且压缩包中会按照所属ID和文件类型创建不同目录下载(这块搞了好久,我对Java IO流不是很熟悉;JDK8 Stream 分组的功能帮了我很大忙,JDK8 Stream的使用,见我写的这篇文章《JDK8都发行5年多了,你还不会使用Stream流和Lambda表达式吗?》)。

方式一:

点击一键打包下载按钮,就可以下文件,这种方式需要传入文件类型和所属ID,具体代码如下。

  • 页面代码:
<button class="btn btn-success" onclick="downloadZip1('1','A','')">一键打包下载1</button>
  • JS代码: 
/**
 * 打包下载1
 * 
 * @param belongId
 * @param type
 * @param fileTag
 */
function downloadZip1(belongId,type,fileTag) {
    window.location.href = filePrefix+"/downloadZip1?belongId=" + belongId+"&type="+type+"&fileTag"+fileTag;
}
  • Java代码:
-----------------Controller------------------   
 	/**
	 * 打包下载1
	 *
	 * @param belongId
	 * @param type
	 * @param fileTag
	 */
	@GetMapping("/downloadZip1")
	@ResponseBody
	public void downloadZip1(@RequestParam("belongId") Long belongId,
							 @RequestParam("type") String type,
							 @RequestParam("fileTag") String fileTag,
							 HttpServletResponse response) {
		log.info("打包下载文件开始,文件所属id:[{}],文件总类型:[{}],文件类型:[{}]",belongId,type,fileTag);
		try {
			fileService.downloadZip(belongId,type,fileTag,"压缩包",response);
			log.info("打包下载文件结束,文件所属id:[{}],文件总类型:[{}],文件类型:[{}]",belongId,type,fileTag);
		} catch (Exception e) {
			log.error("打包下载文件异常,异常信息:[{}]", e.getMessage());
		}
	}
-----------------Service------------------
	@Override
	public void downloadZip(Long belongId, String type, String fileTag, String zipFilename, HttpServletResponse response) throws IOException {

		Map<String, Object> map = new HashMap<>(4);
		map.put("belongId", belongId);
		map.put("type", type);
		map.put("fileTag", fileTag);
		List<FileDTO> list = fileDao.list(map);
		List<byte[]> contentList = new ArrayList<>();
		List<String> filenameList = new ArrayList<>();
		String typeName = "";
		if (!list.isEmpty()) {
			typeName = list.get(0).getTypeName();
			list.forEach(x -> {
				log.info("文件名称和url,name:[{}],url:[{}] ", x.getFileName(), x.getUrl());
				if (StringUtil.isNotBlank(x.getUrl())) {
					contentList.add(ZipDownloadUtil.downloadUrlConvertByte(x.getUrl()));
					filenameList.add(getFilename(x));
				}
			});
		}

		ZipDownloadUtil.downloadZip(response, zipFilename, contentList, filenameList);

	}

方式二:

点击一键打包下载按钮,就可以下文件,这种方式需要所属ID类型和压缩包名称,具体代码如下。

  • 页面代码:
<button class="btn btn-success" onclick="downloadZip2()">一键打包下载2</button>
  • JS代码: 
/**
 * 打包下载2
 */
function downloadZip2() {
    var params={};
    params.belongIds=[1,2];
    params.zipFilename='测试';
    var param = jQuery.param(params);
    window.location.href = filePrefix+"/downloadZip2?" + param;
}
  • Java代码:
-----------------Controller------------------   
/**
	 *
	 * 打包下载2
	 *
	 * @param belongIds
	 * @param zipFilename
	 */
	@GetMapping("/downloadZip2")
	@ResponseBody
	public void downloadZip2(@RequestParam("belongIds[]") List<Long> belongIds,
							 @RequestParam("zipFilename") String zipFilename,
							 HttpServletResponse response) {
		log.info("打包下载文件开始,文件所属id集合:[{}]", JsonUtil.beanToJson(belongIds));
		try {
			fileService.batchDownloadZip(belongIds,zipFilename,response);
			log.info("打包下载文件结束,文件所属id集合:[{}],压缩文件名称:[{}]", JsonUtil.beanToJson(belongIds),zipFilename);
		} catch (Exception e) {
			log.error("打包下载文件异常,异常信息:[{}]", e.getMessage());
		}

	}
-----------------Service------------------
	@Override
	public void batchDownloadZip(List<Long> belongIdList, String zipFilename, HttpServletResponse response) throws IOException {
		//数据为空
		if (belongIdList.isEmpty()) {
			return;
		}
		List<byte[]> contentList = new ArrayList<>();
		List<String> filenameList = new ArrayList<>();
		//遍历每一个资产包
		belongIdList.forEach(belongId->{
			Map<String,Object> param = new HashMap<>(2);
			param.put("belongId", belongIdList.get(0));
			List<FileDTO> list = fileDao.list(param);
			//按文件类型分组
			Map<String, List<FileDTO>> map = list.stream().collect(Collectors.groupingBy(FileDTO::getTypeName));
			String partlPackageNo = "";
			//遍历分组
			map.forEach((key, value)->{
				String typeName=key;
				value.forEach(x->{
					log.info("文件名称和url,name:[{}],url:[{}] ", x.getUrl(), x.getFileName());
					contentList.add(ZipDownloadUtil.downloadUrlConvertByte(x.getUrl()));
					filenameList.add(partlPackageNo+"/"+typeName+"/"+getFilename(x));
				});
			});
		});
		//封装压缩包名字
		zipFilename=zipFilename+"_"+ LocalDateTime.now().toString()+".zip";
		ZipDownloadUtil.downloadZip(response, zipFilename, contentList, filenameList);

	}

三、源码地址:

https://gitee.com/hanxinghua2017/springboot_demo.git 《 springboot-some-function模块》