在web开发中,文件上传功能是很普遍的,我们最常见的就是上传图片了,还有上传Excel,今天小编给大家分享一下利用apache的组件实现文件上传功能。
文件上传总体思路
我们想要将磁盘上的文件上传到服务器上去,首先应该有一个管理磁盘文件的工具,当我们上传文件时,还要有一个负责上传文件和解析文件的工具,这两个工具就是apache提供的jar包,commons-fileupload组件和commons-io组件。我们将这两个组件放到我们的项目中,这样我们就可以开始上传工作了。小编将上传工作分成了三个步骤,1.准备需要上传的磁盘文件,2.开始上传,3.解析上传文件并保存到服务器。
一.准备需要上传的磁盘文件
文件准备就不用说了,先建立一个jsp,此jsp负责用户上传文件。此jsp中有一form表单,此表单有三个特点,或者是说文件上传的三个前提。
a、表单的method必须是post
b、表单的enctype属性必须是multipart/form-data
c、表单中提供<inputtype="file"/>类型的上传输入域
下面是具体的代码:<form action="${pageContext.request.contextPath}/servlet/UploadServlet2" method="post" enctype="multipart/form-data">
name:<input type="text" name="name"/><br/>
file1:<input type="file" name="photo"/><br/>
file2:<input type="file" name="photo"/><br/>
<input type="submit" value="上传"/>
</form>
二.开始上传
我们建立一个servlet,在此servlet中开始准备上传时用到的类,也就是DiskFileItemFactory类,和ServletFileuqLoad类,DiskFileItemFactory负责管理磁盘文件,ServletFileuqLoad类负责上传和解析文件。下面是具体的代码。
<pre name="code" class="java">public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");// 解决上传的中文文件乱码问题
response.setContentType("text/html;charset=UTF-8");
// 1.0. 检查是否是multipart/form-data类型的
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (!isMultipart) {
throw new RuntimeException(
"The form's enctype attribute value must be multipart/form-data");
}
// 2.0开始实现上传,创建上传文件需要用到的两个对象
DiskFileItemFactory factory = new DiskFileItemFactory();// 产生FileItem的工厂
ServletFileUpload sfu = new ServletFileUpload(factory); //因为解析器依赖于这个工厂,所以将这个工厂传进去
// 3.0创建一个容器来接收解析的内容
List<FileItem> items = new ArrayList<FileItem>();
//4.0将上传的文件信息放到容器中
try {
items = sfu.parseRequest(request);
} catch (FileUploadException e) {
e.printStackTrace();
}
//5.0 遍历 开始处理解析的内容,这里封装了两个方法,一个是专门处理FormField的方法,一个是专门处理UploadField的方法
for (FileItem item : items) {
if (item.isFormField()) {
processFormField(item);// 处理普通p上传字段
} else {
processUploadField(item);// 处理上传字段
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
下面是两个需要解析的方法,一个是一个是专门处理FormField的方法(也就是表单中普通的字段),一个是专门处理UploadField的方法(也就是需要上传的文件)。
三、解析上传文件并保存到服务器
1、专门处理FormField的方法
<pre name="code" class="java">protected void processFormField(FileItem item) {
// 打印到控制台
String fieldName = item.getFieldName();
String value = "";
try {
value = item.getString("UTF-8");// 解决普通字段的编码问题,得到普通字段的值
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.out.println(fieldName + "=" + value);
}
2、专门处理FormField的方法(此方法负责存放文件)
<pre name="code" class="java">protected void processUploadField(FileItem item) {
try {
// 找到一个存放位置 存放文件名
String fileName = item.getName();// 上传的文件的文件名
// C:\Users\wzhting\Desktop\a.txt
// a.txt(浏览器不同)
if (fileName != null) {
// 控制只能能上传图片
// if (!item.getContentType().startsWith("image")) {
// return;
// }
fileName = FilenameUtils.getName(fileName);
fileName = IdGenertor.genGUID() + "_" + fileName;
}
// 存放路径
String realPath = getServletContext().getRealPath("/WEB-INF/files");
// 生成一个子目录
String childDirectory = genChildDirectory(realPath, fileName);
File storeDirectory = new File(realPath + File.separator
+ childDirectory);
//如果目录不存在,就创建一个
if (!storeDirectory.exists()) {
storeDirectory.mkdirs();
}
//开始存放磁盘文件
item.write(new File(storeDirectory, fileName));
} catch (Exception e) {
e.printStackTrace();
}
}
3、为了避免上传的文件存在同一个文件夹下(对于后期的遍历查找不利)我们可以写一个方法来临时创建分目录。
<pre name="code" class="java">// 按照hashcode创建分目录 放置一个文件夹下面的上传文件过度
private String genChildDirectory(String realPath, String fileName) {
int hashCode = fileName.hashCode();
int dir1 = hashCode & 0xf;
int dir2 = (hashCode & 0xf0) >> 4;
String str = dir1 + File.separator + dir2;
File file = new File(realPath, str);
if (!file.exists()) {
file.mkdirs();
}
return str;
}
// 按照时间创建分目录 放置一个文件夹下面的文件过多
protected String genChildDirectory(String realPath) {
Date now = new Date();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String str = df.format(now);
File file = new File(realPath, str);
if (!file.exists()) {
file.mkdirs();
}
return str;
}
上面两个方法一个是根据日期来创建目录,一个是根据hashcode创建目录。
四、其它上传文件中经常用到的功能
1.限制上传文件的类型,比如说,限制只能上传照片
if (!item.getContentType().startsWith("image")) {
return;
}
2.限制一下上传文件的大小
DiskFileItemFactory factory = new DiskFileItemFactory();// 产生FileItem的工厂
ServletFileUpload sfu = new ServletFileUpload(factory); //因为解析器依赖于这个工厂,所以将这个工厂传进去
// 限制上传文件大小
sfu.setFileSizeMax(1024 * 196);// 限制单个文件的大小不超过200kb
//sfu.setSizeMax(5*1024*1024);//限制上传的总文件大小不超过5M
// 3.0创建一个容器来接收解析的内容
List<FileItem> items = new ArrayList<FileItem>();
//4.0将上传的文件信息放到容器中
try {
items = sfu.parseRequest(request);
} catch (FileUploadBase.FileSizeLimitExceededException e) {
response.getWriter().write("照片不能超过196k");
} catch (FileUploadException e) {
e.printStackTrace();
}
五、小结
小编将上传文件的步骤和代码总结了一遍,其实当文件上传到服务器上的时候,我们有时候还需要将文件的存放路径放在数据库中,这样以来我们再取改文件的时候就相对容易一点了。整个文件上传的过程,我认为在文件解析和存储的过程是最麻烦的,里面用到了IO的许多知识,好了,就总结到这吧!