有时候,在开发中,需要遇到拖拽上传图片的需求,即从磁盘选中一张或多张图片,然后按着鼠标把图片拖动到页面上指定的区域,实现图片的上传。

需要购买阿里云产品和服务的,点击此链接领取优惠券红包,优惠购买哦,领取后一个月内有效: https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=fp9ccf07

1、后端上传图片的接口

我是之前用vue写一个简单的后台系统的时候,用Java的SpringMVC+MyBatis的框架写了一个简单的后台管理的一些接口,刚好有一个上传用户头像的接口,该接口是把上传后的图片存储在另外一台Tomcat下,这里就直接使用这个接口来上传图片。

/**
* 上传用户头像
* @param request
* @param response
*/
@ResponseBody
@RequestMapping(value="uploadSysHeadImg.do", method=RequestMethod.POST)
public void uploadSysHeadImg(HttpServletRequest request,HttpServletResponse response){
JSONObject jo = new JSONObject();
//校验token
// boolean f = tokenService.checkToken(request, response);
// if(!f){ return; } try {
MultipartResolver resolver = new CommonsMultipartResolver(request.getSession().getServletContext());
MultipartHttpServletRequest Murequest = resolver.resolveMultipart(request);
Map<String, MultipartFile> files = Murequest.getFileMap();//得到文件map对象
// 实例化一个jersey
Client client = new Client(); List<String> fileNameList = new ArrayList<>();
List<String> relaPathList = new ArrayList<>();
List<String> realPathList = new ArrayList<>();
for(MultipartFile pic: files.values()){
String uploadInfo = Upload.upload(client, pic, request, response, uploadHost, headImgPath);
if(!"".equals(uploadInfo)){ //如果上传成功
String[] infoList = uploadInfo.split(";");
fileNameList.add(infoList[0]); //文件名
relaPathList.add(infoList[1]); //相对路径
realPathList.add(infoList[2]); //真实路径
}else{ //如果上传失败
fileNameList.add("");
relaPathList.add("");
realPathList.add("");
}
}
jo.put("success", 1);
jo.put("error", null);
jo.put("fileNameList", fileNameList);
jo.put("relaPathList", relaPathList);
jo.put("realPathList", realPathList);
}catch (Exception e) {
jo.put("success", 0);
jo.put("error", "上传失败");
}
ResponseUtils.renderJson(response, jo.toString());
}

2、前端代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.bootcss.com/jquery/1.12.0/jquery.js"></script>
<style>
#drop_area {
position: relative;
width: 300px;
height: 150px;
border: 1px dashed #ddd;
border-radius: 5px;
margin-bottom: 5px;
}
#drop_area .text {
position: absolute;
width: 100%;
top: 60px;
text-align: center;
font-size: 14px;
}
#img_area {
width: 300px;
}
#img_area img {
width: 300px;
margin-bottom: 5px;
}
</style>
</head>
<body>
<div id="drop_area">
<div class="text"><span>+</span><span>将文件拖到此处,即可上传</span></div>
</div>
<div id="img_area"></div>
</body> <script>
var dp = document.getElementById('drop_area');
dp.addEventListener('dragover', function(e) {
e.stopPropagation();
//阻止浏览器默认打开文件的操作
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
}); //单图上传
// dp.addEventListener("drop", function(e) {
// e.stopPropagation();
// //阻止浏览器默认打开文件的操作
// e.preventDefault();
// var files = e.dataTransfer.files;
// var file = files[0];
// var formData = new FormData();
// formData.append("file", file);
// $.ajax({
// type: 'post',
// url: 'http://127.0.0.1:8081/ssm_project/sysUser/uploadSysHeadImg.do',
// data: formData,
// contentType: false, //必须 禁止jQuery设置Content-Type请求头
// processData: false, //必须 禁止jQuery处理发送的数据
// dataType: "json",
// success: function(res){
// if(res.success == 1){
// }
// },
// });
// }); //多图上传
dp.addEventListener("drop", function(e) {
e.stopPropagation();
//阻止浏览器默认打开文件的操作
e.preventDefault();
var files = e.dataTransfer.files;
var formData = new FormData();
for(var i =0; i<files.length; i++){
formData.append("file"+i, files[i]);
}
$.ajax({
type: 'post',
url: 'http://127.0.0.1:8081/ssm_project/sysUser/uploadSysHeadImg.do',
data: formData,
contentType: false, //必须 禁止jQuery设置Content-Type请求头
processData: false, //必须 禁止jQuery处理发送的数据
dataType: "json",
success: function(res){
if(res.success == 1){
res.realPathList.forEach(function(item){
$('#img_area').append('<img src="'+item+'">');
});
}
},
});
});
</script>
</html>

