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

需要购买阿里云产品和服务的,点击此链接领取优惠券红包,优惠购买哦,领取后一个月内有效: 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. Python与C/C++相互调用

    参考链接:https://www.cnblogs.com/yanzi-meng/p/8066944.html

  2. 使用ajax的几种方式

    1.$.ajax()发送一个get请求,数据返回为json $.ajax({ type: "GET", url: "select", //ajax请求地址 da ...

  3. 你必须知道的Docker镜像仓库的搭建

    近期工作中发现用到的容器镜像越来越多(不多的时候没考虑过镜像仓库的问题),同一个容器镜像也存在多个版本,那么镜像仓库的搭建需求就涌现出来,本文就目前的几个常用镜像仓库的搭建进行介绍,我们可以根据需要选 ...

  4. 第八章 Fisco Bcos 国密版本的部署、控制台搭建、合约的部署、sdk 调用

    鉴于笔者以前各大博客教程都有很多人提问,早期建立一个技术交流群,里面技术体系可能比较杂,想了解相关区块链开发,技术提问,请加QQ群:538327407 参考资料 证书说明:https://mp.wei ...

  5. vs调试看窗口风格

    vs调试看窗口风格 技巧:在数值上右键,以16进制显示.

  6. 个人永久性免费-Excel催化剂功能第20波-Excel与Sqlserver零门槛交互-数据上传篇

    Excel作为众多数据存储的交换介质,在不同的系统内的数据很少可以很连贯地进行整合分析,一般的业务系统都会提供导出Excel作为标配功能供用户使用系统内生成的数据. 此时最大的问题是,Excel很维去 ...

  7. Java map笔记

    Map 是一个键值对的集合 花和尚 豹子头 鲁智深 林冲 如果想要从map中获得值,可以根据键 Map<Key,velue> Map虽然是集合,但是和collection的接口无关 我们可 ...

  8. classpath和classpath*区别

    classpath和classpath*区别: classpath:只会到你的class路径中查找找文件. classpath*:不仅包含class路径,还包括jar文件中(class路径)进行查找. ...

  9. C#2.0新增功能01 分布类与分部方法

    连载目录    [已更新最新开发文章,点击查看详细] 分部类型 拆分一个类.一个结构.一个接口或一个方法的定义到两个或更多的文件中, 每个源文件包含类型或方法定义的一部分,编译应用程序时将把所有部分组 ...

  10. u盘制作启动盘步骤以及安装win10步骤

    1.下载制作工具:微PE工具箱V2.0 http://www.wepe.com.cn/download.html 2.默认制作启动盘 3.下载win10镜像 ed2k://|file|cn_windo ...