javaWeb小项目-文件上传下载

1 文件上传

1.1 文件上传原理分析

1.1.1 文件上传的前提

  • 提供form表单,method必须是post
  • form表单的enctype,必须是multipart/form-data
  • 提供input type="file"类的上传输入域

1.1.2 enctype属性

**enctype作用:**告知服务器请求正文MIME类型。(请求消息头:Context-Type作用是一致的)
可选值:
application/x-www-form-urlencoded(默认):
正文:username=admin&password=123
服务器获取数据:String username = request.getParameter(“username”);
multipart/form-data
正文:在这里插入图片描述
服务器获取数据:request.getParameter(String)方法获取指定的表单字段字符内容。但是文件上传表单已经不在是字符内容,而是字节内容,所以无效,所以利用字节流读取数据。request.getInputStream();
在这里插入图片描述

1.2 文件上传案例

1.2.1 upload.jsp

<form action="${pageContext.request.contextPath}/UploadServlet" method="post" enctype="multipart/form-data">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    文件:<input type="file" name="file"><br>
    <input type="submit" value="提交">
</form>

1.2.2 UploadServlet

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //1.获取表单提交的原始数据
        InputStream is =request.getInputStream();

        //2.读取数据
        byte[] buf = new byte[1024];
        int len=0;
        while((len = is.read(buf))!=-1){
            //把字节转成utf-8的编码字符串
            String str = new String(buf,0,len,"utf-8");
            System.out.println(str);
        }
    }

}

由于需要将读取到的字节进行分割成有效数据,所以利用第三方框架来进行处理。

1.3 家用第三方解析文件

1.3.1 fileupload概述

  • fileupload是由apache的commons组件提供的上传组件。它最主要的工作就是帮我们解析request.getInputStream()。
  • 使用fileupload只需要2个jar包
    commons-fileupload.jar,核心包;
    commons-io.jar,依赖包。

    在idea中,导入的包不会立即起效,需要对导入的包进行应该是加载一类。
    选中java之后,选中java->本项目->web->WEB-INF->lib点击ok即可。
    在这里插入图片描述

1.3.2 fileupload的核心类:

DiskFileItemFactory、ServletFileUpload、FileItem

1.3.3 解析原理

在这里插入图片描述
通过浏览器上传的数据中,每一个表单项input都封装成了一个FileItem对象,利用DiskFileItemFactory工厂对象构造一个FileItem集合类ServletFileUpload,来存储FilItem对象。

1.3.4 FileItem对象介绍

  • FileItem对象对应一个表单项(表单字段)。可以是文件字段或普通字段
  • boolean isFormField():判断当前表单字段是否为普通文本字段,如果返回false,说明是文件字段;
  • String getFieldName():获取字段名称,例如:,返回的是username;
  • String getString():获取字段的内容,如果是文件字段,那么获取的是文件内容,当然上传的文件必须是文本文件;
  • String getName():获取文件字段的文件名称;(a.txt)
  • String getContentType():获取上传的文件的MIME类型,例如:text/plain。
  • int getSize():获取上传文件的大小;
  • InputStream getInputStream():获取上传文件对应的输入流;
  • void write(File):把上传的文件保存到指定文件中。
  • delete():删除临时文件

