文件上传插件(bootstrap file-iput)的使用

file-input 是 bootstrap 框架下的一个文件上传插件,支持基于 AJAX 和 HTML5 的多文件多线程上传、拖曳上传、文件预览等。这个插件的优点是使用简单,文件上传预览功能优雅。

安装

首先引用资源文件,可以通过自动引入和手动引入的方法。

自动安装方法

# 途径一:Bower 包管理
$ bower install bootstrap-fileinput
# 途径二:npm 安装
$ npm install bootstrap-fileinput
# 途径三:Composer 安装
$ php composer.phar require kartik-v/bootstrap-fileinput "dev-master"

手动安装方法(需事先引入 Bootstrap 和 Jquery)

先下载 bootstrap-file-input 资源文件,项目地址。最新版本支持 bootstrap 3.x 和 4.x 。

<link href="bootstrap-fileinput/css/fileinput.min.css" rel="stylesheet" />
<script src="bootstrap-fileinput/js/fileinput.min.js"></script>
<!-- 中文支持引入 -->
<script src="bootstrap-fileinput/js/locales/zh.js"></script>

使用

前端表单(HTML)

<label class="form-label">上传文件</label>
<input type="file" id="upload-files" name="upload-files" multiple/>

初始化(Javascript)

<script>
    $(function () {
        // 初始化上传插件
        $('#upload-file').fileinput({
            language: 'zh',
            // 上传接口
            uploadUrl: 'secure/upload-uploadify-file',
            // 异步上传需要携带的其他参数,比如商品id等, 可选
            uploadExtraData: {},// 异步上传需要携带的其他参数,比如id等, 可选
            allowedFileExtensions: ['pdf', 'doc', 'docx', 'jpg', 'ppt'],
            initialCaption: "请上传PDF或Word文档",//文本框初始话value
            dropZoneEnabled: false,// 禁用dropZone区域, 选择图片后才显示预览区域(推荐)
            showPreview: true,//默认true,显示文件预览区域
            showCaption: true,
            showUpload: true,
            showRemove: true,
            showClose: true,
            overwriteInitial: true,//新选择文件后,是否删掉初始化的文件
            layoutTemplates: {
                actionDelete: ''
            },
            browseClass: 'btn btn-sm btn-primary'
        });
    });
</script>

在初始化部分,uploadUrl 指定了文件上传的 POST 请求地址,这个需要自己在后端实现。这种方式是 AJAX 上传,拖曳上传功能也必须在 AJAX 方式中方为有效。file-input 另外还支持 FORM 上传,由于我使用的较少,此处不展开。

实例

以 JAVA(Spring)为例,实现一个将文件上传到又拍云的例子。

1、引用资源

<link type="text/css" rel="stylesheet" href="/res/bootstrap/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="/res/bootstrap-fileinput/css/fileinput.min.css" />
<script type="text/javascript" src="/res/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/res/bootstrap-fileinput/js/fileinput.min.js"></script>
<script type="text/javascript" src="/res/bootstrap-fileinput/js/zh.js"></script>

2、前端页面(JSP 表单)

<div class="modal fade" id="add-section-modal" tabindex="-1" role="dialog"
     aria-labelledby="myLargeModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">
                    &times;
                </button>
                <h6 class="modal-title" id="myModalLabel">添加章节</h6>
            </div>
            <div class="modal-body">
                <form id="section-add-form" style="margin-top:40px;">
                    <div class="form-line form-group-id" style="display: none;">
                        <span class="form-label"><span class="warning-label">*</span>id:</span>
                        <input type="text" class="df-input-narrow" id="training-add-id" value=""
                               disabled="disabled">
                        <span class="form-message"></span>
                        <br>
                    </div>
                    <div class="form-line form-group" style="display: block;">
                        <span class="form-label"><span class="warning-label">*</span>课程名称:</span>
                        <input type="text" class="df-input-narrow" id="training-name" value="默认分组"
                               disabled="disabled">
                        <span class="form-message"></span>
                        <br>
                    </div>
                    <div class="form-line form-group add-section-name" style="display: block;">
                        <span class="form-label"><span class="warning-label">*</span>章节名称:</span>
                        <input type="text" class="df-input-narrow" id="section-name" value="">
                        <span class="form-message"></span>
                        <br>
                    </div>
                    <div class="form-line form-group add-section-desc" style="display: block;">
                        <span class="form-label"><span class="warning-label">*</span>章节描述:</span>
                        <textarea class="df-input-narrow" id="section-desc"></textarea>
                        <span class="form-message"></span>
                        <br>
                    </div>
                    <div class="form-line control-group">
                        <span class="form-label"><span class="warning-label">*</span>上传课件:</span>
                        <div class="controls file-form-line">
                            <input type="file" id="upload-file" name="upload-file" multiple/>
                            <div class="form-group " id="files">
                                <span class="help-inline form-message"></span>
                            </div>
                        </div>
                    </div>
                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">
                    关闭
                </button>
                <button id="add-section-btn" type="submit" class="btn btn-primary">
                    确定添加
                </button>
            </div>
        </div>
    </div>
