详细阐述Web开发中的图片上传问题
Web开发中,图片上传是一种极其常见的功能。但是呢,每次做上传,都花费了不少时间。
一个“小功能”花费我这么多时间,真心不愉快。
So,要得认真分析下原因。
1.在最初学习Java Web开发的时候,经验不足,属于能力问题,比如对技术认识不到位。
2.图片上传是一类问题,而不是一个问题。
比如,大家都会做饭,但每个人自己做饭是有不同的。做了一个人吃、一家人吃、喜事待客做好几桌,是不同的问题。
同样的,图片上传,是上传一张还是多张,前端的用户体验如何,后端逻辑处理是否正确,图片存储是否可靠。
本文主要探讨这个问题。
3. 有些情况,真不是我的问题。
比如,前端上传组件是别人写的,一会这样做,一会那样做,后端不断改。
比如,代码本来都不是我写的,是因为需求变化了,我接手了,然后自己改。
-------------------------------------------------------------------------
下面,重点探讨第2个原因,技术问题。
a.上传单个图片
html写个file类型的input,form设置一下,enctype="multipart/form-data"。
后端写个方法处理下就好,简要2点,1是用@RequestParam MultipartFile 接收一个文件,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. 上传多个图片。
方法一:
定义多个file,后端用数组接收@RequestParam("file") CommonsMultipartFile[] files。
一种比较灵活的方式是,写JS方法,点击“添加”和“删除”,可以选择增加上传图片的“上传框”。
这种方式,我没有去实践,在CSDN上看到了一篇不错的帖子,属于看了但没有去实践。
方法二:
使用图片上传组件,相比方法一,更加灵活,但也有缺点,后端接收不能直接使用数组CommonsMultipartFile[] files,我尝试了不太行。
前端上传组件,尝试的有webuploader,可以一次性选择多张图片,但是分批上传的。
尼玛,百度了下,原来是百度团队搞的,怪不得看起来用起来,好高端大气的样子。
官网:http://fex-team.github.io/webuploader/
最先用的是,dropzone,感觉还行,但是没有百度的看起来美观,一次性可以选择多张图片,但一次性全部上传。
官网:http://www.dropzonejs.com/
最先的最先,某个同事用的是jquery的上传组件,印象中是的。
后端处理多张图片的代码,比较通用的。
@RequestMapping("/idCardImageUpload")
public void idCardImageUpload(HttpServletRequest request,
HttpServletResponse response) throws IllegalStateException,
IOException {
// 创建一个通用的多部分解析器
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-1];
}
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-8");
jsonObj.put("success", true);
jsonObj.put("fileName",finalFileName);
returnJsonObject(response, jsonObj);
}
}
--------------------------------------------------------------------------------------------
上面介绍了原因,然后重点阐述了前后端的组件和实践方法,下面回归“图片上传问题”的本质,即流程问题。
图片上传流程
第一步:通过上传组件,选择一张或多张图片。
第二步:确定上传,把图片传到后端,后端接收图片,保存到某个位置。
第三步:前端提交表单,包括图片的名字等。
这个问题有点复杂,再补充几点:
第一:上传是可以同步的,也可以是异步的。
比如通过form提交到后端,也可以是通过jquery等插件AJAX提交。
异步提交的时候,需要后端“回显图片信息”,比如图片的名字、图片的URL。
第二:是否允许图片存储位置,有“脏数据”,即没有实际价值的图片。
比如,一个用户选择了图片,上传到了后端,但是表单可能没有提交。
如果,直接把用户的图片,放到实际的存储位置,就有脏数据了,但不影响图片的展示。
另外一种方式是,用户上传的图片,先存到一个特定的临时位置,用户确定上传图片后,把这里的图片移动到,实际的存储位置。
第三:图片信息存到数据库。
个人觉得,只存储图片的名字比较好,至于路径,存到数据库之后,会非常不灵活。
前端展示图片,自定义url路径,比如/image/a.jpg,后端把/image路径映射到实际的图片位置。
第四:图片的名字。
把用户上传时的名字,作为实际存储的图片名字不好,一是中文容易出问题,二是不能保证唯一性,会存在覆盖的可能性。
个人觉得,图片的名字用时间+随机数等方式生成唯一的名字,比如abcd.jpg。
这个时候需要注意,图片的后缀,需要从用户上传的图片名字解析出来,比如从“小雷FansUnion.png”解析出后缀".png",把
“小雷FansUnion.gif”存为“abcd.png”可能无法正常显示。
第五:图片上传也可以使用云服务。
2014年春,做ITFriend的时候,用的是“美图秀秀的图片上传组件”。云服务用着还是不错的,上传之后,可以立即进行“美化”“涂鸦”等操作。
最终,再保存到数据库。
第六:图片存储也可以使用云服务。。
个人觉得,图片一定要存储到Tomcat等服务器的外部。有的人为了方便,把图片存储到Tomcat的webapps目录,这样比较危险,tomcat重启-重新部署,可能会把图片给搞丢了。
存储到硬盘等外部,做个图片请求映射就好。
还有一种方式,图片存储也使用“云存储”,又拍云用着还凑合。
-------------------------------------------------
总结,图片上传其实是个很复杂的问题。
没有足够经验,不懂实际需求的开发者,进度会估计不准。
参考资料
http://fex-team.github.io/webuploader/
http://www.dropzonejs.com/
http://blog.csdn.net/a1314517love/article/details/24183273
秒针工作时,BrandCenter项目积累
朋来谷工作时,ITFriend项目积累
一起好工作时,p2p项目积累
详细阐述Web开发中的图片上传问题的更多相关文章
- 关于web项目中的图片上传、并在前端显示问题(tomcat中配置文件上传虚拟路径)
一.数据库存储 直接把图片的二进制码存到数据库,可参考blog:http://blog.csdn.net/hope2jiang/article/details/590733 直接存图片在mysql上面 ...
- 【转】关于web项目中的图片上传、并在前端显示问题(tomcat中配置文件上传虚拟路径)
一.数据库存储 直接把图片的二进制码存到数据库,可参考blog:http://blog.csdn.net/hope2jiang/article/details/590733 直接存图片在mysql上面 ...
- 分享一个FileUtil工具类,基本满足web开发中的文件上传,单个文件下载,多个文件下载的需求
获取该FileUtil工具类具体演示,公众号内回复fileutil20200501即可. package com.example.demo.util; import javax.servlet.htt ...
- iOS开发中文件的上传和下载功能的基本实现-备用
感谢大神分享 这篇文章主要介绍了iOS开发中文件的上传和下载功能的基本实现,并且下载方面讲到了大文件的多线程断点下载,需要的朋友可以参考下 文件的上传 说明:文件上传使用的时POST请求,通常把要上传 ...
- 使用express+multer实现node中的图片上传
使用express+multer实现node中的图片上传 在前端中,我们使用ajax来异步上传图片,使用file-input来上传图片,使用formdata对象来处理图片数据,post到服务器中 在n ...
- 微信小程序开发之多图片上传+服务端接收
前言: 业务需求,这次需要做一个小程序同时选中三张图片一起上传到服务端,后端使用的.NET WEBAPI接收数据保存. 使用技术: 在这章中将会使用到微信小程序wx.uploadFile(Object ...
- web高拍仪图片上传
公司引进高拍仪,想拍完照片点上传按钮直接上传图片.高拍仪接口能提供照片的本地路径,现在的问题是不用file控件选择,只有路径,不知道如何上传到服务器,求解决方案. 方法: 使用泽优Web图片上传控件( ...
- 部署新浪SAE web.py Session及图片上传等问题注意事项
1.以下几条代码解决编码问题 import sysreload(sys)sys.setdefaultencoding('utf-8') 2.图片上传问题 需要开通sina的Storage服务,随便建个 ...
- 用Web Service实现客户端图片上传到网站
由于项目需要,通过本地客户端,把图片上传到网站.通过webservice. 这是客户端代码: private void btnimg_Click(object sender, EventArgs e) ...
随机推荐
- 浅析C#组件编程中的一些小细节
控件与组件的区别(Control&Component的区别) 作者:作者不详 发布日期:2011-06-30 12:08:41 控件与组件的区别(Control&Component的 ...
- c编程:僵尸吃大脑
第一行输入一个正整数n 以下每一行输入僵尸已经吃了的大脑数量a,和需要生存必需要吃的大脑数量b.总共n行. 例子输入 3 4 5 3 3 4 3 例子输出 NO BRAINS MMM BRAINS M ...
- Altium Designer的pcb界面如何让线变成点
但是16版本,需要tools --- Grid Manager --双击 双击后: 转自:http://blog.csdn.net/ldcung/article/details/77411434
- VS2012载入DLL编译出现试图载入格式不对的程序; 以及执行出现Mixed mode assembly is built against version 'v2.0.50727' of the
VS2012载入DLL编译出现试图载入格式不对的程序:以及执行出现Mixed mode assembly is built against version 'v2.0.50727' of therun ...
- [React Intl] Install and Configure the Entry Point of react-intl
We’ll install react-intl, then add it to the mounting point of our React app. Then, we’ll use react- ...
- 【UVA】434-Matty's Blocks
一道非常easy想复杂的题,给出主视图和右视图,计算最少能用几个正方体组成相应的视图,以及最多还能加几块正方体. 求最多加入事实上就是求出最多的正方体数减去最少的,主要就是最少的不好求. 一開始各种模 ...
- Python中字符串的解压缩
今天在用Streaming-Python处理一个MapReduce程序时,发现reducer失败,原由于耗费内存达到极限了.细致查看代码时,发现有一个集合里保存着URL,而URL长度是比較长的,直接保 ...
- MinGW、MinGW-w64 与TDM-GCC 应该如何选择?
MinGW.MinGW-w64 与TDM-GCC 应该如何选择? https://www.zhihu.com/question/39952667
- DIKW模型与数据工程(了解)
DIKW 体系 DIKW体系是关于数据.信息.知识及智慧的体系,可以追溯至托马斯·斯特尔那斯·艾略特所写的诗--<岩石>.在首段,他写道:"我们在哪里丢失了知识中的智慧?又在哪里 ...
- iOS View自定义窍门——UIButton实现上显示图片,下显示文字
“UIButton实现上显示图片,下显示文字”这个需求相信大家在开发中都或多或少会遇见.比如自定义分享View的时候.当然,也可以封装一个item,上边imageView,下边一个label.但是既然 ...