1.3.5 使用fileupload实现文件上传代码

  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //解析表单数据
        //1.创建工厂类
        DiskFileItemFactory factory = new DiskFileItemFactory();
        //2.获取文件上传对象
        ServletFileUpload sfu = new ServletFileUpload(factory);

        //设置单个文件上传大小
        sfu.setFileSizeMax(1024*1024*20);//文件最大为2M
        //3.获取FileItem
        try {
            //FileItem相当于一个input标签的数据
            List<FileItem> items = sfu.parseRequest(request);
            for (FileItem item:items) {
                if(item.isFormField()){//普通数据
                    System.out.println(item.getFieldName() + "---" + item.getString("utf-8"));
                }else {//文件数据
                    System.out.println("文件名:"+ item.getName());
                    System.out.println("文件类型:" + item.getContentType());
                    System.out.println("文件大小:" + item.getSize());
                    System.out.println("文件内容.." +item.getString());

                    //如果是文件,需要把文件保存到本地

                    //1.指定文件保存的目录
                    //添加一个日期目录
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
                    String dateStr = sdf.format(new Date());
                    //保存为日期文件
                    //String path = request.getServletContext().getRealPath("upload/"+dateStr);

                    //把日期转成16进制的字节串
                    String dateHexStr = Integer.toHexString(dateStr.hashCode());
                    String path = request.getServletContext().getRealPath("upload/"+dateHexStr);
                    System.out.println("保存文件的路径:"+path);

                    //2.创建文件夹
                    File dir = new File(path);
                    if(!dir.exists()){
                        dir.mkdirs();
                        System.out.println("创建文件夹了");
                    }else{
                        System.out.println("文件夹已经存在了");
                    }

                    //3.把上传的文件保存
                    //3.1 指定文件保存的名字
                    //后缀名
                    String[] arr = item.getName().split("\\.");
                    String suffix = arr[arr.length-1];
                    //文件名
                    String fileName = UUID.randomUUID().toString()+"."+suffix;

                    //3.2 拼接文件保存路径
                    String fileSavePath = path + "\\" + fileName;
                    System.out.println("保存文件完整路径:"+fileSavePath);

                    //3.3 保存
                    item.write(new File(fileSavePath));
                    item.delete();//删除临时文件
                }

            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }

其中的注意事项如下:

①文件上传保存路径的两种方案

  • 方案一:添加日期目录,方便分类查找
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String dateStr = sdf.format(new Date());
 //保存为日期文件
String path = request.getServletContext().getRealPath("upload/"+dateStr);
  • 方案二:将日期20180808转换成16进制字符串
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String dateStr = sdf.format(new Date());
//把日期转成16进制的字节串
String dateHexStr = Integer.toHexString(dateStr.hashCode());
String path = request.getServletContext().getRealPath("upload/"+dateHexStr);

②文件上传注意的问题

  • 中文乱码问题
    • 表单普通字段乱码用item.getString(“utf-8”);
    • 文件名乱码用SerlvetFileUpload.setHeaderEncoding(“utf-8”);
  • 文件上传大小限制问题
    • 单个文件大小:
      ServletFileUpload.setFileSizeMax(字节)
    • 总文件大小:
      ServletFileUpload.setSizeMax(字节)
  • 临时文件
    DiskFileItemFactoru:
    作用:参数FileItem对象
    内部有一个缓存,缓存大小默认是10Kb。如果上传的文件超过10Kb,用磁盘作为缓存。存放缓存文件的目录在哪里?默认是系统的临时目录。
    如果自己用IO流实现的文件上传,要在流关闭后,清理临时文件。调用FileItem.delete();

1.4 多文件上传

字节设置超过两个及两个的文件上传:
在这里插入图片描述
动态添加文件上传
HTML

<form action="${pageContext.request.contextPath}/UploadServlet" method="post" enctype="multipart/form-data">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <div id="filesDiv">
        <div>文件:<input type="file" name="file"><input type="button" value="删除" onclick="deleteDiv(this)"></div>
    </div>
    <input type="button" value="添加" onclick="addFileUploadDiv()">
    <input type="submit" value="提交">
</form>

JS

    <script>
        function addFileUploadDiv() {
            //1.通过id拿到filesDiv
            var div = document.getElementById("filesDiv");
            div.innerHTML += '<div>文件:<input type="file" name="file"><input type="button" value="删除" οnclick="deleteDiv(this)"></div>'
        }

        function deleteDiv(input) {
            //通过父标签移除子标签
            var div = document.getElementById('filesDiv');
            div.removeChild(input.parentNode);
        }
    </script>

2 文件下载

2.1 文件下载需要设置响应头

  • Content-Disposition
attachment;filename=xx.xx以附件形式下载
  • Content-Type
application/octet-stream二进制流
text/html网页
text/json返回的是一个json格式的字符串

2.2 案例下载代码

/**
 * 文件下载的注意事项
 * 1.设置两个响应头
 * 2.如果文件是中文名,要进行URLEncode
 * 3.通过输入流读取数据,通过输出流response.getOutputStream输出数据给客户端
 *
 * 练习:
 * 通过参数来下载指定文件
 */
@WebServlet("/DownloadServlet")
public class DownloadServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //实现文件的下载
        //1.指定文件的下载路径
        String fileName = "text.txt";
        String path = "C:\\Users\\Yyyz\\Desktop\\test\\"+fileName;

        //2.设置响应头
        //如果是中文文件,要设置URL编码
        fileName = URLEncoder.encode(fileName,"utf-8");
        response.setHeader("Content-Disposition","attachment;filename="+fileName);//以附件的形式下载
        response.setContentType("application/octet-stream");//以二进制的数据返回给客户端

        //3.通过输入输出流将文件下载到客户端
        //通过输入流读数据
        FileInputStream fis = new FileInputStream(new File(path));

        //通过输出流写数据
        ServletOutputStream sos = response.getOutputStream();

        byte[] buf = new byte[1024];
        int len=0;
        while((len=fis.read(buf))!=-1){
            sos.write(buf,0,len);
        }

        //关闭流
        fis.close();
        sos.close();//输出流可以不用关,tomcat会自动关闭。
    }
}

补充:该部分内容来自于java3y(微信公众号)的文件上传和下载

FileUpload的开发步骤:

  • 创建解析器工厂对象【DiskFileItemFactory】
  • 通过解析器工厂创建解析器【ServletFileUpload】
  • 调用解析器方法解析request对象,得到所有上传的内容【list】
  • 遍历list,判断每个对象是否是上传文件
    • 如果是普通表单字段,得到字段名和字段值
    • 如果是上传文件,调用InputSteam方法得到输入流,读取上传的数据
      SmartUpload
      需要导入smartupload.jar
      (由于没有找到完整的jar包,简单了解。)中文乱码时可能没有好的解决方案

文件上传的细节

  • 上传文件的大小以及临时文件需要处理
  • 上传文件的位置不能再web服务器管理之下,不然容易出安全问题
  • 文件名最好独一无二
  • 用户量大了之后,文件会非常巨大,应该将上传的文件分布到不同的目录之下
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值