</div>

3、初始化插件(JS)

<script>
    $(function () {
        // 初始化上传插件
        $('#upload-file').fileinput({
            language: 'zh',
            // 上传接口
            uploadUrl: 'secure/upload-uploadify-file',
            // 异步上传需要携带的其他参数,比如商品id等, 可选
            uploadExtraData: {},// 异步上传需要携带的其他参数,比如id等, 可选
            allowedFileExtensions: ['pdf', 'doc', 'docx', 'jpg', 'ppt'],
            initialCaption: "请上传PDF或Word文档",//文本框初始话value
            dropZoneEnabled: false,// 禁用dropZone区域, 选择图片后才显示预览区域(推荐)
            showPreview: true,//默认true,显示文件预览区域
            showCaption: true,
            showUpload: true,
            showRemove: true,
            showClose: true,
            overwriteInitial: true,//新选择文件后,是否删掉初始化的文件
            layoutTemplates: {
                actionDelete: ''
            },
            browseClass: 'btn btn-sm btn-primary'
        });

        //上传成功后回调函数
        $('#upload-file').on('fileuploaded', function (event, data, previewId, index) {
            var response = data.response;
            $("#files").append('<input type="hidden" class="filePaths" name="filePaths_' + index + '.filePath"  value="' + response.result + '">');
        });

        // 上传失败后回调函数
        $('#upload-file').on('fileuploaderror', function (event, data, previewId, index) {
            console.log(data.response.result);
            util.error("上传附件失败");
        });
    });
</script>

4、文件上传控制器

@Controller
public class TrainingAction {
	@RequestMapping(value = "/secure/upload-uploadify-file", method = RequestMethod.POST,produces = "application/json;charset=UTF-8")
	@ResponseBody
	public String uploadFile(HttpServletRequest request, HttpServletResponse response) {
		UserInfo userInfo = (UserInfo) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		List<String> filePathList = new ArrayList<String>();
		try {
			filePathList = FileUploadUtil.uploadFileToUpyun(request, response, userInfo.getUsername());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		if (filePathList.size() == 0) {
			return "{\"result\":\""+"系统错误"+"\"}";
		}

		String filePath = filePathList.get(0);

		filePath  =filePath.replaceAll("\\\\","\\\\\\\\");
		return "{\"result\":\""+filePath+"\"}";
	}
}

5、文件上传实现类(上传到又拍云)

public class FileUploadUtil {

    private static Log log = LogFactory.getLog(FileUploadUtil.class);

    private String HMAC_SHA1_ALGORITHM = "HmacSHA1";

    // 返回 List 集合
    // 满足单个和多个文件上传使用
    public static List<String> uploadFileToUpyun(HttpServletRequest request,
                                                 HttpServletResponse response, String username) throws FileNotFoundException {
        // 初始化又拍云sdk
        RestManager manager = new RestManager(Constants.BUCKET, Constants.OPERATOR, Constants.PASS);
        manager.setTimeout(60);
        manager.setApiDomain(RestManager.ED_AUTO);

        // 创建list集合,用于接收上传文件的路径
        List<String> filePathList = new ArrayList<String>();

        String strPath = ",upload,exam,files,";
        // 文件上传路径
        String filepath = strPath.replace(',', '/');
        // 转换request,解析出request中的文件
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        // 获取文件map集合
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        String fileName = null;
        // 循环遍历,取出单个文件
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            // 获取单个文件
            MultipartFile mf = entity.getValue();
            // 获得原始文件名
            fileName = mf.getOriginalFilename();
            // 截取文件类型; 这里可以根据文件类型进行判断
            String fileType = fileName.substring(fileName.lastIndexOf('.'));
            try {
                String newFileName = MD5FileUtil.getMD5String(mf.getBytes());
                String newfilepath;
                newfilepath = filepath + username + "-" + newFileName + fileType;
                String filepathUrl = Constants.domain + newfilepath;

                log.info("start upload file: " + fileName);
                Response wrResponse = manager.writeFile(newfilepath, mf.getBytes(), null);
                log.info("UpYun upload response: " + wrResponse);

                filePathList.add(filepathUrl);

            } catch (IOException | UpException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                log.info("upload failed. filename: " + fileName + e.getMessage());
                return null;
            }
        }
        return filePathList;
    }
}

6、实现结果

bootstrap-fileinput 支持图片、文档、压缩文件等多类型的文件上传,允许客户端上传的文件类型在初始化时通过 allowedFileExtensions: ['pdf', 'doc', 'docx', 'jpg', 'ppt'] 属性配置。

关于文件上传还需要注意代码安全问题,毕竟这是服务器一个面向用户最为直接的入口,容易让人有机可乘。

文件上传漏洞 ~ Misaki’s Blog

对文件上传的一些思考和总结 – 安全客

参考资料

Bootstrap File Input – © Kartik

【Bootstrap】bootstrap-fileinput 上传文件插件 – K.Takanashi

暂无评论

发送评论 编辑评论


				
上一篇
下一篇