该上传下载附件的功能是基于bootstrap fileinput组件实现的。
其源码以及API地址如下:
bootstrap-fileinput源码:https://github.com/kartik-v/bootstrap-fileinput
bootstrap-fileinput在线API:http://plugins.krajee.com/file-input
bootstrap-fileinput Demo展示:http://plugins.krajee.com/file-basic-usage-demo
先看一下实现的效果图:此处与默认的上传样式有区别,是因为使用了【explorer】样式的主题。
下面记录一下具体实现步骤:
1、下载源码,将相应js、css分别放入static目录下,如下:主要是fileinput.min.js、fileinput.min.js、以及用于显示中文的zh.js、主题相关theme.min.js、theme.min.css
2、在include.html中引入相应js、css
<link th:href="@{/css/bootstrap-fileinput/fileinput.min.css}" rel="stylesheet"/>
<link th:href="@{/css/bootstrap-fileinput/themes/explorer/theme.min.css}" rel="stylesheet"/>
<script th:src="@{/js/plugins/bootstrap-fileinput/fileinput.min.js}"></script>
<script th:src="@{/js/plugins/bootstrap-fileinput/themes/explorer/theme.min.js}"></script>
<script th:src="@{/js/plugins/bootstrap-fileinput/locales/zh.js}"></script>
3、先考虑后端的实现,此处需要在数据库中新建一张sys_attachment表,用于保存上传图片的相关信息,包括图片名称、图片路径等,生成语句如下:
DROP TABLE IF EXISTS `sys_attachment`;
CREATE TABLE `sys_attachment` (
`id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT 'id',
`business_type` varchar(40) DEFAULT NULL COMMENT '业务类型',
`business_id` varchar(40) DEFAULT NULL COMMENT '业务Id',
`file_path` varchar(100) DEFAULT NULL COMMENT '文件路径',
`file_name_real` varchar(100) DEFAULT NULL COMMENT '真实的文件名',
`file_name_show` varchar(100) DEFAULT NULL COMMENT '显示用的文件名',
`file_size` bigint(10) DEFAULT NULL COMMENT '文件大小',
`del_flag` int(10) DEFAULT NULL COMMENT '删除标记',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=81 DEFAULT CHARSET=utf8 COMMENT='附件表';
4、后台创建sys_attachment对应的实体、mapper、service、controller文件。此处主要展示AttachmentController层代码:
@Controller
@RequestMapping("/system/attachment")
public class AttachmentController extends BaseController
{
private String prefix = "system/attachment";
@Autowired
private IAttachmentService attachmentService;
@RequiresPermissions("module:attachment:view")
@GetMapping()
public String attachment()
{
return prefix + "/attachment";
}
@PostMapping("/load")
@ResponseBody
public String load(Attachment attachment)
{
List<Attachment> alist = attachmentService.selectAttachmentList(attachment);
JSONObject jsonObject = new JSONObject();
jsonObject.put("success", true);
jsonObject.put("alist", alist);
return jsonObject.toString();
}
@PostMapping("/delete")
@ResponseBody
public AjaxResult delete(String ids)
{
try
{
return toAjax(attachmentService.deleteAttachmentByIds(ids));
}
catch (Exception e)
{
return error(e.getMessage());
}
}
@PostMapping("/save")
@ResponseBody
public AjaxResult save(Attachment attachment)
{
return toAjax(attachmentService.insertAttachment(attachment));
}
}
5、将附件上传的方法,加入至 CommonController.java中
@RequestMapping("common/upload")
@ResponseBody
public String fileUpload(@RequestParam MultipartFile file)
{
JSONObject json = new JSONObject();
if(file!=null){
try {
//上传文件,返回文件名
String fileName = FileUploadUtils.upload(Global.getDownloadPath(), file);
//拼装文件名、文件路径信息,返回json
json.put("success", true);
json.put("filePath", Global.getDownloadPath() + fileName);
json.put("fileNameReal", fileName);
json.put("fileNameShow", file.getOriginalFilename());
json.put("fileSize", file.getSize());
return json.toString();
} catch (IOException e) {
json.put("success", false);
json.put("msg", "上传失败!");
return json.toString();
}
}else {
json.put("success", false);
json.put("msg", "请选择附件!");
return json.toString();
}
}
6、在ry-ui.js中封装【初始化上传附件】、【初始化编辑附件】、【执行上传附件】、【执行下载附件】的相关js代码。
其中相应的配置大部分都有注释解释了,如果需要更详细的了解具体的参数配置详情,可以参考:,或查看官方API说明。
代码内容比较多,可能还有可以优化的地方,后续可能会优化。
//文件的操作
file :{
//初始化新增附件
initAddFiles : function (ctrlName,fileType){
var control = $('#' + ctrlName);
// 具体参数自行查询
control.fileinput({
theme: "explorer", //主题
language: 'zh', //设置语言
uploadUrl: '/common/upload', //上传的地址
enctype: 'multipart/form-data',
uploadAsync: true,
showUpload: false, //是否显示上传按钮
showPreview: true,//是否展前预览
dropZoneEnabled: false,//是否显示拖拽区域
allowedFileExtensions : fileType == 'file' ? ['doc','docx','xls','xlsx','pdf','txt','ppt','zip'] : ['jpg','gif','png'],//接收的文件后缀
maxFileCount: 10,
msgFilesTooMany: "选择上传的文件数量 超过允许的最大数值!",
previewFileIcon: '<i class="fa fa-file"></i>',
layoutTemplates :{
actionUpload:'',//去除上传预览缩略图中的上传图片;
actionZoom:'', //去除上传预览缩略图中的查看详情预览的缩略图标。
},
allowedPreviewTypes: ['image'],
previewFileIconSettings: {
'doc': '<i class="fa fa-file-word-o text-primary"></i>',
'xls': '<i class="fa fa-file-excel-o text-success"></i>',
'ppt': '<i class="fa fa-file-powerpoint-o text-danger"></i>',
'pdf': '<i class="fa fa-file-pdf-o text-danger"></i>',
'zip': '<i class="fa fa-file-archive-o text-muted"></i>',
'txt': '<i class="fa fa-file-text-o text-info"></i>',
},
previewFileExtSettings: { // configure the logic for determining icon file extensions
'doc': function(ext) {return ext.match(/(doc|docx)$/i);},
'xls': function(ext) {return ext.match(/(xls|xlsx)$/i);},
'ppt': function(ext) {return ext.match(/(ppt|pptx)$/i);},
'zip': function(ext) {return ext.match(/(zip|rar|tar|gzip|gz|7z)$/i);},
'txt': function(ext) {return ext.match(/(txt|ini|csv|java|php|js|css)$/i);}
}
});
},
//初始化编辑附件
initEditFiles : function(ctrlName,fileType,businessType,businessId){
$.ajax({
type : "post",
url : "/system/attachment/load",
dataType : "json",
data:{
"businessType" :businessType,
"businessId" : businessId
},
success : function(data) {
//layer.msg('操作成功!');
$.file.loadEditFiles(ctrlName,fileType,data);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
layer.msg('操作失败!');
}
});
},
//获取已上传需要编辑的附件
loadEditFiles: function (ctrlName,fileType,djson){
var control = $('#' + ctrlName);
//后台返回json字符串转换为json对象
var reData = eval(djson).alist;
// 预览图片json数据组
var preList = new Array();
for ( var i = 0; i < reData.length; i++) {
var array_element = reData[i];
// 此处指针对.txt判断,其余自行添加
if(array_element.fileNameReal.indexOf("txt") > 0){
// 非图片类型的展示
preList[i]= "<div class='file-preview-other-frame'><div class='file-preview-other'><span class='file-icon-4x'><i class='fa fa-file-text-o text-info'></i></span></div></div>"
}else if(array_element.fileNameReal.indexOf("doc") > 0){
preList[i]= "<div class='file-preview-other-frame'><div class='file-preview-other'><span class='file-icon-4x'><i class='fa fa-file-word-o text-primary'></i></span></div></div>"
}else if(array_element.fileNameReal.indexOf("xls") > 0){
preList[i]= "<div class='file-preview-other-frame'><div class='file-preview-other'><span class='file-icon-4x'><i class='fa fa-file-excel-o text-success'></i></span></div></div>"
}else if(array_element.fileNameReal.indexOf("ppt") > 0){
preList[i]= "<div class='file-preview-other-frame'><div class='file-preview-other'><span class='file-icon-4x'><i class='fa fa-file-powerpoint-o text-danger'></i></span></div></div>"
}else if(array_element.fileNameReal.indexOf("zip") > 0){
preList[i]= "<div class='file-preview-other-frame'><div class='file-preview-other'><span class='file-icon-4x'><i class='fa fa-file-archive-o text-muted'></i></span></div></div>"
}else if(array_element.fileNameReal.indexOf("pdf") > 0){
preList[i]= "<div class='file-preview-other-frame'><div class='file-preview-other'><span class='file-icon-4x'><i class='fa fa-file-pdf-o text-danger'></i></span></div></div>"
}else{
// 图片类型
preList[i]= "<img src=\" "+ctx+"profile/download/"+array_element.fileNameReal+"\" class=\"file-preview-image\" height=\"80\" width=\"80\">";
}
}
var previewJson = preList;
// 与上面 预览图片json数据组 对应的config数据
var preConfigList = new Array();
for ( var i = 0; i < reData.length; i++) {
var array_element = reData[i];
var tjson = {
caption: array_element.fileNameShow, // 展示的文件名
size : array_element.fileSize,
width: '120px',
url: '/system/attachment/delete', // 删除url
key: array_element.fileNameReal, // 删除是Ajax向后台传递的参数
extra: {ids: array_element.id}
};
preConfigList[i] = tjson;
}
// 具体参数自行查询
control.fileinput({
theme: "explorer",
language: 'zh', //设置语言
uploadUrl: '/common/upload', //上传的地址
enctype: 'multipart/form-data',
uploadAsync: true,
showUpload: false, //是否显示上传按钮
showPreview: true,//是否展前预览
dropZoneEnabled: false,//是否显示拖拽区域
showRemove:false, //是否显示移除按钮
allowedFileExtensions : fileType == 'file' ? ['doc','docx','xls','xlsx','pdf','txt','ppt','zip'] : ['jpg','gif','png'],//接收的文件后缀
maxFileCount: 10,
msgFilesTooMany: "选择上传的文件数量 超过允许的最大数值!",
previewFileIcon: '<i class="fa fa-file"></i>',
layoutTemplates :{
actionUpload:'',//去除上传预览缩略图中的上传图片;
actionZoom:'', //去除上传预览缩略图中的查看详情预览的缩略图标。
},
allowedPreviewTypes: ['image'],
initialPreview: previewJson,
initialPreviewConfig: preConfigList,
otherActionButtons:'<button type="button" class="kv-file-down btn btn-sm btn-default" data-key = {key} onclick="$.file.download(this)" title="下载附件"><i class="fa fa-cloud-download"></i></button>',
previewFileIconSettings: {
'doc': '<i class="fa fa-file-word-o text-primary"></i>',
'xls': '<i class="fa fa-file-excel-o text-success"></i>',
'ppt': '<i class="fa fa-file-powerpoint-o text-danger"></i>',
'pdf': '<i class="fa fa-file-pdf-o text-danger"></i>',
'zip': '<i class="fa fa-file-archive-o text-muted"></i>',
'htm': '<i class="fa fa-file-code-o text-info"></i>',
'txt': '<i class="fa fa-file-text-o text-info"></i>',
'mov': '<i class="fa fa-file-video-o text-warning"></i>',
'mp3': '<i class="fa fa-file-audio-o text-warning"></i>',
'jpg': '<i class="fa fa-file-photo-o text-danger"></i>',
'gif': '<i class="fa fa-file-photo-o text-muted"></i>',
'png': '<i class="fa fa-file-photo-o text-primary"></i>'
},
previewFileExtSettings: { // configure the logic for determining icon file extensions
'doc': function(ext) {return ext.match(/(doc|docx)$/i);},
'xls': function(ext) {return ext.match(/(xls|xlsx)$/i);},
'ppt': function(ext) {return ext.match(/(ppt|pptx)$/i);},
'zip': function(ext) {return ext.match(/(zip|rar|tar|gzip|gz|7z)$/i);},
'htm': function(ext) {return ext.match(/(htm|html)$/i);},
'txt': function(ext) {return ext.match(/(txt|ini|csv|java|php|js|css)$/i);},
'mov': function(ext) {return ext.match(/(avi|mpg|mkv|mov|mp4|3gp|webm|wmv)$/i);},
'mp3': function(ext) {return ext.match(/(mp3|wav)$/i);}
}
});
},
//执行上传附件
uploadFile : function(ctrlName,businessType,businessId){
var control = $('#' + ctrlName);
var file = control.val();
if(file != '' ){
//执行上传
control.fileinput("upload");
//上传成功后的处理
control.on("fileuploaded", function(event, outData) {
var result = outData.response;
var filePath = result.filePath;
var fileNameReal = result.fileNameReal;
var fileNameShow = result.fileNameShow;
var fileSize = result.fileSize;
$.ajax({
cache : true,
type : "POST",
url : "/system/attachment/save",
data : {
"businessType" : businessType,
"businessId" : businessId,
"filePath" : filePath,
"fileNameReal" : fileNameReal,
"fileNameShow" : fileNameShow,
"fileSize" : fileSize,
"delFlag" : '0'
},
async : false,
error : function(request) {
},
success : function(data) {
}
});
})
}
},
//执行下载附件
download : function(obj){
var $btn = $(obj),dataKey = $btn.data('key');
if(dataKey == false){
layer.msg('暂未上传,无法下载!');
}else{
window.location.href="/common/download?fileName="+dataKey;
}
}
}
7、页面调用。
在新增页面上:
<div class="form-group">
<label class="col-sm-3 control-label">附件上传:</label>
<div class="col-sm-8">
<input id="file-Portrait" type="file" multiple="multiple" name="file">
</div>
</div>
$(function() {
//初始化上传组件
$.file.initAddFiles("file-Portrait","file");
});
使用ajax保存相应业务数据成功后,调用上传组件:
注意此处可以从data中获取businessId,需要覆写一下toAjax方法,需要将业务保存后的Id传入该json中,以便获取。
$.ajax({
cache : true,
type : "POST",
url : prefix + "/add",
data : $('#form-notice-add').serialize(),
async : false,
error : function(request) {
$.modal.alertError("系统错误");
},
success : function(data) {
var businessId = data.businessId;
$.file.uploadFile("file-Portrait","notice",businessId);
$.operate.saveSuccess(data);
}
});
对于编辑页面上:
$(function() {
var businessId = $("#noticeId").val();
$.file.initEditFiles("file-Portrait","file","notice",businessId);
});
自此上传与下载的功能基本实现了!