在网页设计中经常会遇到需要上传文件的时候,比如上传一个照片,上传一个头像等,今天总结一下使用fileUpload实现文件上传的方式,用代码示例代替话语讲解,以下实例是以上传图片为例
第一步:导入程序需要的jar包
第二步:新建一个web工程(不多说明)
第三步:新建一个jsp界面用于点击上传图片(直接用效果图表示)
在jsp中需要注意的几点 文件上传前提条件
- 表单的请求方式必须是post
- 表单提交的类型必须是enctype="multipart/form-data"
- 上传文件的控件 千万注意name属性必须有
###** 第四步:创建FileUploadServlet(名字自己取)对文件上传进行各种处理**
提前解释一些概念 后面会用到
- 临时存储目录: 上传或者下载大的文件的时候会先将文件存储到临时存储目录中,当上传或者下载完成的时候临时文件会自动消失.文件小的话就一下传输完了,不会有临时文件
- 文件上传成功,只是在磁盘上,别人如果想访问必须映射到服务器上面,发布到服务器,详情可以参考tomcat虚拟路径映射问题
- 数据库中不会存储图片 一般只是存储路径或者存储文件名等到时候取出来拼接路径
- 当时用请求转发的时候 即response.sendRedirect("ShowImg.jsp"); 请求转发不能使用域对象传值 可以使用session例如request.getSession().setAttribute("netPath", netPath);
FileUploadServlet对应的代码
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/* 防止中文乱码对编码进行设置 */
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset = utf-8");
/*------------------1.判断当前表单的类型 ---------------------------*/
if (!ServletFileUpload.isMultipartContent(request)) {
/* 不是上传的表单类型 直接return */
return;
}
/* 是上传的表单类型 */
// ------------2.配置DiskFileItemFactory------------------
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
// 为上传核心类设置上传的临时目录
diskFileItemFactory.setRepository(new File("c:\\"));
// ------------3.创建上传核心类对象---------------------------
ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
// 设置进度条
ProgressListener pListener = new ProgressListener() {
// 参数arg0表示上传的字节数 参数arg1表示总的的字节数
public void update(long arg0, long arg1, int arg2) {
// 设置后天可以查看季进度百分比
String percent = arg0 * 100 / arg1 + "%";
System.out.println(percent);
}
};
servletFileUpload.setProgressListener(pListener);
// -----------4.解析请求-----------------------------------
try {
// 解析完请求以后得到的是装有每一个表单项的list集合List
List list = servletFileUpload.parseRequest(request);
// 对list集合进行遍历 判断是普通表单项还是上传表单项
for (FileItem fileItem : list) {
if (fileItem.isFormField()) {
// 普通表单
String name = fileItem.getFieldName();
String value = fileItem.getString("utf-8");
} else {
// 上传表单 写文件 调用封装好的方法
File file = new File("c:\\img");
if (!file.exists()) {
// 文件夹不存在 创建文件夹
file.mkdirs();
}
// 在img文件夹中创建文件
String name = fileItem.getName();
String filename = name.substring(name.lastIndexOf("\\") + 1);
File file2 = new File(file, filename);
// 服务器上的映射地址http://localhost:8080/img01/具体资源名
String netPath = "http://localhost:8080/img01/" + filename;
try {
fileItem.write(file2);
} catch (Exception e) {
e.printStackTrace();
}
// 重定向不能使用请求域对象 所以使用session传值
System.out.println(netPath);
request.getSession().setAttribute("netPath", netPath);
response.sendRedirect("ShowImg.jsp");
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
ShowImg.jsp对应代码
上面的几个步骤已经实现了文件的上传和共享
第五步:接下来是重点的重点 对细节进行封装和改进
首先分析需要改进的细节的地方
- 文件的名字直接暴露在netPath的路径上面 大家都可以看到 安全性低
- 可能一个上传的文件名为aa 另一个人有上传了一个同名不同文件的aa 会引起覆盖 所以要保证名字的唯一性
- 不同用户不同时间上传的不同类型的文件都放在同一个文件夹下,混乱 所以要**打散文件**
需要注意打散的文件在映射到服务器的时候目录中不能忘记加上打散生成的新的文件路径
为了方便以后使用 将上面所有的改进放在工具类中
##第六步:创建FileUtils工具类 对细节进行改造 FileUploadUtils对应代码 之后做项目可以直接拿来用的自定义工具类
package com.qf.utils;
/**
* @author 作者 张明月 E-mail:[email protected]
* @version 创建时间:2017年9月22日 上午12:55:26
* 类说明
*/
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import org.apache.commons.fileupload.FileItem;
public class FileUploadUtils {
/*------------------------获取上传文件的的文件名----------------------*/
public static String getFileNameByCommon(FileItem fileItem) {
return fileItem.getName().substring(fileItem.getName().lastIndexOf("\\") + 1);
}
/*---------------------通过UUID获取上传文件的的文件名----------------------*/
public static String getFileNameByUUID(FileItem fileItem) {
String filename = getFileNameByCommon(fileItem);
String Singlefilename = UUID.randomUUID().toString() + "_" + filename;
return Singlefilename;
}
/*---------------------通过时间戳获取上传文件的的文件名----------------------*/
public static String getFileNameByTimeStamp(FileItem fileItem) {
String filename = getFileNameByCommon(fileItem);
String Singlefilename = System.currentTimeMillis() + "_" + filename;
return Singlefilename;
}
/*--------------------- 改进之前的默认方法获取文件夹-------------------*/
// 参数fileItem表示上传表单项 返回值为上传文件要写入的文件夹
public static File getFileByCommon(FileItem fileItem) {
File file = new File("c:\\img");
if (!file.exists()) {
file.mkdirs();
}
String filename = getFileNameByCommon(fileItem);
File file2 = new File(file, filename);
return file2;
}
/*----------------通过uuid实现文件名字的唯一性-------------------*/
public static File getFileByUUIDToSingleName(FileItem fileItem) {
File file = new File("c:\\img");
if (!file.exists()) {
file.mkdirs();
}
String Singlefilename = getFileNameByUUID(fileItem);
File file2 = new File(file, Singlefilename);
return file2;
}
/*----------------通过时间戳实现文件名字的唯一性-------------------*/
public static File getFileByTimestampToSingleName(FileItem fileItem) {
File file = new File("c:\\img");
if (!file.exists()) {
file.mkdirs();
}
String filename = getFileNameByCommon(fileItem);
String Singlefilename = System.currentTimeMillis() + "_" + filename;
File file2 = new File(file, Singlefilename);
return file2;
}
/*----------------------按照日期将文件打散---------------------------*/
public static File getFileByDataToBreakDirectory(FileItem fileItem) {
// 获取日期值
Long time = System.currentTimeMillis();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String data = format.format(new Date(time));
// 创建文件夹(按照时间创建)
File file = new File("c:\\img", data);
if (!file.exists()) {
file.mkdirs();
}
// 创建文件
String Singlefilename = getFileNameByTimeStamp(fileItem);
File file2 = new File(file, Singlefilename);
return file2;
}
/*----------------------按照hashcode将文件打散---------------------------*/
public static File getFileByHashCodeToBreakDirectory(FileItem fileItem) {
/* 获取文件名称hashcode值 */
String Singlefilename = getFileNameByTimeStamp(fileItem);
int filenameHashcode = Singlefilename.hashCode();
/* 将int型的hashcode的值转化成16进制的字符串 */
String code = Integer.toHexString(filenameHashcode);
/* 16进制有很多字符 随机取就可以 */
String directory = code.charAt(0) + "\\" + code.charAt(1);
// 创建2层目录
File file = new File("c:\\img", directory);
if (!file.exists()) {
file.mkdirs();
}
File file2 = new File(file, Singlefilename);
return file2;
}
/*----------------通过磁盘路径得到服务器的映射路径地址(网络访问路径)-------------------*/
public static String getNetPath(String diskPath) {
int index1 = diskPath.indexOf("img");
String netPath = "http://localhost:8080/img01/"+diskPath.substring(index1 + 4).replace("\\", "/");
return netPath;
}
}
第七步:利用工具类 回头简化FileUploadServlet
简化之后对应代码
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/* 防止中文乱码对编码进行设置 */
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset = utf-8");
/*------------------1.判断当前表单的类型 ---------------------------*/
if (!ServletFileUpload.isMultipartContent(request)) {
/* 不是上传的表单类型 直接return */
return;
}
/* 是上传的表单类型 */
// ------------2.配置DiskFileItemFactory------------------
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
// 为上传核心类设置上传的临时目录
diskFileItemFactory.setRepository(new File("c:\\"));
// ------------3.创建上传核心类对象---------------------------
ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
// 设置进度条
ProgressListener pListener = new ProgressListener() {
// 参数arg0表示上传的字节数 参数arg1表示总的的字节数
public void update(long arg0, long arg1, int arg2) {
// 设置后天可以查看季进度百分比
String percent = arg0 * 100 / arg1 + "%";
System.out.println(percent);
}
};
servletFileUpload.setProgressListener(pListener);
// -----------4.解析请求-----------------------------------
try {
// 解析完请求以后得到的是装有每一个表单项的list集合List
List list = servletFileUpload.parseRequest(request);
// 对list集合进行遍历 判断是普通表单项还是上传表单项
for (FileItem fileItem : list) {
if (fileItem.isFormField()) {
// 普通表单
String name = fileItem.getFieldName();
String value = fileItem.getString("utf-8");
} else {
File file2 = FileUploadUtils.getFileByUUIDToSingleName(fileItem);
// 服务器上的映射地址http://localhost:8080/img01/具体资源名
String netPath = FileUploadUtils.getNetPath(file2.getAbsolutePath());
try {
fileItem.write(file2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 重定向不能使用请求域对象 所以使用session传值
System.out.println(netPath);
request.getSession().setAttribute("netPath", netPath);
response.sendRedirect("ShowImg.jsp");
}
}
} catch (FileUploadException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}```