1. 进行文件上传时, 表单需要做的准备:

1). 请求方式为 POST: <form action="uploadServlet" method="post" ... >

2). 使用 file 的表单域: <input type="file" name="file"/>

3). 使用 multipart/form-data 的请求编码方式: <form action="uploadServlet" method="post" enctype="multipart/form-data">


jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/uploadServlet" method="post"
enctype="multipart/form-data">
File:<input type="file" name="file" /> <br>
desc:<input type="text" name="desc"> <br>
<input type="submit">
</form>
</body>
</html>


4). 关于 enctype:


> application/x-www-form-urlencoded:表单 enctype 属性的默认值。这种编码方案使用有限的字符集,当使用了非字母和数字时,


必须用”%HH”代替(H 代表十六进制数字)。对于大容量的二进制数据或包含非 ASCII 字符的文本来说,这种编码不能满足要求。



> multipart/form-data:form 设定了enctype=“multipart/form-data”属性后,表示表单以二进制传输数据 



2.使用commons-fileupload组件上传文件

lib:

commons-fileupload-1.2.1.jar

commons-io-2.0.jar

基本思想: 

> commons-fileupload 可以解析请求, 得到一个 FileItem 对象组成的 List
> commons-fileupload 把所有的请求信息都解析为 FileItem 对象, 无论是一个一般的文本域还是一个文件域. 
> 可以调用 FileItem 的 isFormField() 方法来判断是一个 表单域 或不是表单域(则是一个文件域)
> 再来进一步获取信息

public class uploadServlet extends HttpServlet {

private static final long serialVersionUID = -7199179697800254436L;

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

//1、创建一个DiskFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
FileCleaningTracker fileCleaningTracker = FileCleanerCleanup.getFileCleaningTracker(getServletContext());
factory.setFileCleaningTracker(fileCleaningTracker);

// 设置内存缓冲区,超过后写入临时文件
factory.setSizeThreshold(1024 * 1024 * 5);
File tmpDirectory = new File("d:\\tempDirectory");
factory.setRepository(tmpDirectory);

//2、创建一个文件上传解析器
ServletFileUpload upload = new ServletFileUpload(factory);

//设置上传的单个文件最大字节数
upload.setSizeMax(1024 * 1024 * 5);

try {
List<FileItem> parseRequest = upload.parseRequest(req);
for (FileItem fileItem : parseRequest) {
// 2.遍历items:若是一般表单域,打印信息
if (fileItem.isFormField()) {
String name = fileItem.getFieldName();
String value = fileItem.getString();
System.out.println(name + ":" + value);
}else{
//若是文件域则把文件保存到 d:\\files 目录下.
String fieldName = fileItem.getFieldName();
String name = fileItem.getName();
String contentType = fileItem.getContentType();
long size = fileItem.getSize();

System.out.println(fieldName);
System.out.println(name);
System.out.println(contentType);
System.out.println(size);

InputStream inputStream = fileItem.getInputStream();
byte[] buffer = new byte[1024];
int len = 0;
fieldName ="d:\\files\\"+name;
System.out.println(fieldName);
FileOutputStream outputStream = new FileOutputStream(fieldName);


while((len=inputStream.read(buffer))!=-1){
outputStream.write(buffer, 0, len);
}
outputStream.close();
inputStream.close();

}
}

} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

// ServletInputStream inputStream = req.getInputStream();
// Reader reader = new InputStreamReader(inputStream);
// BufferedReader bufferedReader = new BufferedReader(reader);
// String str = null;
// while ((str = bufferedReader.readLine()) != null) {
// System.out.println(str);
// }
}

}

多文件上传

jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>
<script type="text/javascript" src="${pageContext.request.contextPath }/scripts/jquery-1.7.2.js"></script>
<script type="text/javascript">

$(function(){

var i = 2;

$("#addFile").click(function(){
$(this).parent().parent().before("<tr class='file'><td>File"
+ i + ":</td><td><input type='file' name='file"
+ i + "'/></td></tr>"
+ "<tr class='desc'><td>Desc"
+ i + ":</td><td><input type='text' name='desc"
+ i + "'/><button id='delete"
+ i + "'>删除</button></td></tr>");
i++;

//获取新添加的删除按钮
$("#delete" + (i-1)).click(function(){
var $tr = $(this).parent().parent();
$tr.prev("tr").remove();
$tr.remove();

//对 i 重写排序
$(".file").each(function(index){
var n = index + 1;

$(this).find("td:first").text("File" + n);
$(this).find("td:last input").attr("name", "file" + n);
});

$(".desc").each(function(index){
var n = index + 1;

$(this).find("td:first").text("Desc" + n);
$(this).find("td:last input").attr("name", "desc" + n);
});

i = i - 1;
});

return false;
});

});

