图片上传那些事

简述:

一个项目上,之前已经做好了用flash上传图片的功能,但是现在因为客户端的限制,要求不用flash,可以使用html5,于是改造开始了。

先给出之前flash的界面:

需求: 

上面的图片里面可以看出三个需求:

1. 文件选择按钮外观需要美化

2. 可以预览图片

3. 上传图片(上传后的图片存在形式需要与之前flash上传的一样,也就是说需要byte[]的形式)

用户上传图片之后,需要把新的图片显示到其他位置,所以还有一个需求:

4. 上传成功后调用回调函数

思考:

1. 文件选择按钮外观需要美化

  这个问题比较容易,下面会直接给出方案。

2. 可以预览图片

  这个问题对于html5来说也是小事一件,下面会给出方案。

3. 上传图片

4. 上传成功后调用回调函数

  单纯的上传图片,使用form提交即可,与服务端交互之后调用回调函数也比较容易,ajax即可。但是如果要同时满足两个条件,问题来了:

  P1 : form提交的方式如何回调?

  p2 :  ajax的方式如何上传图片?

oh,shit,dilemma problem...

解决方案:

1. 文件选择按钮外观需要美化

  首先要有一个文件选择按钮: <input type="file" />

  针对按钮本身去优化样式,应该是行不通的,所以目前比较流行的方式都是把按钮设置为透明的,然后覆盖在一个带有样式的“按钮”上。一个提供外观,一个提供文件选择功能。参考代码如下:

  


<style>
a {
display: inline-block;
width: 108px;
height: 30px;
background-repeat: no-repeat;
background-image: url("fileChooser.jpg");
position: relative;
overflow: hidden;
}
input{
position: absolute;
right: 0;
top: 0;
font-size: 100px;
opacity: 0;
filter: alpha(opacity = 0);
cursor: pointer;
}
</style>

<a href="#">
<input type="file"/>
</a>

2. 可以预览图片

  预览图片有两种方式,但其实都是殊途同归,就是如何获取到图片的url

  2.1 使用FileReader把图片读到内存中,然后再获取以data:开头的图片数据,并设置给img的src中

    


<input type="file">
<img id="img">
<script type="text/javascript">
$("input").change(function(){
var file = this.files[0];
var reader = new FileReader();
reader.onload = function(e){
$("#img").attr("src", reader.result);
}
reader.readAsDataURL(file);
});
</script>

    有关FileReader的详情可以到 http://www.w3.org/TR/file-upload/#dfn-filereader
查看,这里暂时不详述了,之后再写一个专题介绍。

  2.2 还可以使用createObjectURL方法来获取到图片的url来设置给img

    


<input type="file">
<img id="img">
<script type="text/javascript">
$("input").change(function(){
var file = this.files[0];
$("#img").attr("src", getObjectURL(file));
});
function getObjectURL(file) {
var url = null;
if (window.createObjectURL != undefined) { // basic
url = window.createObjectURL(file);
} else if (window.URL != undefined) { // mozilla(firefox)
url = window.URL.createObjectURL(file);
} else if (window.webkitURL != undefined) { // webkit or chrome
url = window.webkitURL.createObjectURL(file);
}
return url;
}

3. 上传图片

4. 上传成功后调用回调函数

  这两个问题一起来说。

  上面已经提到了,实际上根据上传+回调的需求,有两种解决方案,但是都会遇到各自的问题,而实际证明,两个问题都可以解决,并且都可以达到目的。我们都分析一下。

  P1 : form提交的方式如何回调?

    首先我们确定上传图片使用form提交的方式,这个时候遇到的问题是如何进行回调。

    对于form提交,提交之后需要回调函数,并且参数是从服务端返回回来的这种情况下,都有一个统一的解法:

    增加一个隐藏的iframe,让form提交的时候target指向这个iframe(这是response会返回内容到这个iframe),同时启动一个定时器去查看iframe是否被写完,写完之后,就可以调用回调函数了。

    给一段伪代码:


<form id="form" action="some URL" target="hidenFrame" method="post">
<input name="file" type="file">
</form>
<img id="img">
<button id="submit"></submit>
<iframe name="hidenFrame"></iframe>

