程序员人生 网站导航

[置顶] 详细阐述Web开发中的图片上传问题

栏目:综合技术时间:2015-03-04 08:32:39
    Web开发中,图片上传是1种极为常见的功能。但是呢,每次做上传,都花费了很多时间。

    1个“小功能”花费我这么多时间,真心不愉快。

   So,要得认真分析下缘由。

1.在最初学习Java Web开发的时候,经验不足,属于能力问题,比如对技术认识不到位。

2.图片上传是1类问题,而不是1个问题。
   比如,大家都会做饭,但每一个人自己做饭是有不同的。做了1个人吃、1家人吃、喜事待客做好几桌,是不同的问题。
   一样的,图片上传,是上传1张还是多张,前真个用户体验如何,后端逻辑处理是不是正确,图片存储是不是可靠。
   本文主要探讨这个问题。

3. 有些情况,真不是我的问题。
   比如,前端上传组件是他人写的,1会这样做,1会那样做,后端不断改。
   比如,代码本来都不是我写的,是由于需求变化了,我接手了,然后自己改。 

-------------------------------------------------------------------------
   下面,重点探讨第2个缘由,技术问题。

a.上传单个图片
  html写个file类型的input,form设置1下,enctype="multipart/form-data"。
  
  后端写个方法处理下就好,扼要2点,1是用
