前提
enctype属性
enctype作用:告知服务器请求正文的MIME类型。(请求消息头:与Content-Type作用是一致的)
可选值:
服务器获取数据:不能通过request.getParameter(String)方法获取指定的表单字段字符内容,因为文件上传表单已经不在是字符内容,而是字节内容,需要通过IO流获取。
html
Servlet
这种办法获取到的数据会带分割串,处理比较麻烦,因此一般使用第三方包
fileupload是由apache的commons组件提供的上传组件。 它最主要的工作就是帮我们解析request.getInputStream()。
使用fileupload只需要2个jar包
fileupload的核心类有:
FileItem对象对应一个表单项(表单字段)。可以是文件字段或普通字段
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException,IOException {
//1.判断是否为文件上传表单
if(ServletFileUpload.isMultipartContent(req)){
//2.创建个文件工厂
FileItemFactory factory = new DiskFileItemFactory();
//3.创建文件上传对象
ServletFileUpload fileUpload = new ServletFileUpload(factory);
//4.解析请求
try{
List<FileItem> items = fileUpload.parseRequest(req);
for(FileItem item : items){
if(item.isFormField()){//普通表单字段
processFormField(item);
}else{//文件字段
processFile(item);
}
}
}catch (FileUploadException fue){
fue.printStackTrace();
}
}
}
private void processFile(FileItem item) {
String fieldName = item.getFieldName();
String fieldValue = item.getString();
//1.获取文件扩展名
String suffix = item.getName().split("\\.")[1];
String saveFileName = UUID.randomUUID().toString() + "." + suffix;
System.out.println(saveFileName + ":" + item.getContentType());
//2.创建文件保存的文件夹
String folderPath = this.getServletContext().getRealPath("/WEB-INF/upload");//获取项目真实路径
System.out.println("保存的路径:" + folderPath);
File file = new File(folderPath);
if(!file.exists()){
file.mkdirs();
}
//3.保存文件
//文件完整保存路径
String filePath = folderPath + "/" + saveFileName;
try {
item.write(new File(filePath));
item.delete();//删除临时文件
} catch (Exception e) {
e.printStackTrace();
}
}
private void processFormField(FileItem item) {
String fieldName = item.getFieldName();
String fieldValue = item.getString();
System.out.println(fieldName + ":" + fieldValue);
}
}
上述方法源自视频教学,但是似乎有误。 可能是每个Date对象都有不同的hashCode造成的,改为:将Date赋值给String对象,使用String创建hashcode
表单普通字段乱码用item.getString(“UTF-8”);
文件名乱码可用
单个文件大小:
总文件大小:(多文件上传)
DiskFileItemFactory:
存放缓存文件的目录在哪里? 默认是系统的临时目录。
如果自己用IO流实现的文件上传,要在流关闭后,清理临时文件。 在最后加上FileItem.delete(),删除临时文件
动态添加
<form action="/UploadServlet" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username" placeholder="请输入用户名"><br>
密码:<input type="password" name="password" placeholder="请输入密码"><br>
<div id="div1">
<div>
<input type="file" name="photo" /><input type="button" value="添加" onclick="addFile()"/><br />
</div>
</div>
<input type="submit" value="提交">
</form>
<script type="text/javascript">
function addFile(){
//得到div容器
var div1 = document.getElementById("div1");
div1.innerHTML += "<div><input type='file' name='photo' /><input type='button' value='删除' οnclick='delFile(this)'/><br /></div>";
}
function delFile(input){
//使用input对象的爷爷删除他的爸爸
input.parentNode.parentNode.removeChild(input.parentNode);
}
</script>
文件下载需要设置两个响应头
@WebServlet("/DownloadServlet")
public class DownloadServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//1.文件下载的位置
//此处可通过获取客户端参数然后在数据库中查找是否存在文件
String filePath = "C:/test.jpg";
//2.文件名
String fileName = "img.jpg";
fileName = URLEncoder.encode(fileName,"UTF-8");//中文名文件需要进行URL编码
//3.设置响应头
resp.setHeader("Content-Disposition","attachment;filename=" + fileName);
resp.setContentType("application/octet-stream");
//4.响应文件
File file = new File(filePath);
InputStream is = new FileInputStream(file);
byte[] bytes = new byte[1024 * 8];
int len;
OutputStream os = resp.getOutputStream();
while((len = is.read(bytes)) != -1){
os.write(bytes,0,len);
}
//5.关闭流
is.close();
os.close();
}
}
实质上,就是IO流的使用 由于文件在网络上通过字节流传输,因此通过字节IO流实现即可