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

需要购买阿里云产品和服务的,点击此链接领取优惠券红包,优惠购买哦,领取后一个月内有效: 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. 使用http3访问服务

    用到的包:import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.Response; 主要代码: try { //创建OkH ...

  2. Discuz ML! V3.X 代码注入漏洞

    Discuz ML! V3.X 代码注入漏洞 前言 Discuz!ML是一个由CodersClub.org创建的多语言,集成,功能齐全的开源网络平台,用于构建像"社交网络"这样的互 ...

  3. Class(类)和 继承

    ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰.更像面向对象编程的语法而已. //定义类 class Point { co ...

  4. py+selenium遇见IE,元素只有name属性【神奇解决】

    问题:当需要自动化测试某系统,而该系统只兼容IE8,怎么办? IE8的问题:IE8不支持getElementByName,而属性中又没有ID,定位难度较大. IE8以下不兼容getElementByN ...

  5. Sublime Text 3 实现C语言代码的编译和运行

    Sublime Text 3 是一款优秀的代码编辑软件.界面简洁,轻巧快速,很受大家的欢迎. 最近开始用他来编辑数据结构的C语言代码,这就需要在新建编译系统.具体方法如下: 首先: 接下来是关键的一步 ...

  6. java开发---关于ORA00604和ORA12705

    MyEclipse和oracle连接中出现的一个问题: 在使用工具连接orcale数据库时报了这两个异常  ORA-00604和ORA12705 ; 查找问题原因: 大概猜测是与字符集有关系 , 确认 ...

  7. 关键字static、final

    final final能修饰类.修饰方法.能修饰属性. 修饰类:该类不能被继承. 修饰方法:该方法不能被重写.所以abstract和final不能同时用 修饰属性/变量:该属性/变量为常量,该值不能再 ...

  8. c语言进阶11-经典算法代码

    重要算法一览 #include "stdio.h" #include "stdio.h" void main() { int a,b,c,i,n; int x, ...

  9. Visual Studio 调试系列1 Debug 与 Release 模式

    系列目录     [已更新最新开发文章,点击查看详细] Debug 模式 Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序. 在Debug模式下调试,可以在断点处看到 ...

  10. List集合源码解读

    一:总述: 主要讲解3个集合 1.ArrayList: 底层是数组,线程不安全: 2.LinkedList: 底层是链表,线程不安全: 3.Vector    底层数据结构是数组.线程安全: 二:Ar ...