一般表单的enctype属性默认值为application/x-www-form-urlencoded,不具备上传文件的功能,所以要改为:multipart/form-data,并且只能用post方式提交。这个过程中将编码方式改为了MIME,它将普通参数和上传的附件一块发送给服务端,再用request的getParameter方法获取参数就失效了。
一、手动上传方式
Jsp页面写法
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form method="post" action="${pageContext.request.contextPath}/MoudleFileUpload" enctype="multipart/form-data">
<table>
<caption>文件上传</caption>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"/></td>
</tr>
<tr>
<td>文件:</td>
<td><input type="file" name="file"/></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="submit"/></td>
</tr>
</table>
</form>
</body>
</html>
Servlet写法
package com.hncj.test;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/NormalUpload")
public class NormalUpload extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//String username = request.getParameter("username"); 返回null
ServletInputStream is = request.getInputStream();
int len = 0;
byte[]arr = new byte[1024];
while((len = is.read(arr))>0) {
System.out.println(new String(arr,0,len));
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
测试结果中,不仅包含了输入的用户名信息,还包含文件内容。
这种方法的弊端:存在文件名乱码问题,提交的普通参数和文件不好分离......
二、组件方式
需要使用Apache的两个jar包:commons-fileupload-1.3.3.jar commons-io-2.6.jar
可以在官网下载:Apache
代码如下:
package com.hncj.test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
@WebServlet("/MoudleFileUpload")
public class MoudleFileUpload extends HttpServlet{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String storePath = this.getServletContext().getRealPath("/WEB-INF/store");
String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
File store = new File(storePath);
File temp = new File(tempPath);
if(!store.exists()) {
store.mkdir();
}
if(!temp.exists()) {
temp.mkdir();
}
//创建文件工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
//设置缓冲文件存储路径
factory.setRepository(temp);
//设置文件的大小限制
factory.setSizeThreshold(30*1024*1024);
//创建文件上传类
ServletFileUpload upload = new ServletFileUpload(factory);
//解决文件名乱码问题
upload.setHeaderEncoding("UTF-8");
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long pBytesRead, long pContentLength, int pupload) {
System.out.println("文件总大小:"+pContentLength+"字节 你已经上传:"+pBytesRead);
}
});
if(!upload.isMultipartContent(request)) {
//不是MIME传输方式
return;
}else {
try {
//获取数据集合
List<FileItem> fileItems = upload.parseRequest(request);
for(FileItem item : fileItems) {
if(item.isFormField()) {
//不是文件类型,而是普通提交数据
System.out.println(item.getString("UTF-8"));
}else {
/*String content = item.getString("UTF-8");输出文件内容*/
//不同浏览器获取的文件名不同,有的是具体位置,有的直接是文件的名字,所以要规范一下
String name = item.getName();
String fileName = name.substring(name.lastIndexOf("\\")+1);
InputStream is = item.getInputStream();
FileOutputStream fos = new FileOutputStream(store+"/"+fileName);
int len = 0;
byte[]arr = new byte[1024];
while((len = is.read(arr))>0) {
fos.write(arr, 0, len);
}
fos.close();
is.close();
//删除下载时产生的临时文件,这步很重要
item.delete();
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
为了防止不同用户提交相同文件名的文件,可以使用UUID值加上真实文件名的文件名修改方式。
同时为了防止同一目录下文件过多,可是采用生成多级目录分散存储的方式。
package com.hncj.test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
@WebServlet("/MoudleFileUpload")
public class MoudleFileUpload extends HttpServlet{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String storePath = this.getServletContext().getRealPath("/WEB-INF/store");
String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
File store = new File(storePath);
File temp = new File(tempPath);
if(!store.exists()) {
store.mkdir();
}
if(!temp.exists()) {
temp.mkdir();
}
//创建文件工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
//设置缓冲文件存储路径
factory.setRepository(temp);
//设置文件的大小限制
factory.setSizeThreshold(30*1024*1024);
//创建文件上传类
ServletFileUpload upload = new ServletFileUpload(factory);
//解决文件名乱码问题
upload.setHeaderEncoding("UTF-8");
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long pBytesRead, long pContentLength, int pupload) {
System.out.println("文件总大小:"+pContentLength+"字节 你已经上传:"+pBytesRead);
}
});
if(!upload.isMultipartContent(request)) {
//不是MIME传输方式
return;
}else {
try {
//获取数据集合
List<FileItem> fileItems = upload.parseRequest(request);
for(FileItem item : fileItems) {
if(item.isFormField()) {
//不是文件类型,而是普通提交数据
System.out.println(item.getString("UTF-8"));
}else {
/*String content = item.getString("UTF-8");输出文件内容*/
//不同浏览器获取的文件名不同,有的是具体位置,有的直接是文件的名字,所以要规范一下
String name = item.getName();
String fileName = name.substring(name.lastIndexOf("\\")+1);
String uuidName = getUUIDName(fileName); //加上UUID
String savePath = getRandomDir(storePath, uuidName); //加上两级目录
InputStream is = item.getInputStream();
FileOutputStream fos = new FileOutputStream(savePath+"/"+uuidName);
int len = 0;
byte[]arr = new byte[1024];
while((len = is.read(arr))>0) {
fos.write(arr, 0, len);
}
fos.close();
is.close();
//删除下载时产生的临时文件,这步很重要
item.delete();
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
//加上UUID之后的文件名
private String getUUIDName(String fileName) {
return UUID.randomUUID()+"_"+fileName;
}
//加上2级目录
private String getRandomDir(String storePath,String uuidName) {
int hashCode = uuidName.hashCode();
int dir1 = hashCode & 0xf;
int dir2 = (hashCode>>4) & 0xf;
String savePath = storePath+"/"+dir1+"/"+dir2;
File f = new File(savePath);
if(!f.exists()) {
boolean flag = f.mkdirs(); //特别注意,mkdirs(),目录和文件一定要先创建父目录,再创建子目录,坑啊
//刚开始一直报FileNotFound和IOException
}
return f.getPath();
}
}