<script type="text/javascript">
$("input").change(function(){
var file = this.files[0];
$("#img").attr("src", getObjectURL(file));
});
function getObjectURL(file) {
var url = null;
if (window.createObjectURL != undefined) { // basic
url = window.createObjectURL(file);
} else if (window.URL != undefined) { // mozilla(firefox)
url = window.URL.createObjectURL(file);
} else if (window.webkitURL != undefined) { // webkit or chrome
url = window.webkitURL.createObjectURL(file);
}
return url;
}
$("#submit").click(function(){
var form = $("#form")[0];
form.enctype = "multipart/form-data";
if ($("input")[0].files.length) {
form.submit();
var interval = setInterval(
function() {
var written = check();//check() is some code to check if response is written in iframe
if (written) {
callback();// call callback
clearInterval(interval);
}
}, 100);
}
});

      上述代码只有check()部分没有给出,读者自行填充即可。一般可以在response里面写上一段javascript代码,其中定义一个方法,方法中返回回调函数所需的参数,interval中每次都检查

      iframe里面是否已经定义了约定好的获取返回参数的方法,即可同时达到判断response是否已经完毕以及获取回调函数参数两个目的。

    

  p2 :  ajax的方式如何上传图片?

     ajax对回调来说非常容易,但是form上传到服务端的时候上传的是什么东西?如何构造数据才能传到服务端,让服务端解析?

     解决这个问题有一个很NB的方法,用FormData。(因为我在听说这个对象之前,做了很多工作来转换图片,以求达到跟form一样的格式传到服务端,所以觉得很NB)

     直接给出代码:

      


<form id="form" action="some URL" target="hidenFrame" method="post">
<input name="file" type="file">
</form>
<img id="img">
<button id="submit"></submit>
<iframe name="hidenFrame"></iframe>

<script type="text/javascript">
$("input").change(function(){
var file = this.files[0];
$("#img").attr("src", getObjectURL(file));
});
function getObjectURL(file) {
var url = null;
if (window.createObjectURL != undefined) { // basic
url = window.createObjectURL(file);
} else if (window.URL != undefined) { // mozilla(firefox)
url = window.URL.createObjectURL(file);
} else if (window.webkitURL != undefined) { // webkit or chrome
url = window.webkitURL.createObjectURL(file);
}
return url;
}
$("#submit").click(function(){
$.ajax({
url: "some URL",
async: true,
type: "post",
contentType:false, //需要设置false,否则jquery会处理二进制数据,但我们不希望jquery处理
processData:false, //需要设置false,否则jquery会处理二进制数据,但我们不希望jquery处理
data: new FormData($("#form")[0]),
success: function(serverData){
callback(serverData);
}
});
});

    很明显的,使用FormData+ajax的方式对上传+回调的需求使用起来最简洁。

一些没提到的事情:

1.  服务端如何解析上传的图片

  这个问题在上面没有提到,这里给出java的一个实现,其中因为最后存储图片以及获取图片路径的方法是公司内部的方法,贴出来也没什么用,所以给隐去了,但骨架如下:

  


import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class PortraitRequestHandler implements JspRequestHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response) throws Throwable {

try {
request.setCharacterEncoding("GBK");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
// 文件上傳部分
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart == true) {
try {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);

// 得到所有的表单域,它们目前都被当作FileItem
List<FileItem> fileItems = upload.parseRequest(request);
Iterator<FileItem> iter = fileItems.iterator();

// 依次处理每个表单域
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (!item.isFormField()) {// 如果是上传域
// 获得文件名及路径
String fileName = item.getName();
if (fileName != null) {

byte[] b = new byte[(int) item.getSize()];
item.getInputStream().read(b);
// 这里b就是图片的内容,可以调用需要的方法存储
}
}
}
PrintWriter out = response.getWriter();
out.append("/* 这里返回刚上传图片的访问路径 */");
} catch (Exception e) {
e.printStackTrace();
}
}
}

}

  

2. Form上传的时候,上传的到底是什么形式的数据?

  Form也好FormData+ajax的方式也好,实际上用什么形式上传用户选择的文件,都是浏览器做的工作,我们不是很清楚。但是从上面的服务端程序就可以看出,实际上最终是以byte流的形式post到服务端的,

  服务端也用了apache的fileupload来处理。

  想想其实不难理解。文件肯定是以二进制流的形式传到服务端进行存储,呃,废话。

思考题:

如果不用FormData,ajax方式咋传图片?

  提两个思路,抛砖引玉:上文提到了FileReader,FileReader有readAsArrayBuffer方法可以把图片读成byte流。
 

  另一个思路: 图片有自己特有的一个保存形式,即
data:开始的一段数据。 FileReader同样提供了这样的接口,并且上面我们用到过。

图片上传那些事,布布扣,bubuko.com

时间: 2024-10-13 22:01:41

图片上传那些事的相关文章

妈蛋:kinMaxShow轮播图异常,WebUploader图片上传坑爹,图片被压缩了

今天晚上在改造轮播图. 原来的代码是这样的: <div> <img src="${static}/image/index/banner/`.jpg" /> </div> <div> <img src="${static}/image/index/banner/2.jpg" /> </div> <div> <img src="${static}/image/index/

