Web---文件上传-用apache的工具处理、打散目录、简单文件上传进度
发布日期:2021-06-29 13:36:56 浏览次数:2 分类:技术文章

本文共 9255 字,大约阅读时间需要 30 分钟。

我们需要先准备好2个apache的类:

上一个博客文章只讲了最简单的入门,现在来开始慢慢加深。

先过渡一下:只上传一个file项

index.jsp:

用apache的工具处理文件上传

文件:

web.xml:

UploadServlet
cn.hncu.servlets.upload.UploadServlet
UploadServlet
/upload

UploadServlet.java:

package cn.hncu.servlets.upload;import java.io.File;import java.io.IOException;import java.io.PrintWriter;import java.util.List;import java.util.UUID;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.FileUploadException;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;import org.apache.commons.io.FileUtils;public class UploadServlet extends HttpServlet {    public void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        //下面这句解决上传文件名的中文乱码        //注意。下面这句设置中文,如果是“multipart/form-data”表单,可以设置其中file组件的文件名,但对其中的普通表单组件无效        //如果是"application/x-www-form-urlencoded"表单,可以设置其中的普通表单组件        request.setCharacterEncoding("utf-8");        //先获取所接收文件要保存的路径        String path = getServletContext().getRealPath("/imgs");        //文件上传需要临时目录(如果不指定,那么该目录就是tomcat/temp)        File tempDiv = new File("E:/a");        if(!tempDiv.exists()){            tempDiv.mkdir();        }        DiskFileItemFactory fileFactory = new DiskFileItemFactory(1024*8, tempDiv);        //创建用于解析文件的工厂类,同时设置缓存区的大小和位置        //####思路的入口:        ServletFileUpload upload = new ServletFileUpload(fileFactory);        upload.setFileSizeMax(1024*1024*5);//设置单个文件上传最大为5M        upload.setSizeMax(1024*1024*8);//所有上传文件大小之和的最大值,此处设最多能上传8M        //setSizeMax方法用于设置请求消息实体内容的最大允许大小,以防止客户端故意通过上传特大的文件来塞满服务器端的存储空间,单位为字节。        //以下开始解析:        //parseRequest是从查询字符串和请求体中获取参数赋值到paramMap,然后格式化uri,填充Request对象实例        try {            List
list = upload.parseRequest(request); for(FileItem fi:list){ // isFormField()。isFormField方法用来判断FileItem对象里面封装的数据是一个普通文本表单字段,还是一个文件表单字段。 //如果是普通文本表单字段,返回一个true否则返回一个false。 //因此可以用该方法判断是否是普通表单域还是文件上传表单域。 if(fi.isFormField()){ //普通表单组件,如:
String str = fi.getString("utf-8");//以指定编码的方式获取,来解决普通表单组件的中文乱码问题 //将FileItem对象中保存的数据流内容以一个字符串返回。 System.out.println("普通表单组件:"+str); }else{//文件组件 String fileName = fi.getName();//获得上传文件的文件名 System.out.println("fileName:"+fileName); //由于上传的文件“名字”可能会有中文,而服务器目录当中的资源名称不能够用中文(带中文的文件在浏览器中无法访问的),因此要把它转换成非中文的文件名(要考虑文件名不能重复) //于是,我们用java自带的UUID类,自动生成 String uuid = UUID.randomUUID().toString().replace("-", "");//去掉uuid中的'-' String ext = fileName.substring(fileName.lastIndexOf("."));//截取文件的扩展名: .* //System.out.println("ext:"+ext); String newFileName = uuid+ext;//本地服务器存储的文件名 //System.out.println("newFileName:"+newFileName); //真正的文件内容在fi.getInputStream() 当中 FileUtils.copyInputStreamToFile(fi.getInputStream(), new File(path+"/"+newFileName));//拷贝的字节从InputStream源文件到目的地(file)。 } } } catch (FileUploadException e) { throw new RuntimeException(e); } }}

演示结果:

在这个上传中,我们并没有把uuid和文件名联系起来,这样是不好的,必须用数据库把uuid和其对应的文件名存起来。以后下载的时候还给客户端一样的名字,而不是给他uuid的名字。

上传二个file项

index.jsp:

文件1:
文件1的说明:
文件2:
文件2的说明:

其他的相对前面的都没改动~

演示结果:

上传文件最终版:

index.jsp:

进一步演示文件上传用法

文件1:
文件1的说明:
文件2:
文件2的说明:

web.xml:

UploadServlet2
cn.hncu.servlets.upload.UploadServlet2
UploadServlet2
/upload2

UploadServlet2.java:

package cn.hncu.servlets.upload;import java.io.File;import java.io.IOException;import java.io.PrintWriter;import java.util.List;import java.util.UUID;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.FileUploadException;import org.apache.commons.fileupload.ProgressListener;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;public class UploadServlet2 extends HttpServlet {
//防黑1---在地址栏直接提交的-我们要防住 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); response.getWriter().print("不支持GET方式上传!!!"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); final PrintWriter out = response.getWriter();//等会内部类需要用到这个变量,所以定义成final //防黑2--非multipart表单提交 //手动方式 String type = request.getContentType(); if(!type.contains("multipart/form-data")){
//如果此字符串包含 s,则返回 true,否则返回 false out.print("不支持普通表单提交"); return; } DiskFileItemFactory fiFactory = new DiskFileItemFactory(); fiFactory.setSizeThreshold(1024*8);//8k,缓存区大小 File file = new File("d:/a"); if(!file.exists()){ file.mkdir(); } fiFactory.setRepository(file);//设置缓存区 /* ServletFileUpload类是Apache文件上传组件处理文件上传的核心高级类(所谓高级就是不需要管底层实现,暴露给用户的简单易用的接口)。 使用其 parseRequest(HttpServletRequest) 方法可以将通过表单中每一个HTML标签提交的数据封装成一个FileItem对象,然后以List列表的形式返回。 */ ServletFileUpload upload = new ServletFileUpload(fiFactory); upload.setHeaderEncoding("utf-8");//用于设置文件名的编码,相当于:request.setCharacterEncoding("utf-8"); String path = getServletContext().getRealPath("/imgs"); //文件上传进度功能---设置监听器 upload.setProgressListener(new ProgressListener() { private int pre=0; //参数解析---pBytesRead:已上传字节数 pContentLength:上传的总字节数 pItems:文件序号(从1开始的) @Override public void update(long pBytesRead, long pContentLength, int pItems) { double d = pBytesRead*100.0/pContentLength;//计算百分比 int dd = (int)d; if(pre!=dd){
//防范输出一样的百分比 out.print(dd+"%
"); pre=dd; } } }); FileItem fi=null; try { List
list = upload.parseRequest(request); for(FileItem fi2:list){ fi=fi2;//相当于传指针,同一个对象 if(fi.isFormField()){
//普通表单组件 String str = fi.getString("utf-8"); System.out.println("普通表单组件提交的内容:"+str); }else{
//表单中的:file组件 //防黑3--在file组件中不选择文件 if(fi.getSize()==0){ continue; } //文件名 String fileName = fi.getName(); fileName = fileName.substring( fileName.lastIndexOf("\\")+1 );//这里就是文件名(后缀名也在的) String ext = fileName.substring( fileName.lastIndexOf(".") );// .* 后缀名 //文件名不能用中文,必须转换成ascii码的格式,而且文件名不能重复(必须保证唯一),因此采用UUID来实现 String newFileName = UUID.randomUUID().toString().replace("-", "");//去掉'-' newFileName = newFileName+ext; //打散目录(因为对于普通的机器,一个文件夹如果存储的文件个数超过1000个,性能就会急剧下降!!!)、 String dir1 = Integer.toHexString( fileName.hashCode() & 0xf ); String dir2 = Integer.toHexString( (fileName.hashCode() & 0xf0)>>4 );//右移四位 String dir3 = Integer.toHexString( ( fileName.hashCode() & 0xf00 )>>8); File dir = new File(path+"/"+dir1+"/"+dir2+"/"+dir3);//16*16*16个文件夹 if(!dir.exists()){ dir.mkdirs(); } File f = new File(dir+"/"+newFileName); fi.write(f); } } }catch (FileUploadException e) { throw new RuntimeException(e); } catch (Exception e) { throw new RuntimeException(e); } finally{ if(fi!=null){ fi.delete();//清临时文件 } } }}

演示结果:

进行了一个文字型的文件上传进度,没办法啊,现在还没学AJax,做不了同步~~理解理解,后面会学到的。

注意看文件的保存目录!!!!(0-f)16进制的文件名~

我做了三层~

演示下中文路径的文件不能显示的实例:

中文路径不行

先移动这个图片到这个目录:

再看浏览器的访问结果:

无法访问到这个文件!!!!!!

进度条前台技术演示:

最后,我们自己来做个假的进度条看看:

其实只是少了aJax技术而已。

index.jsp:

进度条前台技术演示

propress.jsp:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>              

进度条前台技术演示

演示结果:

点启动按钮,就是从0%启动,运行到全部填充完毕(100%)就停止。

点停止按钮,就停止在当前进度,点重新启动,就是恢复启动~从暂停的地方继续~~

转载地址:https://chenhx.blog.csdn.net/article/details/51996821 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Apache FileUpload详细介绍
下一篇:apache的FileUtils方法大全

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月13日 01时00分00秒