文件上传与下载的前后端处理

这两天在搞一个东西,单据帮助内容的导入导出。具体说就是将单据的帮助信息(字段名称和帮助内容)编辑成Excel,然后上传。后端解析流,使用poi解析Excel内容并保存到数据库中。这就是导入;从数据库读取内容并装入poi里,写入输出流让前端浏览器下载,这就是导出。

就是这么简单的功能,但我却搞了两天,上传的时候request并不是类型,下载的时候已经写入response的输出流了,但浏览器就是没有弹出下载框。在网上看了个遍都不知道为什么。

后来终于知道原因了,是因为我用了Ajax向服务端发送请求。Ajax只能传递xml或json(好像有4种,网上的说法感觉都不靠谱,找时间看一看Ajax权威指南这一类的书籍,一次过彻底弄明白吧),而文件的上传下载是涉及到二进制数据的,所以Ajax做不到,只能用form请求。

上传大概是这么处理:

// 创建上传文件form
        var form = $("<form>"),   //定义一个form表单
            resFrame = $('<iframe name="res" style="display:none;"></iframe>'),
            fileInput;
        form.attr('id', uploadFormId);
        form.attr('name', uploadFormId);
        form.attr('enctype','multipart/form-data');   //在form表单中添加查询参数
        form.attr('method','post');
        form.attr('action',"");
        form.append(resFrame);
        form.attr('target','res');
        //文件浏览选择控件
        fileInput = $('<input>'); 
        fileInput.attr('id','uploadFile'); 
        fileInput.attr('type','file'); 
        fileInput.attr('name', "file[]"); 
        form.append(fileInput);

重点是设置好enctype属性和file类型的input元素。再弄一个隐藏的iframe作为form的target,好让提交form请求后页面不会刷新(伪Ajax)

public String importAction(HttpServletRequest request,HttpServletResponse response, ModelMap modelMap) throws WafException,WafBizException{
        Context ctx = WafContext.getInstance().getContext();
        MultipartHttpServletRequest mReq = (MultipartHttpServletRequest)request;
        MultipartFile mf = mReq.getFile("file[]");
// ..............
}

这样子提交请求,服务端拿到的request就是MultipartHttpServletRequest,用它才可以拿到上传的文件流。

private Workbook getWb(MultipartFile mf) throws BOSException
    {
//        MultipartHttpServletRequest
        Workbook wb = null;
        try{
            String name = mf.getOriginalFilename();
            InputStream inputStream = mf.getInputStream();
            String postfix = name.substring(name.lastIndexOf(".") + 1);
            if("xls".equals(postfix)){
                POIFSFileSystem fs = null;
                fs = openWorkbookFile(inputStream);
                wb = new HSSFWorkbook(fs);
            }else if("xlsx".equals(postfix)){
                wb = new XSSFWorkbook(inputStream);
            }else{
                throw new BOSException("引入的不是以xls或xlsx为后缀的文件");
            }
        }catch(IOException e){
            throw new BOSException(e);
        }
        return wb;
    }
View Code

获取Workbook,用它来处理Excel的方式网上搜一大把

createDownloadForm = function(){
        // 创建下载文件隐藏form
        var form = $("<form>"),   //定义一个form表单
            resFrame = $('<iframe name="res" style="display:none;"></iframe>');
        form.attr('id', downloadFormId);
        form.attr('style','display:none');   //在form表单中添加查询参数
        form.attr('method','post');
        form.attr('action',"");
        form.append(resFrame);
        form.attr('target','res');
        downloadForm = form;
        return form;
    }
View Code

下载也使用form提交请求,使用Ajax无效,Ajax返回的responseText是一堆看不懂的乱码,当然浏览器不会自动下载文件。

if(isDownload)
            form.submit();
        else{
            waf.block.show({
                text: '正在导入,请稍后...'
            })
            form.ajaxSubmit({
                url: "?method="+action,
                type: "post",
                async: false,
                //dataType:"json",
                success: function(data){
                    waf.block.hide();
                    if("success" == data.result){
                        waf.msgBox.showInfo("导入成功");
                    }else{
                        waf.msgBox.showInfo(data.summany);
                    }
                },
                error: function(data){
                    waf.block.hide();
                    waf.msgBox.showInfo("导入失败");
                }
            });
        }
View Code

还有很奇怪的一点,如果是下载,一定要用调用form.submit提交,用下面的AjaxSubmit提交浏览器也不会自动下载文件。上传文件应该两种方式都可以,但AjaxSubmit可以添加返回处理函数。

// 文件名称
            String fileName = billTypeEnum.getAlias() + "-帮助内容.xlsx";
            
            // 导出,让前台浏览器自动下载
            String headerStr="attachment;filename=" + new String(fileName.getBytes("utf-8"),"ISO8859-1");
            response.setContentType(FileUploadUtils.getContentType("xlsx"));
            response.setHeader("Content-disposition",headerStr);
            ServletOutputStream output = null;
            
            output = response.getOutputStream();
            wb.write(output);
            output.flush();
            output.close();
View Code

后端大概这么处理。fileName是下载时的默认文件名。FileUploadUtils.getContentType("xlsx")返回的是"application/x-excel"。

以上代码片段,前端使用jQuery,后端使用java servlet

原文地址:https://www.cnblogs.com/var-iable/p/3681702.html