</script>

</head>
<body>

<font color="red">${msg }</font>
<br><br>


<form action="${pageContext.request.contextPath }/app/FileUploadServlet" method="post" enctype="multipart/form-data">

<table>
<tr class="file">
<td>File1:</td>
<td><input type="file" name="file1"/></td>
</tr>
<tr class="desc">
<td>Desc1:</td>
<td><input type="text" name="desc1"/></td>
</tr>

<tr>
<td><input type="submit" id="submit" value="提交"/></td>
<td><button id="addFile">新增一个附件</button></td>
</tr>
</table>

</form>

</body>
</html>


upload.properties

exts=pptx,docx,doc,zip
file.MaxSize=102400
total.file.max.size=512000


FileUploadAppProperties


public class FileUploadAppProperties {
private Map<String, String> properties = new HashMap<>();

private FileUploadAppProperties() {
}

private static FileUploadAppProperties instance = new FileUploadAppProperties();

public static FileUploadAppProperties getInstance() {
return instance;
}

public void addProperties(String propertyName, String propertyValue) {
properties.put(propertyName, propertyValue);
}

public String getProperties(String propertyName) {
return properties.get(propertyName);
}

}


监听器加载配置文件

FileUploadAppLitener

@WebListener
public class FileUploadAppLitener implements ServletContextListener {


@Override
public void contextInitialized(ServletContextEvent arg0) {
InputStream in = getClass().getClassLoader().getResourceAsStream("/upload.properties");
Properties properties = new Properties();


try {
properties.load(in);
for (Map.Entry<Object, Object> pro : properties.entrySet()) {
String propertName = (String) pro.getKey();
String propertValue = (String) pro.getValue();
FileUploadAppProperties.getInstance().addProperties(propertName, propertValue);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}


@Override
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
}
}


FileUploadBean

public class FileUploadBean {
private Integer id;
// 文件名
private String fileName;
// 文件路径
private String filePath;
// 文件描述
private String fileDesc;


public FileUploadBean() {
}


public FileUploadBean(String fileName, String filePath, String fileDesc) {
super();
this.fileName = fileName;
this.filePath = filePath;
this.fileDesc = fileDesc;
}
setter ...getter ..
}


FileUploadServlet

@WebServlet("/app/FileUploadServlet")
public class FileUploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

private static final String FILE_PATH = "/WEB-INF/files";

private static final String TEMP_DIR = "d:\\tempDirectory";

protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

String path;

try {
ServletFileUpload upload = getServletUpload();

String fileSaveDir = getServletContext().getRealPath(FILE_PATH);
File file = new File(fileSaveDir);
if (!file.exists()) {
file.mkdirs();
}

// 把需要上传的FileItem 都放入到该Map中
// 键:文件的待存放的路径,值:对应的FileItem对象
Map<String, FileItem> uploadFiles = new HashMap<>();
// 解析请求,得到FileItem 的集合
List<FileItem> items = upload.parseRequest(request);
// 1.构建FileUploadBean 的集合,同时填充uploadFiles
List<FileUploadBean> beans = buildFileUploads(items, uploadFiles);
// 2.校验扩展名
vaidateExtName(beans);
// 3.校验文件的大小:在解析时,已经检验了,我们只需通过异常得到结果
// 4.进行文件的上传操作
upload(uploadFiles);
// 5.把上传的信息保存到数据库
saveBean(beans);

//6. 删除临时文件夹的临时文件
FileUtils.delAllFile(TEMP_DIR);

path = "/app/success.jsp";
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
String msg = e.getMessage();

path = "/app/upload.jsp";
request.setAttribute("msg", msg);

}
request.getRequestDispatcher(path).forward(request, response);

}

private void saveBean(List<FileUploadBean> beans) {
// TODO Auto-generated method stub

}

private void upload(Map<String, FileItem> uploadFiles) throws IOException {
for (Map.Entry<String, FileItem> uploadFile : uploadFiles.entrySet()) {
String filePath = uploadFile.getKey();
FileItem fileItem = uploadFile.getValue();
System.out.println(filePath);
upload(filePath, fileItem.getInputStream());
}

}

