背景
最近都没有腾出来时间写博客,今天想把昨天写的有关于上传图片的内容总结一下。
我要写的内容是:原本上传营业证书的格式是图片,后来改为也可以上传word和pdf格式。所以需要在原来代码的基础上,根据营业证书的地址后缀,判断文件格式是图片or文档or pdf,然后进行不同格式的显示。
思路
1.起初打算在前端进行后缀的判断,类似代码如下:
function checkedImportExcel() { var msg = ""; var fileDir = $("#file").val(); var suffix = fileDir.substr(fileDir.lastIndexOf(".")); if (fileDir == "") { msg += "选择需要导入的Excel文件! "; } if (".xls" != suffix && ".xlsx" != suffix) { msg += "选择Excel格式的文件导入! "; } if (msg != "") { alert(msg); return false; } $("#formImportExcel").submit(); }
可以通过判断营业证地址后缀进行判断,可最终没实现出来。
2.后来决定在后端进行判断,传到jsp页面时多加一个为后缀的参数,类似代码如下:
//根据后缀进行判断 营业地址是word还是pdf还是 图片 if (null != businessLicenseAddress) { String[] split = businessLicenseAddress.split(Pattern.quote(".")); int count = split.length - 1; String suffix = split[count]; if ("png".equals(suffix) | "jpg".equals(suffix) | "jpeg".equals(suffix) | "gif".equals(suffix)) { modelMap.addAttribute("img", "png"); } else if ("pdf".equals(suffix)) { modelMap.addAttribute("pdf", "pdf"); } else { modelMap.addAttribute("doc", "doc"); } }
最后在前端,对接受得参数用c:if进行判断,类似代码如下:
<c:if test="${not empty img}"> <p><img src="/hyb-ent/ent_info/findEntInfoLicenceImg/${entListInfoForm.entInfo.id}" class="img-rounded" alt="" width="50" height="50"> </p> </c:if> <c:if test="${not empty pdf}"> <p> <a href="/hyb-ent/ent_info/findEntInfoLicenceDoc/${entListInfoForm.entInfo.id}/${pdf}" class="btn btn-default glyphicon glyphicon-hand-down">导出营业证书pdf</a> </p> </c:if> <c:if test="${not empty doc}"> <p> <a href="/hyb-ent/ent_info/findEntInfoLicenceDoc/${entListInfoForm.entInfo.id}/${doc}" class="btn btn-default glyphicon glyphicon-hand-down">导出营业证书doc</a> </p> </c:if>
3. 后端导出证书,最开始使用的是URl类,打算通过读取地址,通过Url类进行打开,可是实现的时候总是报错。
因为在实现的这个功能的时候,营业证书实际上是保存在服务器的,所以不能根据数据库中真实的地址去验证功能是否实现。所以我最开始用的地址都是本机桌面上保存的地址。所以都在c盘。可报错内容为 无法识别字符:c。
百度发现url在读取本机内容是需要加上字段file:\可依然报错。大概解决了小一天。原来是这种项目在服务器上,文件也保存在服务器上的情况中,不需要使用URL,直接使用File类指定地址进行读取就可以。类似代码如下:
public void downloadBusinessLicense(@PathVariable("address") String address, @PathVariable("filename") String filename, HttpServletResponse response, HttpServletRequest request) { FileInputStream fileInputStream = null; OutputStream outputStream = null; response.setHeader("Content-Disposition", "attachment;fileName=" + address); try { String filePath = request.getServletContext().getRealPath("/") + File.separator + "file" + File.separator + "MyTest." + filename; outputStream = response.getOutputStream(); fileInputStream = new FileInputStream(new File(filePath)); System.out.println(filePath); byte[] buf = new byte[2048]; int length = fileInputStream.read(buf); while (length != -1) { outputStream.write(buf, 0, length); length = fileInputStream.read(buf); } outputStream.close(); fileInputStream.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
有一个知识点也被我忘了,不需要返回输出流,输出流自动就返回。要理解“输出”的含义。且HttpServletResponse类似的类中,提供了getOutputInstream()方法。
至此,这一部分算是写完可以交差了。可接下来要说的,几乎否定了我一整天的工作。
<c:if test="${not empty img}"> <p><img src="/hyb-ent/ent_info/findEntInfoLicenceImg/${entListInfoForm.entInfo.id}" class="img-rounded" alt="" width="50" height="50"> </p> </c:if>
4.之前也说过了,本来这个功能就可以显示出图片。
这里要说一个技能点。在前端标签<img src="">,一直以为src后面接的是图片路径,其实不然。src后接的其实是一个输出流对应的url。
可为什么本地项目启动时,可以直接src后面接一个图片路径,而没有通过controller返回一个输出流?
因为tomcat和jetty工具,已经封装好了。不过路径和大小都有局限性。
那为什么src后面接网络图片地址时,也能访问得到?
因为其实那不是地址,相对应的也是通过地址访问到一个开放的Controller,得到输出流。
所以,回到项目中去。在原本的项目中,能访问得到图片,那他src后面对应的路径,同样不会是这个照片的绝对路径,而是一个Controller,返回了一个输出流。所以其实,我只要把标签换一下,其他的复制粘贴,我这部分工作早就可以做完了。。。。what????可能没说清楚。我再解释一遍。
src路径接的是controller,返回的是一个输出流,而OutputStream形式的输出流,都是字节传输。图片、文档、pdf三者之间根本没有区别。所以其实只要在前端把图片标签img换成一个按钮,点击下载,按钮的url和图片的一样。其实就结束了。
那为什么我自己写的写的代码运行会报错?
因为营业证书保存的位置在另一个项目下,当前我所写的项目是取不到营业证书的。
所以历时一天的写代码过程曲曲折折,最后发现其实只需要写两行代码....气得我想吃辣条。
当然直接这么调用还是有问题的。就是下载的文件没有后缀,需要自己手动加。不过没关系,重新写一个Controller,添加一个消息头
response.setHeader("Content-Disposition","attachment;fileName="+entId+ "."+suffix);
Over!