1. Upload上传
1.1. 通过点击或者拖拽上传文件。
1.2. Upload上传属性
参数 | 说明 | 类型 | 可选值 | 默认值 |
action | 必选参数, 上传的地址 | string | 无 | 无 |
headers | 设置上传的请求头部 | object | 无 | 无 |
multiple | 是否支持多选文件 | boolean | 无 | 无 |
data | 上传时附带的额外参数 | object | 无 | 无 |
name | 上传的文件字段名 | string | 无 | file |
with-credentials | 支持发送cookie凭证信息 | boolean | 无 | false |
show-file-list | 是否显示已上传文件列表 | boolean | 无 | true |
drag | 是否启用拖拽上传 | boolean | 无 | false |
accept | 接受上传的文件类型(thumbnail-mode 模式下此参数无效) | string | 无 | 无 |
on-preview | 点击文件列表中已上传的文件时的钩子 | function(file) | 无 | 无 |
on-remove | 文件列表移除文件时的钩子 | function(file, fileList) | 无 | 无 |
on-success | 文件上传成功时的钩子 | function(response, file, fileList) | 无 | 无 |
on-error | 文件上传失败时的钩子 | function(err, file, fileList) | 无 | 无 |
on-progress | 文件上传时的钩子 | function(event, file, fileList) | 无 | 无 |
on-change | 文件状态改变时的钩子, 添加文件、上传成功和上传失败时都会被调用 | function(file, fileList) | 无 | 无 |
before-upload | 上传文件之前的钩子, 参数为上传的文件, 若返回false或者返回Promise且被reject, 则停止上传。 | function(file) | 无 | 无 |
before-remove | 删除文件之前的钩子, 参数为上传的文件和文件列表, 若返回false或者返回Promise且被reject, 则停止删除。 | function(file, fileList) | 无 | 无 |
list-type | 文件列表的类型 | string | text/picture/picture-card | text |
auto-upload | 是否在选取文件后立即进行上传 | boolean | 无 | true |
file-list | 上传的文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}] | array | 无 | [] |
http-request | 覆盖默认的上传行为, 可以自定义上传的实现 | function | 无 | 无 |
disabled | 是否禁用 | boolean | 无 | false |
limit | 最大允许上传个数 | number | 无 | 无 |
on-exceed | 文件超出个数限制时的钩子 | function(files, fileList) | 无 | 无 |
1.3. Slot
name | 说明 |
trigger | 触发文件选择框的内容 |
tip | 提示说明文字 |
1.4. Methods
方法名 | 说明 | 参数 |
clearFiles | 清空已上传的文件列表(该方法不支持在before-upload中调用) | 无 |
abort | 取消上传请求 | (file: fileList中的file对象) |
submit | 手动上传文件列表 | 无 |
2. Upload上传例子
2.1. 使用脚手架新建一个名为element-ui-upload的前端项目, 同时安装Element插件。
2.2. 编写index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import UploadFunction from '../components/UploadFunction.vue'
import DragUpload from '../components/DragUpload.vue'
import ThumbnailUpload from '../components/ThumbnailUpload.vue'
import SubmitUpload from '../components/SubmitUpload.vue'
Vue.use(VueRouter)
const routes = [
{ path: '/', redirect: '/UploadFunction' },
{ path: '/UploadFunction', component: UploadFunction },
{ path: '/DragUpload', component: DragUpload },
{ path: '/ThumbnailUpload', component: ThumbnailUpload },
{ path: '/SubmitUpload', component: SubmitUpload }
]
const router = new VueRouter({
routes
})
export default router
2.3. 在components在新建UploadFunction.vue
<template>
<div>
<h1>点击上传</h1>
<h4>通过action设置上传的地址, 并且action必选参数。</h4>
<h4>通过file-list上传的文件列表, 默认是[]数组。</h4>
<h4>通过limit设置最大允许上传个数。</h4>
<h4>通过list-type设置文件列表的类型, 可以设置为text/picture/picture-card, 默认是text。</h4>
<h4>通过multiple设置是否支持多选文件。</h4>
<h4>通过show-file-list设置是否显示已上传文件列表, 默认为true。</h4>
<h4>通过accept设置接受上传的文件类型, 前端并没有绝对限制。</h4>
<h4>before-upload上传文件之前的钩子, 参数为上传的文件, 若返回false或者返回Promise且被reject, 则停止上传。</h4>
<h4>on-change文件状态改变时的钩子, 添加文件、上传成功和上传失败时都会被调用。</h4>
<h4>on-progress文件上传时的钩子。</h4>
<h4>on-success文件上传成功时的钩子。</h4>
<h4>on-error文件上传失败时的钩子。</h4>
<h4>on-preview点击文件列表中已上传的文件时的钩子。</h4>
<h4>before-remove删除文件之前的钩子, 参数为上传的文件和文件列表, 若返回false或者返回Promise且被reject, 则停止删除。</h4>
<h4>on-remove文件列表移除文件时的钩子。</h4>
<h4>on-exceed文件超出个数限制时的钩子。</h4>
<h4>通过slot你可以传入自定义的上传按钮类型和文字提示。</h4>
<el-upload :action="action2" :file-list="fileList" :limit="limit" list-type="text" multiple :show-file-list="true" accept=".png, .jpg"
:before-upload="handleBeforeUpload"
:on-change="handleChange"
:on-progress="handleProgress"
:on-success="handleSuccess"
:on-error="handleError"
:on-preview="handlePreview"
:before-remove="beforeRemove"
:on-remove="handleRemove"
:on-exceed="handleExceed">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件, 且不超过200MB。</div>
</el-upload>
</div>
</template>
<script>
export default {
data () {
return {
action1: 'http://localhost:8080/ElementUIUpload/EUpload.action',
action2: 'http://localhost:9876/upload',
fileList: [],
limit: 3
}
},
methods: {
handleBeforeUpload (file) {
console.log('---handleBeforeUpload---')
console.log(file)
},
handleChange (file, fileList) {
console.log('---handleChange---')
console.log(file)
console.log(fileList)
},
handleProgress (event, file, fileList) {
console.log('---handleProgress---')
console.log(event)
console.log(file)
console.log(fileList)
},
handleSuccess (response, file, fileList) {
console.log('---handleSuccess---')
console.log(response)
console.log(file)
console.log(fileList)
},
handleError (err, file, fileList) {
console.log('---handleError---')
console.log(err)
console.log(file)
console.log(fileList)
},
handlePreview (file) {
console.log('---handlePreview---')
console.log(file)
},
beforeRemove (file, fileList) {
console.log('---beforeRemove---')
console.log(file)
console.log(fileList)
return this.$confirm(`确定移除 ${file.name}?`)
},
handleRemove (file, fileList) {
console.log('---handleRemove---')
console.log(file)
console.log(fileList)
},
handleExceed (files, fileList) {
console.log('---handleExceed---')
console.log(files)
console.log(fileList)
this.$message.warning(`当前限制选择${this.limit}个文件, 本次选择了${files.length}个文件, 共选择了${files.length + fileList.length}个文件`)
}
}
}
</script>
2.4. 在components在新建DragUpload.vue
<template>
<div>
<h1>拖拽上传</h1>
<h4>通过drag设置是否启用拖拽上传。</h4>
<el-upload :action="action2" drag list-type="picture">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处, 或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传jpg/png文件, 且不超过200MB。</div>
</el-upload>
</div>
</template>
<script>
export default {
data () {
return {
action1: 'http://localhost:8080/ElementUIUpload/EUpload.action',
action2: 'http://localhost:9876/upload'
}
}
}
</script>
2.5. 在components在新建ThumbnailUpload.vue
<template>
<div>
<h1>文件缩略图</h1>
<h4>使用scoped-slot去设置缩略图模版。</h4>
<el-upload :action="action2" list-type="picture-card" ref="upload">
<i class="el-icon-plus"></i>
<div slot="file" slot-scope="{file}">
<img class="el-upload-list__item-thumbnail" :src="file.url" alt="">
<span class="el-upload-list__item-actions">
<span class="el-upload-list__item-preview" @click="handlePreview(file)"><i class="el-icon-zoom-in"></i></span>
<span class="el-upload-list__item-delete" @click="handleRemove(file)"><i class="el-icon-delete"></i></span>
</span>
</div>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
</div>
</template>
<script>
export default {
data () {
return {
action1: 'http://localhost:8080/ElementUIUpload/EUpload.action',
action2: 'http://localhost:9876/upload',
dialogImageUrl: '',
dialogVisible: false
}
},
methods: {
handlePreview (file) {
this.dialogImageUrl = file.url
this.dialogVisible = true
},
handleRemove (file) {
var uploadFiles = this.$refs.upload.uploadFiles
uploadFiles.filter(function (value, index, array) {
if (value.uid === file.uid) {
uploadFiles.splice(index, 1)
}
})
}
}
}
</script>
2.6. 在components在新建SubmitUpload.vue
<template>
<div>
<h1>手动上传</h1>
<h4>auto-upload是否在选取文件后立即进行上传。</h4>
<h4>trigger触发文件选择框的内容。</h4>
<el-upload ref="upload" :action="action2" :auto-upload="false">
<el-button slot="trigger" size="small" type="primary">选取文件</el-button>
<el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">上传到服务器</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件, 且不超过200MB。</div>
</el-upload>
</div>
</template>
<script>
export default {
data () {
return {
action1: 'http://localhost:8080/ElementUIUpload/EUpload.action',
action2: 'http://localhost:9876/upload'
}
},
methods: {
submitUpload () {
this.$refs.upload.submit()
}
}
}
</script>
3. Servlet上传文件服务器
3.1. 新建一个名为ElementUIUpload动态web服务器项目
3.2. 新建UFilter.java, 设置跨域访问
package com.bjbs;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class UFilter implements Filter {
@Override
public void init(FilterConfig config) throws ServletException {
System.out.println("在服务器加载项目的时候创建, 初始化。");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("进入到过滤器了, 可以进行过滤操作了。");
// 本过滤器放行, 你可以去下一个过滤器或者Servlet了
chain.doFilter(request, response);
HttpServletResponse res = (HttpServletResponse) response;
// 设置跨域访问
/* 允许跨域的主机地址 */
res.setHeader("Access-Control-Allow-Origin", "*");
/* 允许跨域的请求方法GET, POST, HEAD 等 */
res.setHeader("Access-Control-Allow-Methods", "*");
/* 重新预检验跨域的缓存时间 (s) */
res.setHeader("Access-Control-Max-Age", "4200");
/* 允许跨域的请求头 */
res.setHeader("Access-Control-Allow-Headers", "*");
/* 是否携带cookie */
res.setHeader("Access-Control-Allow-Credentials", "true");
}
@Override
public void destroy() {
System.out.println("服务器停止或者移除项目的时候的销毁。");
}
}
3.3. 新建EUpload.java上传文件
package com.bjbs;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;
public class EUpload extends HttpServlet {
private static final long serialVersionUID = 1L;
// 上传文件存储目录
private static final String UPLOAD_DIRECTORY = "upload";
// 上传配置
private static final int MEMORY_THRESHOLD = 1024 * 1024 * 3; // 3MB
private static final int MAX_FILE_SIZE = 1024 * 1024 * 40; // 40MB
private static final int MAX_REQUEST_SIZE = 1024 * 1024 * 50; // 50MB
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 检测是否为多媒体上传
if (!ServletFileUpload.isMultipartContent(req)) {
// 如果不是则停止
PrintWriter writer = resp.getWriter();
writer.println("Error: 表单必须包含 enctype=multipart/form-data");
writer.flush();
return;
}
// 配置上传参数
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置内存临界值 - 超过后将产生临时文件并存储于临时目录中
factory.setSizeThreshold(MEMORY_THRESHOLD);
// 设置临时存储目录
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
ServletFileUpload upload = new ServletFileUpload(factory);
// 设置最大文件上传值
upload.setFileSizeMax(MAX_FILE_SIZE);
// 设置最大请求值 (包含文件和表单数据)
upload.setSizeMax(MAX_REQUEST_SIZE);
// 中文处理
upload.setHeaderEncoding("UTF-8");
// 构造临时路径来存储上传的文件
// 这个路径相对当前应用的目录
String uploadPath = req.getServletContext().getRealPath("./") + File.separator + UPLOAD_DIRECTORY;
// 如果目录不存在则创建
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) {
uploadDir.mkdir();
}
String msg = "上传文件失败";
try {
// 解析请求的内容提取文件数据
List<FileItem> formItems = upload.parseRequest(new ServletRequestContext(req));
if (formItems != null && formItems.size() > 0) {
// 迭代表单数据
for (FileItem item : formItems) {
// 处理不在表单中的字段
if (!item.isFormField()) {
String fileName = new File(item.getName()).getName();
String filePath = uploadPath + File.separator + fileName;
File storeFile = new File(filePath);
// 在控制台输出文件的上传路径
System.out.println(filePath);
// 保存文件到硬盘
item.write(storeFile);
}
}
msg = "文件上传成功";
}
} catch (Exception ex) {
msg = ex.getMessage();
}
// 不管是字节流还是字符流, 直接使用一行代码就可以解决响应乱码问题。
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().print(msg);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
3.4. 在web.xml中, 配置过滤器和Servlet
3.5. 新建index.html, 使用vue和element-ui, 使用upload组件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>上传文件</title>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入Vue -->
<script src="https://lib.baomitu.com/vue/2.6.14/vue.common.dev.js"></script>
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
</head>
<body>
<div id="app">
<el-upload action="http://localhost:9876/upload" :file-list="fileList" :on-success="handleSuccess" :on-error="handleError">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
</div>
<script>
new Vue({
el: '#app',
data: {
fileList: []
},
methods: {
handleSuccess (response, file, fileList) {
console.log('---handleSuccess---')
console.log(response)
console.log(file)
console.log(fileList)
},
handleError (err, file, fileList) {
console.log('---handleError---')
console.log(err)
console.log(file)
console.log(fileList)
}
}
})
</script>
</body>
</html>
4. SpringBoot上传文件服务器
4.1. 新建一个名为element-upload-spring-boot的SpringBoot项目
4.2. 配置pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.13.RELEASE</version>
</parent>
<groupId>com.bjbs</groupId>
<artifactId>element-upload-spring-boot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<!-- 修改jdk版本 -->
<java.version>1.8</java.version>
<!-- 指定thymeleaf和thymeleaf-layout-dialect高版本可以防止html标签不规范报错 -->
<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>
</properties>
<dependencies>
<!-- springBoot的启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- thymeleaf的启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
</project>
4.3. 新建CorsConfig.java, 支持跨域访问
package com.bjbs.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT").maxAge(3600);
}
}
4.4. 新建UploadController.java
package com.bjbs.controller;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
@RestController
public class UploadController {
@RequestMapping(value="/upload")
public Map<String, Object> upload(HttpServletRequest req) {
Map<String, Object> map = new HashMap<String, Object>();
// 构造临时路径来存储上传的文件
// 这个路径相对当前应用的目录
String uploadPath = req.getServletContext().getRealPath("./") + File.separator + "upload";
// 如果目录不存在则创建
File file = new File(uploadPath);
if (!file.exists()) {
file.mkdir();
}
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) req;
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
for (Map.Entry<String, MultipartFile> entry : fileMap.entrySet()) {
MultipartFile multipartFile = entry.getValue();
String fileName = multipartFile.getOriginalFilename();
String filePath = uploadPath + File.separator + fileName;
try {
multipartFile.transferTo(new File(filePath));
map.put(fileName, filePath);
} catch (IllegalStateException | IOException e) {
e.printStackTrace();
map.put("msg", e.getMessage());
return map;
}
}
map.put("msg", "success");
return map;
}
}
4.5. 新建App.java
package com.bjbs;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
4.6. 在src/main/resources下, 配置application.properties
server.port=9876
#设置单个上传文件的大小
spring.http.multipart.maxFileSize=200MB
#设置一次请求上传文件的总容量
spring.http.multipart.maxRequestSize=1000MB
4.7. 在src/main/resources下, 新建static文件夹, 在static文件夹下新建index.html, 使用vue和element-ui, 使用upload组件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>上传文件</title>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入Vue -->
<script src="https://lib.baomitu.com/vue/2.6.14/vue.common.dev.js"></script>
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
</head>
<body>
<div id="app">
<el-upload action="http://localhost:9876/upload" :file-list="fileList" :on-success="handleSuccess" :on-error="handleError">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
</div>
<script>
new Vue({
el: '#app',
data: {
fileList: []
},
methods: {
handleSuccess (response, file, fileList) {
console.log('---handleSuccess---')
console.log(response)
console.log(file)
console.log(fileList)
},
handleError (err, file, fileList) {
console.log('---handleError---')
console.log(err)
console.log(file)
console.log(fileList)
}
}
})
</script>
</body>
</html>
5. 允许项目, 上传文件
5.1. 启动名为element-upload-spring-boot的SpringBoot项目
5.2. 启动前端element-ui-upload, 访问http://localhost:8080/#/UploadFunction, 上传图片
5.3. 前端访问http://localhost:8080/#/DragUpload, 拖拽上传图片
5.4. 前端访问http://localhost:8080/#/ThumbnailUpload, 上传图片查看大图
5.5. 前端访问http://localhost:8080/#/SubmitUpload, 手动上传图片