private void upload(String filePath, InputStream in) throws IOException {
FileOutputStream outputStream = new FileOutputStream(filePath);
byte[] buffer = new byte[1024];
int len = 0;

while ((len = in.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
outputStream.close();
in.close();

}

/**
* 校验扩展名是否合法
*
* @param beans
*/
private void vaidateExtName(List<FileUploadBean> beans) {
String exts = FileUploadAppProperties.getInstance().getProperties("exts");
List<String> extList = Arrays.asList(exts.split(","));
for (FileUploadBean bean : beans) {
String fileName = bean.getFileName();
String extName = fileName.substring(fileName.lastIndexOf(".") + 1);
if (!extList.contains(extName)) {
throw new InvalidExtNameException(fileName + "文件的扩展名不合法");
}
}

}

private List<FileUploadBean> buildFileUploads(List<FileItem> items, Map<String, FileItem> uploadFiles)
throws UnsupportedEncodingException {
List<FileUploadBean> beans = new ArrayList<>();
// 1.遍历FileItem的集合,先得到的desc的Map<String,String>,其中键:fileName(desc1,desc2...)
// 值表单域对应字段的值
Map<String, String> descs = new HashMap<>();
for (FileItem item : items) {
if (item.isFormField()) {
descs.put(item.getFieldName(), item.getString());
}
}
// 2/再遍历FileItem集合,得到文件域的FileItem对象
// 每个得到一个FileItem对象都创建一个FileUploadBean 对象
// 得到 fileName,构建filePath,从1的Map中得到当前FileItem对应的那个desc
// 使用fileName后面的数字匹配
for (FileItem item : items) {
if (!item.isFormField()) {
String fieldName = item.getFieldName();
String index = fieldName.substring(fieldName.length() - 1);
// 上传文件名
String fileName = item.getName();

System.out.println(fileName);
String desc = descs.get("desc" + index);
String filePath = getFilePath(fileName);
FileUploadBean fileUploadBean = new FileUploadBean(fileName, filePath, desc);
beans.add(fileUploadBean);

uploadFiles.put(filePath, item);
}
}
return beans;
}

private String getFilePath(String fileName) {
String extName = fileName.substring(fileName.lastIndexOf("."));
// 生成随机数,防止filePath相同
Random random = new Random();
int randomNumber = random.nextInt(10000);
String filePath = getServletContext().getRealPath(FILE_PATH) + File.separator + System.currentTimeMillis()
+ randomNumber + extName;
return filePath;
}

private ServletFileUpload getServletUpload() {
String exts = FileUploadAppProperties.getInstance().getProperties("exts");
String maxSize = FileUploadAppProperties.getInstance().getProperties("file.MaxSize");
String total = FileUploadAppProperties.getInstance().getProperties("total.file.max.size");

System.out.println(exts);

DiskFileItemFactory factory = new DiskFileItemFactory();

// 设置内存缓冲区,超过后写入临时文件
factory.setSizeThreshold(1024 * 5);
File tmpDirectory = new File(TEMP_DIR);
factory.setRepository(tmpDirectory);

// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);

// 解决路径或者文件名为乱码的问题
upload.setHeaderEncoding("UTF-8");

// Set overall request size constraint
upload.setSizeMax(Long.parseLong(total));//设置整个表单的上传文件最大字节数
upload.setFileSizeMax(Long.parseLong(maxSize));//设置上传的单个文件最大字节数
return upload;
}

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}

}


public class FileUtils {

/**
* 删除文件夹
* @param folderPath: 文件夹完整绝对路径
*/
public static void delFolder(String folderPath) {
try {
// 删除完里面所有内容
delAllFile(folderPath);
String filePath = folderPath;
filePath = filePath.toString();
java.io.File myFilePath = new java.io.File(filePath);
// 删除空文件夹
myFilePath.delete();
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* 删除指定文件夹下所有文件
* @param path: 文件夹完整绝对路径
* @return
*/
public static boolean delAllFile(String path) {
boolean flag = false;
File file = new File(path);
if (!file.exists()) {
return flag;
}
if (!file.isDirectory()) {
return flag;
}
String[] tempList = file.list();
File temp = null;
for (int i = 0; i < tempList.length; i++) {
if (path.endsWith(File.separator)) {
temp = new File(path + tempList[i]);
} else {
temp = new File(path + File.separator + tempList[i]);
}
if (temp.isFile()) {
temp.delete();
}
if (temp.isDirectory()) {
// 先删除文件夹里面的文件
delAllFile(path + "/" + tempList[i]);
// 再删除空文件夹
delFolder(path + "/" + tempList[i]);
flag = true;
}
}

return flag;
}

}