我在这里用的是jquery的ajax请求。

里面用的formData对象来上传图片的,该对象的作用是:

  1、用一些键值对来模拟一系列表单控件,即把form中所有表单元素的name与value组装成一个queryString;

  2、异步上传二进制文件。

另外有两个属性的值,我们必须要设置它们的值为false:

  contentType: false, //必须 禁止jQuery设置Content-Type请求头

    processData: false, //必须 禁止jQuery处理发送的数据

其中先封装了一个 formData 对象,然后使用 post 方法将文件传给服务器。

这里我们就要先说说在 http 中传输文件的问题。起初http协议中没有上传文件方面的功能,直到rfc1867为http协议添加了这个功能。当然在rfc1867中限定form的method必须为POST, enctype = “multipart/form-data” 以及<input type = "file">。

当我们使用表单上传文件时,我们来查看他的Request headers,如下图:

发现在 multipart/form-data 后面有boundary以及一串字符,这是分界符,后面的一堆字符串是随机生成的,目的是防止上传文件中出现分界符导致服务器无法正确识别文件起始位置。说到这肯定就要说说这分界符有啥作用呢?

因为对于上传文件,我们没有在使用原有的 http 协议,所以 multipart/form-data 请求是基于 http 原有的请求方式 post 而来的.那么来说说这个全新的请求方式与 post 的区别

  1. 请求头的不同,对于上传文件的请求,contentType = multipart/form-data是必须的,而 post 则不是,毕竟 post 又不是只上传文件~。

  2. 请求体不同。这里的不同也就是指前者在发送的每个字段内容之间必须要使用分界符来隔开,比如文件的内容和文本的内容就需要分隔开,不然服务器就没有办法正常的解析文件,而后者 post 当然就没有分界符直接以 name = "value"的形似发送。

而在我的这段JQuery ajax() 方法中,我设置了contentType = false,这不是冲突了吗?这当然没有,因为当我们查看这时的 Request headers,会发现还是有分界符。这是因为当我们在 form 标签中设置了enctype = “multipart/form-data”,这样请求中的 contentType 就会默认为 multipart/form-data (我用的是new formData()对象,它其实就是模拟了一个表单控件,也就是form标签)。而我们在 ajax 中 contentType 设置为 false 是为了避免 JQuery 对其操作,从而失去分界符,而使服务器不能正常解析文件。

3、效果

需要购买阿里云产品和服务的,可以点击此链接领取优惠券红包,优惠购买哦,领取后一个月内有效: https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=fp9ccf07

