这两天在搞一个东西,单据帮助内容的导入导出。具体说就是将单据的帮助信息(字段名称和帮助内容)编辑成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; }