UEditor之实现配置简单的图片上传示例

开心一笑 下班后,阿华到楼下小超市买毛巾,刚买完出来,就遇到同一办公楼里另一家公司的阿菲,之前与她远远的有过几次眼神交流,但从没说过话,"买毛巾啊",看着阿华手里的毛巾,阿菲先开口了. 阿华回到:"是啊,这里的老板眼神太好了,我不敢偷,就只有买了." 阿菲一下就哈哈笑了,配合到:"哇,原来你是小偷." 阿华:"嘘,小声点,其实主要原因是--"阿华指着自己的脑袋接着说到:"你看,我是个有头有脸的人,所以还是要用用毛巾的

UEditor之基于Java图片上传前后端源码研究

开心一笑 一定要快乐学习,所以学习之前先看个笑话: 刚来北京,租了一个小房,一楼,上淘宝买衣服,选了付钱了联系卖家:"我已付款,请发货."谁知那货直接说:"我看到你地址了,自己上楼来拿吧!我就在你楼上." 拿你妹,老子付了邮费的...送下来. 提出问题 Ueditor前后端源码的学习和简单的研究??? 解决问题 前提: 假如你已经看了我的前一篇文章,这一点很重要的啊,当然不看也可以,因为你已经是一个高手,就像我一样,哈哈: 假如你已经安装tomcat服务器: 假如你

妈蛋:kinMaxShow旋转木马异常,WebUploader图片上传坑爹,图像被压缩

今天晚上在改造轮播图. 原来的代码是这种: <div> <img src="${static}/image/index/banner/`.jpg" /> </div> <div> <img src="${static}/image/index/banner/2.jpg" /> </div> <div> <img src="${static}/image/index/b

图片上传时遇到的问题

今天在用ssm框架做图片上传的时候遇见一个问题: 后来检查发现是springMVC配置文件中遗漏了关于图片上传的配置文件 把上面的<bean>配置好就可以了: 顺便总结一下: 图片上传只需要记住三件事: 前台页面:(1)要用post请求:(2)别忘了在form表单中加入enctype="multipart/form-data" 后台controller层要这样写: 3.如果上面代码没问题,就检查一下springmvc配置文件;

KindeEditor图片上传插件用法

因业务需要找了款插件 KindeEditor编辑器确认挺好用,但无奈技术有限,上传配置不知,故问度娘! 图片上传对于部分新手来说有时候是一件非常头疼的事,今天来分享一下项目中使用到的这个插件KindeEditor:对于图片上传.文件上传都是分分钟搞定的事,配置简单:现在来分享一下: KindeEditor官网Api文档:http://kindeditor.net/doc.php 要想使用此插件我们首先就要去官网下载,下载完成后将插件放进我们的项目当中,如图: 接着就是前端如何使用该插件,同样废话

图片上传_及时显示

其实到现在我从刚毕业的雄心壮志,已经变为攀爬的小鸟了.虽然在没有任务的情况下贪玩着,不过在接到任务的时,我还是抱着百分之百的心去完成. 在学校时,拖控件是我最喜欢做的事,因为很简单方便.从来没有考略过性能之类的问题,绝对做出来我就很厉害了.但是现在到了公司完全是老鸟鄙视的对象,虽然公司没有明确规定你不能拖控件,但是可能是虚荣心吧,努力扔掉控件,像js 进发. 我觉得我现在的状态就是,出生的婴儿,见一个学一个. 今天就总结一个我自己知道的图片上传. js: 1 $(function () { 2

图片上传组件开发

我就要自行车 - 需求整理 放眼WWW,一般的图片上传模块,主要就是实现了三个功能,图片的预览,图片的剪裁及预览,图片的上传,那我也就整这么一个吧,再细化一下需求. 图片的预览 用户使用:用户点击“选择图片”,弹出文件浏览器,可以选择本地的图片,点击确认后,所选图片会按照原始比例出现在页面的浏览区域中. 组件调用:开发者可以自己定义图片预览区域的大小,并限定所传图片的文件大小和尺寸大小. 图片的剪裁 用户使用:用户根据提示,在预览区域的图片上拖动鼠标框出想要上传的图片区域,并且能在结果预览区域看

node.js实现图片上传(包含缩略图)

图片上传 使用multiparty插件实现上传 安装multiparty npm i --save multiparty 代码实现 const multiparty = require('multiparty'); let form = new multiparty.Form({uploadDir: upload.path}); 构造参数说明 encoding 设置接收数据编码,默认是utf-8 maxFieldsSize 限制字段可以分配的内存量,默认2M maxFields 限制在发出错误事