上传文件时,通常是修改表单为:enctype="multipart/form-data"
因此我敲了一个方法,支持多文件上传。
处理结果是返回一个Map集合,如果有错误,会包含key为errorMsg的错误信息,如果获取到的errorMsg为空,则直接按字段获取上传文件的文件URL即可。
为了文件保存位置的灵活性,代码中会先去读取类路径下的path.properties属性文件,如果其中有filePath属性的话,则将文件保存到该路径下,如果没有,则默认保存到项目中根目录下。具体看代码,都有注释。
本次采用的是SpringBoot,为了使得方法适应多种环境,我也在SpringMVC下测试过,是没问题的。
其中有部分代码,是为了兼容SpringBoot和SpringMVC框架而添加的,其实就是一些条件判断,根据不同条件,去执行不同的代码。
比如:
- 方法一开始的,直接将request进行强转,在SpringBoot中是可以的,但如果放到SpringMVC中就不行了。因为SpringBoot在请求进入Controller之前会先把request解析成MultipartHttpServletRequest类型,因此才可以直接强转。而SpringMVC没有做这个操作,因此需要我们先手动进行解析成MultipartHttpServletRequest类型。
- 另外,根据前端发送的表单数据是否包含有上传文件,有下面几种情况:
- SSM框架嵌入Swagger框架:如果在Swagger可视化页面发出的附带有上传文件的请求,那么将request解析为MultipartHttpServletRequest类型的时候,不会报错。
- SSM框架嵌入Swagger框架:如果在Swagger可视化页面发出的请求,虽然表单中有file文件,但没有选择上传,那么此时swagger是不会添加enctype="multipart/form-data"属性的,因此如果直接在该方法中进行解析,则会报错该request不包含有上传文件。因此才会先进行判断是否包含有上传文件,再决定是否进行解析request。
- SSM框架,前端jsp页面发送请求,由于表单设置了enctype="multipart/form-data"属性,因此不管有没有上传文件,只要提交了请求,解析request的时候都不会报错。
- 总结:需要注意的是,当swagger页面进行测试接口时,如果参数(表单中)有file类型的字段,还要考虑到有没有选择文件进行上传的情况。因为Swagger发送的请求很奇怪,如果请求携带了file类型的文件,那么解析request的时候不会出问题;如果表单中有file类型的字段,但没有选择上传文件,即发送请求携带的参数都是普通表单项,那么此时解析request为MultipartHttpServletRequest类型,则会报错。因此方法中才特意不厌其烦的做了判断,可以直接测试。我觉得有必要把判断的原因表述一下,方便大家理解代码含义。
依赖:
<build>
<plugins>
<!-- 设置项目的编译版本为本地jdk的版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<!-- 配置编译的默认编码类型为utf-8 -->
<configuration>
<target>1.8</target>
<source>1.8</source>
<encoding>utf-8</encoding>
</configuration>
</plugin>
<!-- 启动maven的内置tomcat7服务器 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
</plugin>
</plugins>
</build>
<!-- 导入SpringBoot的父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
</parent>
<dependencies>
<!-- 导入web组件启动器,版本随父工程 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 导入SpringBoot整合mybatis的组件启动器 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<!-- 导入SpringBoot中的test组件启动器,版本随父工程 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- 导入mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<!-- 导入servlet-api依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- 导入jsp-api依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<!-- 对jsp的支持的依赖 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- 导入jstl标签库 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- jackson,用于RESTful风格的请求url
其中jackson-databind是主要,其他会作为辅助依赖自动加入-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.13</version>
</dependency>
<!-- IO流 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.2</version>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
工具类:
package com.wnkj.utils;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* 自制工具类
*/
public class CommonTools {
// 使用日记工厂获得日记对象
private static Log log = LogFactory.getLog(CommonTools.class);
// 文件上传大小,最大不能超过5M
private static final int UPLOAD_FILE_MAX_SIZE = 5 * 1024 * 1024;
/**
* 便捷将Map集合中的数据封装到JavaBean中,字段必须对应!!!
* @param map
* @param c
* @param <T>
* @return
*/
public static <T> T mapToBean(Map<String, Object> map, Class<T> c) {
try {
// 创建字节码文件的一个实例
T bean = c.newInstance();
// 利用BeanUtils工具类将map集合中的数据封装到bean实例中
BeanUtils.populate(bean, map);
// 返回实例
return bean;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 批量处理request中的普通表单项和文件表单项,并返回一个Map集合
* 该Map集合存储有所有请求参数的值,包括上传文件最终保存文件的文件URL
* @param request
* @return
* @throws Exception
*/
public static Map<String, Object> uploadFile(HttpServletRequest request) throws Exception {
log.debug("<<<<<<<<<<<<-------文件上传:开始------->>>>>>>>>>>>");
// 创建Map集合用于存储结果集或错误信息
Map<String, Object> resultMap = new HashMap<String, Object>();
// 定义MultipartHttpServletRequest类型变量
MultipartHttpServletRequest multipartHttpServletRequest = null;
/*
判断传递进来的参数request是不是属于MultipartHttpServletRequest类型
判断原因:
1. SpringBoot中,请求在进入Controller之前,
会自动在过滤器中将HttpServletRequest类型的request解析成MultipartHttpServletRequest类型;
2. SpringMVC中,则不会自动解析,
因此为了使得当前方法适应SpringBoot和SpringMVC的文件上传,则进行判断操作。
*/
if (request instanceof MultipartHttpServletRequest) {
// 如果是,则直接将HttpServletRequest类型的request强制转换为MultipartHttpServletRequest类型
multipartHttpServletRequest = (MultipartHttpServletRequest) request;
} else {
// 如果不是,创建CommonsMultipartResolver类型解析器
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
/*
判断当前request是不是enctype="multipart/form-data"
判断原因:为了兼容Swagger页面发送请求和前端页面发送请求。
1. 如果是Swagger页面发送的请求,有文件表单项,但没有选择文件上传
那么该request判断的时候,不是enctype="multipart/form-data"类型;
2. 如果是前端页面发送请求,因为设置了enctype="multipart/form-data"类型,
所以该request是enctype="multipart/form-data"类型
*/
boolean flag = commonsMultipartResolver.isMultipart(request);
if (flag) {
// 解析HttpServletRequest类型的request为MultipartHttpServletRequest类型
multipartHttpServletRequest = commonsMultipartResolver.resolveMultipart(request);
}
}
// 如果multipartHttpServletRequest等于null,说明request中不包含上传文件
if (multipartHttpServletRequest == null) {
System.out.println("multipartHttpServletRequest == null");
// 保存所有普通表单项的请求参数和参数值
resultMap.putAll(CommonTools.getParameterMap(request));
// 返回结果集
return resultMap;
}
// 保存所有普通表单项的请求参数和参数值
resultMap.putAll(CommonTools.getParameterMap(multipartHttpServletRequest));
// 得到存储有所有MultipartFile文件的Map集合
Map<String, MultipartFile> multipartFileMap = multipartHttpServletRequest.getFileMap();
System.out.println("multipartFileMap.size() = " + multipartFileMap.size());
// 得到存储有MultipartFile文件的Set集合
Set<Map.Entry<String, MultipartFile>> set = multipartFileMap.entrySet();
// 循环遍历得到每一个Entry
for (Map.Entry<String, MultipartFile> entry : set) {
// 得到每一个MultipartFile对象
MultipartFile multipartFile = entry.getValue();
// 得到文件表单项的name属性的值
String formFileName = multipartFile.getName();
log.debug("当前上传的文件表单项的name属性值为----->>>>>" + formFileName);
// 得到上传文件的原文件名称
String originalFileName = multipartFile.getOriginalFilename();
// 如果上传文件的原文件名称为空,说明没上传文件
if (CommonTools.isEmpty(originalFileName)) {
// 保存对应name属性的属性值为null
resultMap.put(formFileName, null);
// 进入下一次循环
continue;
}
// 得到multipartFile文件的大小
long fileSize = multipartFile.getSize();
log.debug("当前上传的文件表单项的大小为----->>>>>" + fileSize);
// 如果超出限定大小,则返回错误信息
if (fileSize > CommonTools.UPLOAD_FILE_MAX_SIZE) {
log.debug("<<<<<-----错误:上传的文件大小超过5M----->>>>>");
log.debug("<<<<<<<<<<<<-------文件上传:结束------->>>>>>>>>>>>");
resultMap.put("errorMsg", "单个文件表单项大小不得超过5M!(" + formFileName + ")已超过5M!");
return resultMap;
}
// 定义字符串存储文件后缀
String uploadFileSuffix = null;
// 定义字符串存储上传文件类型标记
String uploadFileTypeMark = null;
// 得到上传文件的后缀及文件类型
Map<String, Object> getFileSuffixAndFileType_Map = CommonTools.getFileSuffixAndFileType(originalFileName);
// 获取错误信息
String errorMsg = (String) getFileSuffixAndFileType_Map.get("errorMsg");
// 如果错误信息不等于空
if (CommonTools.notEmpty(errorMsg)) {
log.debug("<<<<<-----错误:" + errorMsg + "----->>>>>");
log.debug("<<<<<<<<<<<<-------文件上传:结束------->>>>>>>>>>>>");
resultMap.put("errorMsg", errorMsg);
return resultMap;
}
// 得到上传文件的后缀
uploadFileSuffix = (String) getFileSuffixAndFileType_Map.get("uploadFileSuffix");
log.debug("当前上传的原文件后缀为----->>>>>" + uploadFileSuffix);
// 得到上传文件的类型
uploadFileTypeMark = (String) getFileSuffixAndFileType_Map.get("uploadFileTypeMark");
log.debug("当前上传的原文件类型为----->>>>>" + uploadFileTypeMark);
// 定义上传文件的文件类型目录
String uploadFileTypeDir = null;
// 如果等于image表示是图片
if ("image".equals(uploadFileTypeMark)) {
uploadFileTypeDir = "uploadImages";
} else { // 否则表示其他类型的文件
uploadFileTypeDir = "uploadFiles";
}
// 得到保存文件的前缀路径
String saveUploadFilePrefixDirectory = CommonTools.saveUploadFilePrefixDirectory(request, uploadFileTypeDir);
// 定义保存文件的日期目录
String saveUploadFileDateDirectory = CommonTools.date2Str(new Date(), "yyyyMMdd");
// 得到保存文件的完整目录
File saveUploadFileCompleteDirectory_File = new File(saveUploadFilePrefixDirectory, saveUploadFileDateDirectory);
// 如果目录不存在的话
if (! saveUploadFileCompleteDirectory_File.exists()) {
saveUploadFileCompleteDirectory_File.mkdirs();
}
log.debug("保存文件的路径为----->>>>>" + saveUploadFileCompleteDirectory_File.getPath());
// 定义保存文件的文件名称,带后缀
String saveUploadFileName = CommonTools.get32UUID() + uploadFileSuffix;
log.debug("保存文件的文件名称为----->>>>>" + saveUploadFileName);
// 得到保存文件的最终File类型对象
File saveFile = new File(saveUploadFileCompleteDirectory_File, saveUploadFileName);
log.debug("保存文件的完整路径为----->>>>>" + saveFile.getPath());
// 读取输入流中的文件,并通过输出流保存
CommonTools.inputReadAndOutputWrite(multipartFile, saveFile);
// 保存上传文件最终保存的文件URL到map集合中
resultMap.put(formFileName, saveUploadFileDateDirectory + "/" + saveUploadFileName);
}
log.debug("<<<<<<<<<<<<-------文件上传:结束------->>>>>>>>>>>>");
return resultMap;
}
/**
* 读取输入流,并通过输出流写出
* @param multipartFile
* @param file
* @throws Exception
*/
public static void inputReadAndOutputWrite(MultipartFile multipartFile, File file) throws Exception {
// 定义资源输入流用于读取multipartFile对象中的文件输入流
InputStream uploadFileInput = null;
// 定义资源输出流,用于将文件输入流写出
OutputStream saveUploadFileOutput = null;
try {
// 得到MultipartFile类型的multipartFile对象中的文件输入流
uploadFileInput = multipartFile.getInputStream();
// 关联最终保存文件的File类型对象
saveUploadFileOutput = new FileOutputStream(file);
// 定义字节数组,用作缓冲区
byte[] buf = new byte[1024];
// 定义int变量记录每次读取到字节数组中的有效长度
int len = 0;
// 循环读取
while ((len = uploadFileInput.read(buf)) != -1) {
// 写操作
saveUploadFileOutput.write(buf, 0, len);
}
// 刷新
saveUploadFileOutput.flush();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (uploadFileInput != null) {
uploadFileInput.close();
}
if (saveUploadFileOutput != null) {
saveUploadFileOutput.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 得到用于保存上传文件的前缀路径
* @param request
* @param uploadFileTypeDir
* @return
* @throws Exception
*/
public static String saveUploadFilePrefixDirectory(HttpServletRequest request, String uploadFileTypeDir) throws Exception {
// 定义资源输入流,专门用于读取path.properties属性文件
InputStream pathPropertiesInput = null;
// 定义用于保存文件的前缀路径
String saveUploadFilePrefixDirectory = null;
try {
// 读取类路径下的path.properties属性文件
pathPropertiesInput = CommonTools.class.getClassLoader().getResourceAsStream("path.properties");
// 如果资源输入流不为空
if (pathPropertiesInput != null) {
// 定义Properties集合用于读取路径资源输入流
Properties props = new Properties();
// 把资源输入流中的属性加载到Properties集合中
props.load(pathPropertiesInput);
// 如果Properties集合的长度大于0
if (props.size() > 0) {
// 获取其中的filePath属性的值
String filePath = props.getProperty("filePath");
// 如果filePath属性的值不为空
if (CommonTools.notEmpty(filePath)) {
// 判断filePath属性的值最后一个字符是否等于 "/"
if (filePath.lastIndexOf("/") == (filePath.length() - 1)) {
saveUploadFilePrefixDirectory = filePath + uploadFileTypeDir + "/";
} else {
saveUploadFilePrefixDirectory = filePath + "/" + uploadFileTypeDir + "/";
}
} else {
saveUploadFilePrefixDirectory = request.getServletContext().getRealPath("/upload/" + uploadFileTypeDir + "/");
}
} else {
saveUploadFilePrefixDirectory = request.getServletContext().getRealPath("/upload/" + uploadFileTypeDir + "/");
}
} else {
saveUploadFilePrefixDirectory = request.getServletContext().getRealPath("/upload/" + uploadFileTypeDir + "/");
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
try {
if (pathPropertiesInput != null) {
pathPropertiesInput.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return saveUploadFilePrefixDirectory;
}
/**
* 得到HttpServletRequest类型的request中的请求参数,
* 并存储为Map<String, Object>类型,返回结果集
* @param request
* @return
*/
public static Map<String, Object> getParameterMap(ServletRequest request) throws Exception {
Map<String, Object> resultMap = new HashMap<String, Object>();
// 得到存储有所有普通表单项的请求参数Map集合
Map<String, String[]> paramsMap = request.getParameterMap();
System.out.println("paramsMap.size() = " + paramsMap.size());
// 得到存储有普通表单项的请求参数的Set集合
Set<Map.Entry<String, String[]>> paramsSet = paramsMap.entrySet();
// 循环遍历得到每一个Entry
for (Map.Entry<String, String[]> entry : paramsSet) {
// 得到请求参数的参数名称
String paramKey = entry.getKey();
// 得到请求参数的参数值(String数组)
String[] paramValues = entry.getValue();
/*
创建字符串缓冲区
注:StringBuffer与StringBuilder功能和方法相同
1. StringBuffer是线程安全的,但效率相对较慢;
2. StringBuilder是线程不安全的,但效率相对较快。
*/
StringBuilder sb = new StringBuilder();
// 判断请求参数的参数值,即String数组长度是否等于1
if (paramValues.length == 1) {
// 保存到字符串缓冲区
sb.append(paramValues[0]);
} else {
// 循环遍历
for (int i = 0; i < paramValues.length; i++) {
// 保存到字符串缓冲区
sb.append(paramValues[i]);
// 如果当前循环遍历的索引号不等于数组长度-1
if (i != (paramValues.length - 1)) {
// 则说明不是最后一个参数值,用逗号隔开
sb.append(",");
}
}
}
// 调用StringBuffer的toString()方法得到一串字符串
String paramValue = sb.toString();
// 用请求参数名称为key,请求参数的值为value保存到Map中
resultMap.put(paramKey, paramValue);
System.out.println(paramKey + "::" + paramValue + "=======================");
}
return resultMap;
}
/**
* 根据上传的文件判断文件所属类型及返回文件后缀
* 文件所属类型:图片或其他
* @param fileName
* @return
* @throws Exception
*/
public static Map<String, Object> getFileSuffixAndFileType(String fileName) throws Exception {
Map<String, Object> resultMap = new HashMap<String, Object>();
if (fileName == null || "".equals(fileName) || fileName.trim().isEmpty()) {
resultMap.put("errorMsg", "参数不能为空!");
return resultMap;
}
int index = fileName.lastIndexOf(".");
String uploadFileSuffix = null;
if (index != -1) {
uploadFileSuffix = fileName.substring(index);
} else {
resultMap.put("errorMsg", "该参数不属于文件类型(没有带扩展名)!");
return resultMap;
}
String uploadFileTypeMark = null;
if (".jpeg".equals(uploadFileSuffix) || ".jpg".equals(uploadFileSuffix)
|| ".png".equals(uploadFileSuffix) || ".gif".equals(uploadFileSuffix)) {
uploadFileTypeMark = "image";
} else {
uploadFileTypeMark = "other";
}
resultMap.put("uploadFileSuffix", uploadFileSuffix);
resultMap.put("uploadFileTypeMark", uploadFileTypeMark);
return resultMap;
}
/**
* 删除文件或文件夹
* @param file
*/
public static void deleteFile(File file) {
// 判断文件是否存在
if(! file.exists()) {
throw new RuntimeException("异常:路径对应的文件不存在!");
}
// 判断file是不是文件夹类型
if(file.isDirectory()) {
// 得到文件夹下面的所有文件夹及文件的File对象
File[] files = file.listFiles();
// 循环遍历每个File
for(int i = 0; i < files.length; i++) {
// 递归
deleteFile(files[i]);
}
// 删除文件夹
file.delete();
} else { // 如果不是则表示属于文件
// 得到当前文件的父目录
File parentFile = file.getParentFile();
// 得到所有的子文件
File[] childFiles = parentFile.listFiles();
// 判断父目录下的子文件个数是否等于1
if(childFiles.length == 1) {
// 删除子文件
file.delete();
// 删除父目录
parentFile.delete();
} else {
// 否则说明父目录仍有多个子文件,所以直接删除文件即可
file.delete();
}
}
}
/**
* 按照yyyy-MM-dd HH:mm:ss的默认格式,将日期格式化为字符串
* @param date
* @return
*/
public static String date2Str(Date date) {
return date2Str(date, "yyyy-MM-dd HH:mm:ss");
}
/**
* 按照参数format的格式,将日期格式化为字符串
* @param date
* @param format
* @return
*/
public static String date2Str(Date date, String format) {
if(date != null) {
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.format(date);
} else {
return "";
}
}
/**
* 得到32位随机字符的ID
* @return
*/
public static String get32UUID() {
return UUID.randomUUID().toString().replace("-", "").toUpperCase();
}
/**
* 判断字符串是否为空
* @param text
* @return
*/
public static boolean isEmpty(String text) {
return text == null || "".equals(text) || text.trim().isEmpty();
}
/**
* 判断字符串是否不为空
* @param text
* @return
*/
public static boolean notEmpty(String text) {
return text != null && !"".equals(text) && !text.trim().isEmpty();
}
}
测试:
Controller类:
package com.wnkj.web.controller;
import com.wnkj.utils.CommonTools;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* 用户模块的Controller类
*/
@RestController
@RequestMapping(value = "/user")
public class UserController {
/**
* 新增用户
* @param
* @return
* @throws Exception
*/
@RequestMapping(value = "/save", method = RequestMethod.POST)
public String save(HttpServletRequest request) throws Exception {
System.out.println("username = " + request.getParameter("username"));
System.out.println("password = " + request.getParameter("password"));
Map<String, Object> map = CommonTools.uploadFile(request);
String errorMsg = (String) map.get("errorMsg");
if (errorMsg != null) {
return errorMsg;
}
String idCard = (String) map.get("idCard");
System.out.println("idCard = " + idCard);
String picture = (String) map.get("picture");
System.out.println("picture = " + picture);
return "success";
}
}
jsp页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<html>
<head>
<title>test</title>
<script type="text/javascript" src="<%=basePath%>static/js/jquery-3.4.1.min.js"></script>
</head>
<body>
<!-- 使用post表单提交,设置类型为:multipart/form-data -->
<form action="<%=basePath%>user/save" method="post" enctype="multipart/form-data">
<h2>基本form表单上传文件</h2>
username:<input type="text" name="username" /><br/>
password:<input type="text" name="password" /><br/>
idCard:<input type="file" name="idCard" /><br/>
picture:<input type="file" name="picture" /><br/>
<input type="submit" value="Register" />
</form>
<hr/>
<!-- Ajax提交表单数据 -->
<div>
<h2>Ajax提交表单数据</h2>
username:<input type="text" name="username" id="username" /><br/>
password:<input type="text" name="password" id="password" /><br/>
idCard:<input type="file" name="idCard" id="idCard" /><br/>
picture:<input type="file" name="picture" id="picture" /><br/>
<button onclick="save()">Register</button>
</div>
</body>
<script type="text/javascript">
function save() {
var username = $("#username").val();
console.log("username = " + username);
var password = $("#password").val();
console.log("password = " + password);
var idCard = $("#idCard")[0].files[0];
console.log("idCard = " + idCard);
var picture = $("#picture")[0].files[0];
console.log("picture = " + picture);
var form = new FormData();
form.append("username", username);
form.append("password", password);
form.append("idCard", idCard);
form.append("picture", picture);
$.ajax({
type : 'POST',
url : '<%=basePath%>user/save',
data : form,
contentType : false,
processData : false,
mimeType : 'multipart/form-data',
success : function(result) {
console.log(result);
}
})
}
</script>
</html>
结果:
测试form表单提交:
发送请求,控制台:
我的path.properties中filePath属性为:/wnkj/tomcat/
这个路径主要用于linux上,但我的IDEA在D盘,所以如果是这个路径,他会去D盘下创建对应的目录来存储,验证:
测试ajax提交:
发送请求,查看控制台:
再查看浏览器的控制台:
最后再查看文件保存路径下的文件:
建议在理解代码的基础上进行套用!如果有什么问题的,可以一起讨论!