文件上传
- web-inf目录下的文件不能从外界直接访问需要重定向和转发过去访问,限制某用户上传的文件只能在某用户账号下访问。
- 文件名不能重复-时间戳+UUID+MD5+位运算(加解密)
- 支持文件的传输必须在form中设置 enctype=“multipart/form-data”
- ARP地址解析协议:交换机将本区域的请求作为节点进行分发,请求认为是外部网络
- 普通项目可以创建module工程,在工程里可以创建servlet等类
网络传输的东西,都需要序列化
pojo,实体类,想在多个电脑上运行,需要传输将对象序列化
JNI =java native interface
implements java.io.Serializable:标记接口jvm识别后会做些事务,java–>java栈,本地方法栈 jvm–>c++>OS
实现步骤:
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//判断上传文件时普通表单还是文件表单
if (!ServletFileUpload.isMultipartContent(req)) { //true为文件表单,false为普通表单
return; //终止访问运行,从栈中弹出。
}
//创建上传文件的保存路径,在web-inf路径下,安全,用户无法直接访问上传的文件
String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
File uploadFiles = new File(uploadPath);
if (!uploadFiles.exists()) {
uploadFiles.mkdirs(); //创建这个目录
}
//缓存,临时文件
//若上传文件大小超过预期,则放到这个临时文件中,几天后自动删除或转为永久
String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
File tmpFiles = new File(tmpPath);
if (!tmpFiles.exists()) {
tmpFiles.mkdirs(); //创建这个目录
}
//处理上传文件,通过流来获取,可以使用req.getInputStream();原生态的文件上传流获取,需要解析,比较麻烦
//用apache的文件上传组件commons-fileupload-1.4.jar来实现,依赖于commons-fileupload-1.4.jar包
try {
//创建DiskFileItemFactory对象,处理文件上传路径和大小限制
DiskFileItemFactory diskFileItemFactory = getDiskFileItemFactory(tmpFiles);
//创建ServletFileUpload对象,需要DiskFileItemFactory对象
ServletFileUpload upload = getServletFileUpload(diskFileItemFactory);
//处理上传文件
String msg = uploadParseRequest(upload, req, uploadPath);
//请求转发出去
req.setAttribute("msg",msg);
req.getRequestDispatcher("info.jsp").forward(req,resp);
} catch (FileUploadException e) {
e.printStackTrace();
}
}
- 需要DiskFileItemFactory、ServletFileUpload等对象
//创建DiskFileItemFactory对象,处理文件上传路径和大小限制
public static DiskFileItemFactory getDiskFileItemFactory(File tmpFiles){
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
//以下可以不设置,有默认值
//设置DiskFileItemFactory对象文件上传路径为临时路径
diskFileItemFactory.setRepository(tmpFiles);
//设置DiskFileItemFactory对象缓冲区大小限制为1M
diskFileItemFactory.setSizeThreshold(1024 * 1024);
return diskFileItemFactory;
}
public static ServletFileUpload getServletFileUpload(DiskFileItemFactory diskFileItemFactory){
//创建ServletFileUpload对象,需要DiskFileItemFactory对象
ServletFileUpload upload = new ServletFileUpload(diskFileItemFactory);
//以下可以不设置,有默认值
//监听文件上传进度
upload.setProgressListener(new ProgressListener() {
//pContentLength预期文件字节大小
//pBytesRead已经读取的文件字节大小
@Override
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("总文件大小为:" + pContentLength + "。已经传输了" + pBytesRead);
}
});
//设置文件编码
upload.setHeaderEncoding("utf-8");
//设置单个文件的最大值
upload.setFileSizeMax(1024 * 1024 * 100);
//设置总共能上传文件的大小
upload.setSizeMax(1024 * 1024 * 100);
return upload;
}
- 利用ServletFileUpload对请求进行解析为 类型为FileItem的List集合,对其进行遍历,若是文件类型则利用创建好的路径(唯一文件名)用输入输出流进行传输保存
public static String uploadParseRequest(ServletFileUpload upload,HttpServletRequest req,String uploadPath) throws FileUploadException, IOException {
//把前端请求解析封装为一个个FileItems对象,需要ServletFileUpload来解析
List<FileItem> fileItems = upload.parseRequest(req);
String msg = "文件上传失败";
//遍历这个fileItems对象
for (FileItem fileItem : fileItems) {
//判断上传的文件值普通文本框还是文件
if (fileItem.isFormField()) {
//getFieldName前端控件的name属性
String name = fileItem.getFieldName();
try {
//name属性对应额value值,并处理乱码
String value = fileItem.getString("utf-8");
System.out.println("name:" + name + ",value=" + value);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else {
//处理文件
String itemName = fileItem.getName();
System.out.println("itemname=" + itemName);
//可能存在文件名不合法的情况
if (itemName.trim().equals("") || itemName == null) {
continue;
}
//获得上传的文件名 /xx/aa.png
String filename = itemName.substring(itemName.lastIndexOf("/") + 1);
//获得上传的文件的后缀名
String fileextname = itemName.substring(itemName.lastIndexOf(".") + 1);
/*若fileextname不符合要求直接return;
告诉用户文件类型不合要求*/
System.out.println("文件信息:filename=" + filename + "文件后缀名" + fileextname);
//上传文件夹的唯一识别名
//uuid与时间戳,硬件的信息有关,所以不可能相同
String uuid = UUID.randomUUID().toString();
//存放地址uploadPath
//文件真实存放位置realPath
String realPath = uploadPath + "/" + uuid;
//给每个文件创建一个文件夹
File realFile = new File(realPath);
if (!realFile.exists()) {
realFile.mkdirs();
}
//文件传输
InputStream is = null;
FileOutputStream fos = null;
//获得文件上传的输入流
is = fileItem.getInputStream();
//创建文件输出流
//realPath是真实的文件夹
//差了一个文件及输出的文件夹+"/"+文件名
fos = new FileOutputStream(realPath + "/" + itemName);
//创建一个缓存区
byte[] bytes = new byte[1024 * 1024];
//判断是否读取完毕
int len = 0;
//若不等于-1则还有数据
while ((len = is.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
msg = "文件上传成功!";
//关闭流资源
is.close();
fos.close();
//清除临时文件
fileItem.delete();
}
}
return msg;
}
- fileUpload.jsp上传页面设置让浏览器支持文件上传的控件和设置表单提交类型。
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>功能界面</title>
</head>
<body>
<%--
上传图片只能用post,get请求有大小限制4kb
--%>
<form action="${pageContext.request.contextPath}/upload.do" method="post" enctype="multipart/form-data">
用户:<input type="text" name="username">
<br/>
文件1:<input type="file" name="file1">
<br/>
文件2:<input type="file" name="file2">
<br/>
<input type="submit" name="submit" value="提交">|
<input type="reset" name="reset" value="重置">
</form>
</body>
</html>
- 结果页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>结果显示</title>
</head>
<body>
文件上传结果:${msg}
</body>
</html>
- 注意文件上传的目录设置。
web-inf目录下的文件不能从外界直接访问需要重定向和转发过去访问,限制某用户上传的文件只能在某用户账号下访问。