Java_实现上传功能
from表单上传
准备
-
前端通过form提交时
method = "post"
,且input属性中type = "file"。
-
在form中添加
enctype="multipart/form-data"
属性,如果没有设置enctype属性默认为enctype=application/x-www-form-urlencoder
(在发送前编码所有字符默认),这样浏览器是无法将文件自身传递到服务端。由于
enctype="multipart/form-data"
代表着浏览器你不使用字符编码,而使用上传专用的编码格式来获取上传的二进制乱码数据。原使用的request.getParameter("name")
无法获取传入的数据。
解决
导入fileupload解析request.getInpustream()。
commons-io.jar是一个处理io流的工具类,主要分为工具类、尾端类、行迭代器、文件过滤器、文件比较器和扩展流。
- commons-fileupload.jar
- commons-io.jar
//创建工厂类,可设置缓冲区以及临时文件目录
DiskFIleItemFactory fac = new DiskFIleItemFactory();
/**
*设置工厂的内存缓冲区大小,默认是10K
*factory.setSizeThreshold(1024*1024);
*设置工厂的临时文件目录:当上传文件的大小大于缓冲区大小时,将使用临时文件目录缓存上传的文件
*factory.setRepository(new File("f:\\cashe\\"));
*/
//创建文件上传解析类
ServletFileUpload upload = new ServletFileUpload(fac);
//使用解析类解析输入流对象
List<FileItem> list = upload.parseRequest(request);
通过request.getInputStream();
获得请求体的所有内容的输入流,将每对分割线的内容装到FileItem对象中。
API分析
1.DiskFileItemFactory
-
public void setSizeThreshold(int sizeThreshold) :设置内存缓冲区的大小,默认值为10K。当上传文件大于缓冲区大小时,fileupload组件将使用临时文件缓存上传文件。
-
public void setRepository(Java.io.File repository) :指定临时文件目录,取默认值找
System.getProperty("java.io.tmpdir");
。
2.ServletFileUpload
- setFileSizeMax(long fileSizeMax) :设置上传单个文件的最大值,,以防止客户端恶意上传超大文件来浪费服务器端的存储空间。其参数是以字节为单位的long型数字。
- setSizeMax(long sizeMax) :设置上传文件总量的最大值以防止客户端恶意上传超大文件来浪费服务器端的存储空间。
- boolean isMultipartContent(HttpServletRequest request) :判断上传表单是否为multipart/form-data类型。
- List parseRequest(HttpServletRequest request):解析request对象,并把表单中的每一个输入项包装成一个fileItem 对象,并返回一个保存了所有FileItem的list集合。
- setHeaderEncoding(java.lang.String encoding) :设置编码格式。在文件上传请求的消息体中,除了普通表单域的值是文本内容以外,文件上传字段中的文件路径名也是文本,在内存中保存的是它们的某种字符集编码的字节数组,Apache文件上传组件在读取这些内容时,必须知道它们所采用的字符集编码,才能将它们转换成正确的字符文本返回。
3.FileItem
- tring getName():用于获得文件上传字段中的文件名。注意IE或FireFox中获取的文件名是不一样的,IE中是绝对路径,FireFox中只是文件名。
- String getFieldName():返回表单标签name属性的值。
- boolean isFormField(): isFormField方法用于判断FileItem类对象封装的数据是一个普通文本表单字段,还是一个文件表单字段,如果是普通表单字段则返回true,否则返回false。
- String getString():将FileItem对象中保存的数据流内容以一个字符串返回,可获得上传字段的二进制数据。推荐使用输入流获取数据
- void write(File file):用于将FileItem对象中保存的主体内容保存到某个指定的文件中。如果FileItem对象中的主体内容是保存在某个临时文件中,该方法顺利完成后,临时文件有可能会被清除。该方法也可将普通表单字段内容写入到一个文件中,但它主要用途是将上传的文件内容保存在本地文件系统中。
- void delete():主动清空FileItem类对象中存放的主体内容
Ajax
- 方法一:引入jquery-form.js文件
方法二:不需要引入js文件,使用FromData方法
/**
* 使用FormData
*/
$("#ormdatasub").click(function(){
var formdata = new FormData($("#domeform")[0]);
$.ajax({
url: "/api/fileupload/dome1",
type: "POST",
data:formdata,
dataType: "json",
processData: false, // 告诉jQuery不要去处理发送的数据
contentType: false, // 告诉jQuery不要去设置Content-Type请求头
success: function (res) {
}
})
})
后台使用MultipartFile 类接收前台传过来的文件。MultipartFile 可以完成file与的互换
/**
* MultipartFile 转 File
* @param file
* @throws Exception
*/
public static void multipartFileToFile( @RequestParam MultipartFile file ) throws Exception {
File toFile = null;
if(file.equals("")||file.getSize()<=0){
file = null;
}else {
InputStream ins = null;
ins = file.getInputStream();
toFile = new File(file.getOriginalFilename());
inputStreamToFile(ins, toFile);
ins.close();
}
}
/**
* File 转 MultipartFile
* @param file
* @throws Exception
*/
public static void fileToMultipartFile( File file ) throws Exception {
FileInputStream fileInput = new FileInputStream(file);
MultipartFile toMultipartFile = new MockMultipartFile("file",file.getName(),"text/plain", IOUtils.toByteArray(fileInput));
toMultipartFile.getInputStream();
}
/**
*流转file
*
*/
public static void inputStreamToFile(InputStream ins, File file) {
try {
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
} catch (Exception e) {
e.printStackTrace();
}
}
注意事项
- 在后台需要进行文件类型、大小、来源等验证保证文件的安全。
- 将上传后的文件生成一个随机的文件名,并且加上此前生成的文件扩展名。或是设置多层嵌套文件夹的方式。
- 设置上传目录执行权限为只可上传文件但不能执行文件,避免不怀好意的人绕过如图片扩展名进行恶意攻击,拒绝脚本执行的可能性。