js拖拽上传图片的更多相关文章

  1. h5拖拽上传图片

    h5实现拖拽上传图片 本文将为大家介绍如何通过js实现拖拽上传图片. 首先我们要禁用调浏览器默认的拖拽事件: window.onload = function(){ //拖离 document.add ...

  2. HTML5 CSS3 经典案例:无插件拖拽上传图片 (支持预览与批量) (二)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/31513065 上一篇已经实现了这个项目的整体的HTML和CSS: HTML5 C ...

  3. 再谈React.js实现原生js拖拽效果

    前几天写的那个拖拽,自己留下的疑问...这次在热心博友的提示下又修正了一些小小的bug,也加了拖拽的边缘检测部分...就再聊聊拖拽吧 一.不要直接操作dom元素 react中使用了虚拟dom的概念,目 ...

  4. React.js实现原生js拖拽效果及思考

    一.起因&思路 不知不觉,已经好几天没写博客了...近来除了研究React,还做了公司官网... 一直想写一个原生js拖拽效果,又加上近来学react学得比较嗨.所以就用react来实现这个拖 ...

  5. js拖拽效果

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. 关于 JS 拖拽功能的冲突问题及解决方法

    前言 我在之前写过关于 JS 拖拽的文章,实现方式和网上能搜到的方法大致相同,别无二致,但是在一次偶然的测试中发现,这种绑定事件的方式可能会和其它的拖拽事件产生冲突,由此产生了对于事件绑定的思考.本文 ...

  7. js拖拽分析

    js拖拽分析 思路 1.三个鼠标事件,mousedown,mousemove,mouseup 2.可移动性absolute 3.边界限制 得到鼠标点击处和div边界的距离,然后得出top 和 left ...

  8. JS拖拽div(移动)

    <!doctype html><html><head> <meta charset="utf-8"> <title>JS ...

  9. 浅谈js拖拽

    本文来自网易云社区 作者:刘凌阳 前言 本文依据半年前本人的分享<浅谈js拖拽>撰写,算是一篇迟到的文章. 基本思路 虽然现在关于拖拽的组件库到处都是,HTML5也把拖放纳入了标准.但考虑 ...

随机推荐

  1. SQL Server 2016 + AlwaysOn 无域集群

    目录 AlwaysOn 搭建 WSFC 配置计算机的 DNS 后缀 安装故障转移集群 验证集群 创建集群 创建文件共享见证 配置 AlwaysOn 新建可用性组 创建侦听器 可读副本的负载均衡 主角色 ...

  2. Abnormal build process termination IDEA启动报错

    报错如下: Error:Abnormal build process termination: "C:Program FilesJavajdk1.11.0_1injava" -Xm ...

  3. Java底层技术系列文章-线程池框架

    一.线程池结构图    二.示例 定义线程接口 public class MyThread extends Thread { @Override publicvoid run() { System.o ...

  4. 奇袭(单调栈+分治+桶排)(20190716 NOIP模拟测试4)

    C. 奇袭 题目类型:传统 评测方式:文本比较 内存限制:256 MiB 时间限制:1000 ms 标准输入输出   题目描述 由于各种原因,桐人现在被困在Under World(以下简称UW)中,而 ...

  5. [Poi2012]Festival 题解

    [Poi2012]Festival 时间限制: 1 Sec  内存限制: 64 MB 题目描述 有n个正整数X1,X2,...,Xn,再给出m1+m2个限制条件,限制分为两类: 1. 给出a,b (1 ...

  6. [Microsoft][ODBC Driver 11 for SQL Server][SQL Server]列名 'user1' 无效

    唉,还是自己对php执行sql语句运用不熟练.... 我的错误代码是这样的,(解决办法在最后) $re=sqlsrv_query($conn, "select * from visitor ...

  7. textarea 绕过jq验证的方法,提交空值

    <textarea placeholder=" aria-required="true" aria-describedby="OtherNotes-err ...

  8. 图像识别sift+bow+svm

    本文概述 利用SIFT特征进行简单的花朵识别 SIFT算法的特点有: SIFT特征是图像的局部特征,其对旋转.尺度缩放.亮度变化保持不变性,对视角变化.仿射变换.噪声也保持一定程度的稳定性: SIFT ...

  9. 【转】DataTable 中数据筛选

    转自:http://blog.163.com/yangxw_2009/blog/static/155255217201032931755646/ 对DataTable进行过滤筛选的一些方法Select ...

  10. 《VR入门系列教程》之15---配置Oculus的开发环境

    安装Oculus SDK     在使用类似Unity3D之类的引擎开发Oculus Rift应用之前,你必须先安装Oculus的SDK,在Oculus的官网上可以下载:http://develope ...