@RequestParam MultipartFile 接收1个文件,2是用FileUtils复制临时文件到目标文件
  
   
@RequestMapping(value = "oneFileUpload", method = RequestMethod.POST) public String uploadLoginSplash(HttpServletRequest request, @RequestParam("file") MultipartFile file) throws IOException { if (!file.isEmpty()) { String realPath = request.getSession().getServletContext().getRealPath(SPLASH); // 这里没必要处理IO流关闭的问题,由于FileUtils.copyInputStreamToFile()方法内部会自动把用到的IO流关掉,我是看它的源码才知道的 FileUtils.copyInputStreamToFile(file.getInputStream(), new File(realPath, SPLASH_JPG)); } return "manager/setting/settingManager"; }



b. 上传多个图片。
 方法1:
  定义多个file,后端用数组接收@RequestParam("file") CommonsMultipartFile[] files。
 1种比较灵活的方式是,写JS方法,点击“添加”和“删除”,可以选择增加上传图片的“上传框”。

 这类方式,我没有去实践,在CSDN上看到了1篇不错的帖子,属于看了但没有去实践。

方法2:
使用图片上传组件,相比方法1,更加灵活,但也有缺点,后端接收不能直接使用数组CommonsMultipartFile[] files,我尝试了不太行。
前端上传组件,尝试的有webuploader,可以1次性选择多张图片,但是分批上传的。
尼玛,百度了下,原来是百度团队弄的,怪不得看起来用起来,好高端大气的模样。
官网:http://fex-team.github.io/webuploader/

最早用的是,dropzone,感觉还行,但是没有百度的看起来美观,1次性可以选择多张图片,但1次性全部上传。
官网:http://www.dropzonejs.com/
最早的最早,某个同事用的是jquery的上传组件,印象中是的。

 后端处理多张图片的代码,比较通用的。
@RequestMapping("/idCardImageUpload") public void idCardImageUpload(HttpServletRequest request, HttpServletResponse response) throws IllegalStateException, IOException { // 创建1个通用的多部份解析器 CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver( request.getSession().getServletContext()); String finalFileName=""; // 判断 request 是不是有文件上传,即多部份要求 if (multipartResolver.isMultipart(request)) { // 转换成多部份request MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request; // 获得request中的所有文件名 Iterator<String> iter = multiRequest.getFileNames(); while (iter.hasNext()) { // 获得上传文件 MultipartFile file = multiRequest.getFile(iter.next()); if (file != null) { // 获得当前上传文件的文件名称 String fileName = file.getOriginalFilename(); // 如果名称不为“”,说明该文件存在,否则说明该文件不存在 if (StringUtils.isNotEmpty(fileName)) { String[] strs = fileName.split("."); String fileExtention="png"; // 重命名上传后的文件名 if(strs.length >=2){ fileExtention=strs[strs.length⑴]; } try { fileName = AES.Encrypt(fileName, DateFormatUtil .format(new Date(), "yyyyMMddHHmmssSSS") .substring(1))+"."+fileExtention; finalFileName +=fileName+","; // 定义上传路径 String imagePath = (String) BasePropertyConfigurer .getContextProperty("idCardImageUploadPath"); String path = imagePath + fileName; File localFile = new File(path); file.transferTo(localFile); } catch (Exception e) { e.printStackTrace(); } } } } JSONObject jsonObj = new JSONObject(); response.setContentType("text/html;charset=UTF⑻"); jsonObj.put("success", true); jsonObj.put("fileName",finalFileName); returnJsonObject(response, jsonObj); } }


--------------------------------------------------------------------------------------------
上面介绍了缘由,然后重点论述了前后真个组件和实践方法,下面回归“图片上传问题”的本质,即流程问题。

图片上传流程
第1步:通过上传组件,选择1张或多张图片。
第2步:肯定上传,把图片传到后端,后端接收图片,保存到某个位置。
第3步:前端提交表单,包括图片的名字等。

这个问题有点复杂,再补充几点:
第1:上传是可以同步的,也能够是异步的。
   比如通过form提交到后端,也能够是通过jquery等插件AJAX提交。
   异步提交的时候,需要后端“回显图片信息”,比如图片的名字、图片的URL。

第2:是不是允许图片存储位置,有“脏数据”,即没有实际价值的图片。
  比如,1个用户选择了图片,上传到了后端,但是表单可能没有提交。

  如果,直接把用户的图片,放到实际的存储位置,就有脏数据了,但不影响图片的展现。

  另外1种方式是,用户上传的图片,先存到1个特定的临时位置,用户肯定上传图片后,把这里的图片移动到,实际的存储位置。

第3:图片信息存到数据库
  个人觉得,只存储图片的名字比较好,至于路径,存到数据库以后,会非常不灵活。
  前端展现图片,自定义url路径,比如/image/a.jpg,后端把/image路径映照到实际的图片位置。

第4:图片的名字。
 把用户上传时的名字,作为实际存储的图片名字不好,1是中文容易出问题,2是不能保证唯1性,会存在覆盖的可能性。
 个人觉得,图片的名字用时间+随机数等方式生成唯1的名字,比如abcd.jpg。
 这个时候需要注意,图片的后缀,需要从用户上传的图片名字解析出来,比如从“小雷FansUnion.png”解析出后缀".png",把
“小雷FansUnion.gif”存为“abcd.png”可能没法正常显示。

第5:图片上传也能够使用云服务。
 2014年春,做ITFriend的时候,用的是“美图秀秀的图片上传组件”。云服务用着还是不错的,上传以后,可以立即进行“美化”“涂鸦”等操作。
终究,再保存到数据库

第6:图片存储也能够使用云服务。
个人觉得,图片1定要存储到Tomcat等服务器的外部。有的人为了方便,把图片存储到Tomcat的webapps目录,这样比较危险,tomcat重启-重新部署,可能会把图片给弄丢了。

存储到硬盘等外部,做个图片要求映照就好。

还有1种方式,图片存储也使用“云存储”,又拍云用着还凑合。
-------------------------------------------------
总结,图片上传实际上是个很复杂的问题。
没有足够经验,不懂实际需求的开发者,进度会估计不准。

参考资料
http://fex-team.github.io/webuploader/
http://www.dropzonejs.com/
http://blog.csdn.net/a1314517love/article/details/24183273 
秒针工作时,BrandCenter项目积累
朋来谷工作时,ITFriend项目积累
1起好工作时,p2p项目积累
 
------分隔线----------------------------
------分隔线----------------------------

最新技术推荐