目录
二、使用upload的http-request属性,覆盖默认的上传行为,自定义上传的实现
这里主要讲表单与文件(图片)的上传提交
一、使用upload的data属性携带表单数据提交
1、表单文本跟图片一起提交
这种情况下,账号昵称这些数据在表单,而加号的地方是upload组件,要上传的是图片,直接提交表单是无法将文件一起提交的。但是upload有一个参数data,如下图
我们可以将表单数据绑定到upload,使用upload的提交方法携带表单数据一起提交。
//以下是upload组件部分
<el-upload
ref="upload" //注册组件信息不可少
class="avatar-uploader"
action="http://localhost:8085/Test/cou" //提交的接口
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
:data="addCourseForm" //addCourseForm为表单数据
:auto-upload="false"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar" />
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
//js部分,只需在函数中执行下面语句即可提交
this.$refs.upload.submit();
表单跟图片一起提交的实现大概就这样。但是又有新的问题,当只提交表单不上传文件时,使用upload的submit()提交不成功,测试后发现连请求都不会发出。原因还是在上面图片,官方文档写的很清楚了,data绑定的数据是文件上传的额外携带的参数,没有选择文件当然不会发出请求。
2、只提交表单,不上传图片
这种情况下,我们需要判断upload选择的图片数量,如果没有选择图片的话,使用常规的方式发起axios请求。
edit() {
// 判断选择的文件数量
if (this.$refs.upload.uploadFiles.length === 0) {
let url = `http://localhost:8080/worryFree/CourseController/updateCourse`;
this.$http
.post(url, this.editCourseForm)
.then((res) => {
console.log(res);
if (res.data.status === 205) {
this.$message.success("修改成功!");
//关闭对话框
this.editCourseVisible = false;
this.$message.success("修改成功!");
//刷新课程列表
this.getCourseList();
}
})
.catch((error) => {
console.log(error);
this.$message("网络异常");
});
} else {
this.$refs.upload.submit();
//关闭对话框
this.editCourseVisible = false;
this.$message.success("修改成功!");
//刷新课程列表
this.getCourseList();
}
},
3、后端接口的处理
当然了,我们的后端接口肯定也要分情况处理,以下是代码
在这个类中,我将相关代码封装了一下。除了处理文件的上传,还用反射生成对象并注入属性值,用原生java写的,还是封装一些工具类比较方便。
package com.util;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class UploadUtil {
/**
* @param //
* @return
* @paramType
* @Description 描述: 处理图片上传
* @Author 李闪闪
* @Date 2021/11/6 14:55
*/
public static Map<String, String> upFile(HttpServletRequest req) throws Exception {
//判断是否有上传文件
if (ServletFileUpload.isMultipartContent(req)) {
Map<String, String> map = new HashMap<>();
DiskFileItemFactory fif = new DiskFileItemFactory();
//设置文件缓冲区大小为4M
fif.setSizeThreshold(1024 * 1024 * 4);
//当上传文件超过缓冲区大小时,启用临时文件夹进行缓存(暂存)
fif.setRepository(new File(req.getSession().getServletContext().getRealPath("/") + "tem"));
ServletFileUpload upload = new ServletFileUpload(fif);
//设置上传的单个文件的最大值是4M
upload.setSizeMax(1024 * 1024 * 4);
//解决中文路径或者文件名乱码问题
upload.setHeaderEncoding("UTF-8");
List<FileItem> items = upload.parseRequest(req);
//System.out.println("列表"+items);
Iterator<FileItem> it = items.iterator();
while (it.hasNext()) {
FileItem item = it.next();
//1. 文本域
if (item.isFormField()) {
//TODO:
String name = item.getFieldName();
//字段值是中文,以utf-8获取
String value = item.getString("utf-8");
map.put(name, value);
}
//2. 文件域
else {
// 判断上传的文件是否是图片;非空则说明是图片
if (ImageIO.read(item.getInputStream()) != null) {
String fileName = item.getName();
if (fileName == null) {
throw new Exception();
}
String[] split = fileName.split("\\.");
String lastName = split[1];
String newName = UUIDUtil.getUUID() + "." + lastName;
// 设置文件上传路径(获取真实物理路径)
File file = new File(req.getSession().getServletContext().getRealPath("/") + "img", newName);
item.write(file);
map.put("images", newName);
} else {
System.out.println("非图片!");
}
}
}
return map;
}
return null;
}
/**
* @param //[map, obj]
* @return java.lang.Object
* @paramType [java.util.Map<java.lang.String, java.lang.String>, java.lang.Class<?>]
* @Description 描述: 获取请求中的文本域和文件名,利用反射自动注入对象
* @Author 李闪闪
* @Date 2021/11/6 14:41
*/
public static Object reObj(Map<String, String> map, Class<?> obj) {
Object o = null;
try {
o = obj.newInstance();
Field[] fields = obj.getDeclaredFields();
for (Map.Entry<String, String> str : map.entrySet()) {
for (Field field : fields) {
//允许通过反射访问该字段
field.setAccessible(true);
String name = field.getName();
if (name.equals(str.getKey())) {
if (int.class == field.getType()) {
field.set(o, Integer.parseInt(str.getValue()));
} else if (long.class == field.getType()) {
field.set(o, Long.parseLong(str.getValue()));
} else if (double.class == field.getType()) {
field.set(o, Double.parseDouble(str.getValue()));
} else {
field.set(o, str.getValue());
}
}
}
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return o;
}
/**
* @param //[req, obj]
* @return java.lang.Object
* @paramType [javax.servlet.http.HttpServletRequest, java.lang.Class<?>]
* @Description 描述: 没有文件时自动获取请求中的参数,注入对象
* @Author 李闪闪
* @Date 2021/11/6 15:13
*/
public static Object reObj(HttpServletRequest req, Class<?> obj) throws InstantiationException,
IllegalAccessException {
Object o = obj.newInstance();
Field[] fields = obj.getDeclaredFields();
for (Field field : fields) {
//允许通过反射访问该字段
field.setAccessible(true);
String name = field.getName();
String param = req.getParameter(name);
if (param != null) {
if (int.class == field.getType()) {
field.set(o, Integer.parseInt(param));
} else if (long.class == field.getType()) {
field.set(o, Long.parseLong(param));
} else if (double.class == field.getType()) {
field.set(o, Double.parseDouble(param));
} else {
field.set(o, param);
}
}
}
return o;
}
以下是我的使用方式,贴出来的只是servlet的一个方法:
/**
* @paramType [javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse]
* @param //[req, resp]
* @return void
* @Description 描述: 添加sku
* @Author 李闪闪
* @Date 2021/11/6 16:13
*/
public void addSku(HttpServletRequest req, HttpServletResponse resp) {
try {
req.setCharacterEncoding("utf-8");
Skus skus = null;
//进入处理文件的方法
Map<String, String> map = UploadUtil.upFile(req);
if (map != null){
//map不为空,则有文件上传
skus = (Skus) UploadUtil.reObj(map, Skus.class);
}else{
//只有表单数据时,直接传入req生成对象,需要注意的是,不管是map中的key还是req中的参数名都应该与实体类属性名一样,否则映射不成功,自然也就无法正确注入属性值
skus = (Skus) UploadUtil.reObj(req,Skus.class);
}
skus.setDate(DateCaseUtil.dateToStr());
skuService.createSkus(skus);
ReMessTo.toRespone(resp,ResponseDataUtil.buildCreate("添加成功"));
} catch (Exception e) {
e.printStackTrace();
ReMessTo.toRespone(resp,ResponseDataUtil.buildError("添加失败"));
}
}
二、使用upload的http-request属性,覆盖默认的上传行为,自定义上传的实现
这种方式是后来在朋友的启示下发现的,我一开始并不知道http-request是这样用的,http-request
指向的函数会有一个element 的默认回调参数
定义为param
这种方式 正好跟上面用data的方式相反,data是upload携带表单数据,http-request则大概可以理解为将upload的文件数据提取出来,添加到表单数据中。
<el-upload class="upload-demo" drag action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList"
:http-request="getFile" :multiple="false">
<i class="el-icon-upload"></i>
<div class="el-upload__text">
<p style="margin:0px;">点击上传</p>
<p style="margin-top:0px;color: rgba(28,31,35,0.8); font-weight: 500;text-align: center;">
或直接将文件拖入此区域</p>
</div>
</el-upload>
getFile(item) {
this.file = item.file;
},
addVideo() {
//FormData对象,它的api文档在这里:https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/FormData
const fd = new FormData()
//以下是我的其他表单数据
fd.append('uid ', this.uid);
fd.append('title ', this.title);
fd.append('vtype ', this.vtype);
//将文件数据添加进FormData对象
fd.append('filename', this.file);
//设置请求头
const config = { headers: {'Content-Type': 'multipart/form-data'} };
let url = `http://localhost:8088/upload/addVideo
this.$http.post(url,fd,config).then(res => {
console.log(res.data.data);
});
}
这种方式比上面的简单多了,还是这种好。
后端接口代码跟上面大体相似,代码还有很大的优化空间。
水平有限,主要是记录一下自己的成长,有什么错误的烦请大佬们指正。