欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

上传和下载

程序员文章站 2022-03-24 11:37:48
...

1.文件上传原理:将表单的内容以二进制的方式上传到后台,用流的读取和写入.
1.1:表单的上传方式:method=“post”
1.2:表单的以二进制编码方式上传内容:enctype=“multipart/form-data”
1.3:表单上传文件:

2.commons-fileupload:是apach公司开源项目,专门用来实现文件.
2.1:导包:commons-fileupload-1.3.1.jar 和commons-io-2.4.jar
2.2:常用接口和类:
2.2.1:DiskFileItemFactory解析器工厂类
常用方法:
setRepository();//设置上传文件临时仓库
setSizeThreshold();//设置上传临时仓库大小
2.2.2:ServletFileUpload解析器类
常用方法:
isMultipartContent(request) //静态方法,判断请求上传的内容是否是二进制
setFileSizeMax(fileSizeMax);//设置单个文件最大上传大小
setSizeMax(sizeMax);//设置上传总文件的大小
parseRequest(request);//解析上传表单元素
2.2.3:FileItem表单元素类
常用方法:
isFormField();//判断是否是普通表单元素(除了文件域元素)
getFieldName();//获得普通表单name属性名
getString(“utf-8”);//获得普通表单value属性值
getName();//获得上传的文件名
write(上传后的路径+文件名);//文件上传的方法

3.解决文件上传重名:
3.1:UUID+原文件名
3.2:系统时间+原文件名
3.3:UUID+系统时间+原文件名

4.单个文件上传:

  eg:/**
 * 实现common-fileupload上传
 * 1.解决上传文件大小限制
 * 2.限制上传文件类型
 * 3.上传后文件重名
 */
@WebServlet("/UploadServlet1")
public class UploadServlet1 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {

    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        //设置响应内容类型和编码
        response.setContentType("text/html;charset=utf-8");
        //设置请求编码
        request.setCharacterEncoding("utf-8");

        //1.创建解析器工厂对象
        DiskFileItemFactory factory=new DiskFileItemFactory();
        //2.用解析器工厂对象作为参数创建解析器
        ServletFileUpload sfu=new ServletFileUpload(factory);
        //设置单个文件上传的大小
        sfu.setFileSizeMax(1024*20);

        //3.判断表单是否是以二进制的方式上传
        if (ServletFileUpload.isMultipartContent(request)){
            try {
                //4.用解析器对象来解析表单元素
                List<FileItem> fs=sfu.parseRequest(request);
                //5.遍历解析出的表单元素
                for (FileItem f:fs){
                    if (f.isFormField()){//普通表单
                        //获得普通表单的name属性名
                        String fieldName=f.getFieldName();
                        //获得普通表单的value属性值
                        String fieldValue=f.getString("utf-8");
                        System.out.println("name属性名:"+fieldName+",value属性值:"+fieldValue);
                    }else{//文件域表单
                        //获得上传的文件名
                        String fileName=f.getName();
                        //限制上传文件类型
                        if (fileName.endsWith(".jpg")||fileName.endsWith(".png")){
                            //获得上传路径
                            String path=request.getServletContext().getRealPath("upload");


                            //解析文件名上传重名问题
                            //第一种:uuid+"#"+fileName
                            fileName= UUID.randomUUID()+"#"+fileName;
                            //第二种:系统时间+"#"+fileName
                            //fileName=System.nanoTime()+"#"+fileName;
                            //第三种:uuid+系统时间+"#"+fileName00

                            //第四种:根据文件名算出子文件夹名,根据文件名调用hashcode进行位与运算,再右移4,
                            // 作用将文件名调用hash算法进行打散生成子文件夹
                            String childPath=String.valueOf(((fileName.hashCode()&0xf0)>>4));

                            //上传的文件路径
                            File path1=new File(path,childPath);
                            //如果上传的路径不存在就创建目录再上传
                            if (!path1.exists()){
                                path1.mkdirs();
                            }

                            //调用文件上传的方法
                            //f.write(new File(path1,fileName));
                            //用工具类实现文件上传
                            IOUtils.copy(f.getInputStream(),new FileOutputStream(new File(path1,fileName)));

                            response.getWriter().write("上传成功!");
                        }else{
                            response.getWriter().write("你上传的文件类型有误,只支持上传.jpg和.png的文件");
                        }
                    }
                }
            }catch (FileUploadBase.FileSizeLimitExceededException e1){
                response.getWriter().write("你上传的文件的大小超过20K,上传失败!");
            }catch (Exception e) {
                e.printStackTrace();
            }
        }else{
            response.getWriter().write("上传表单编码有误!");
        }
    }
}


5.用commons-fileupload上传完整表单

	eg:/**
 * 带头像的完整表单的注册(上传)
 */
@WebServlet("/UploadServlet2")
public class UploadServlet2 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       //设置编码
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        //1.创建解析器工厂对象
        DiskFileItemFactory factory=new DiskFileItemFactory();
        //2.用解析器工厂对象作为参数创建解析器
        ServletFileUpload sfu=new ServletFileUpload(factory);

        //3.判断整个表单是否是以二进制的方式上传
        if (ServletFileUpload.isMultipartContent(request)){
            //声明一个学生对象,用来接收请求中数据
            Student stu1=new Student();
            //获得上传文件路径
            File path=new File(request.getServletContext().getRealPath("upload"));
            //判断上传的路径是否存在,不存在就创建
            if (!path.exists()){
                path.mkdirs();
            }


            try {
                //获得用户的反射对象
                Class clazz=Class.forName("com.qf.day48.entity.Student");
                //获得表单的name属性名,前提name属性名与用户类中属性名一一对应
                String fieldName=null;
                //获得表单的value属性值或图片上传路径名+文件名
                String fieldValue=null;


                //4.用解析器对象解析上传表单每个表单元素
                List<FileItem> fs=sfu.parseRequest(request);
                for (FileItem f:fs){
                    if (f.isFormField()){//普通表单
                        //获得表单的name属性名,前提name属性名与用户类中属性名一一对应
                        fieldName=f.getFieldName();
                        //获得表单的value属性值
                        fieldValue=f.getString("utf-8");

                    }else{//文件表单
                        //表单name属性值,前提name属性名与用户类中属性名一一对应
                       fieldName=f.getFieldName();
                        //获得上传的文件名
                        String fileName=f.getName();
                        //判断上传文件的格式
                        if (fileName.endsWith(".jpg")||fileName.endsWith(".png")||fileName.endsWith(".gif")){
                            //对文件名处理下,防止重名
                            fileName= UUID.randomUUID()+"#"+fileName;
                            //上传文件
                            f.write(new File(path,fileName));
                            //上传的路径+文件名
                            fieldValue=path.getPath()+File.separator+fileName;
                        }else{
                            response.getWriter().write("上传图像格式有误!");
                        }
                    }

                    //获得当前属性
                    Field field1=clazz.getDeclaredField(fieldName);
                    //设置属性访问权限
                    field1.setAccessible(true);

                    //判断当前对象这个属性是否有值,如果有就拼接
                    if (field1.get(stu1)==null){
                        //用属性反射对象给实例对象设置属性值
                        field1.set(stu1,fieldValue);
                    }else{//防止表单name属性名相同时,value值覆盖
                        //用属性反射对象给实例对象设置属性值
                        field1.set(stu1,field1.get(stu1)+","+fieldValue);
                    }
                }

                System.out.println(stu1);
                //省略将学生对象数据添加到数据步骤
                response.getWriter().write("注册成功");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else{
            response.getWriter().write("上传编码有误!");
        }
    }
}

6.Servlet3.0及以后支持文件上传:将表单以多部分上传的.
注意::Part类代表从 multipart/form-data格式的 POST请求中接收到的一个部分或表 单项。每个 part都可 通过 Part.getInputStream方法访问头部,相关的内容 类型和内容。
对于表单数据的 Content-Disposition,即使没有文件名,也可使用 part 的名 称通过HttpServletRequest 的 getParameter和 getParameterValues方法得 到 part的字符值。
6.1:Servlet3.0实现上传多个文件.

	eg:/**
 * Sevlet3.0上传,支持将表单以多部分上传,每个部分part
 * 1.对上传的文件作大小限制
 * 2.对上传的文件作类型限制
 * 3.解决上传的文件的重名
 */
@WebServlet("/UploadServlet3")
@MultipartConfig()//支持表单上传
public class UploadServlet3 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置编码
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        //获得上传的路径
        File path=new File(request.getServletContext().getRealPath("upload"));
        if (!path.exists()){
            path.mkdirs();
        }

        //接收表单上传的多部分
        Collection<Part> parts=request.getParts();
        //遍历上传的每个部分(一个表单项)
        for (Part p:parts){
            //判断每个上传的部分有没有超过上传的大小限制
            if(p.getSize()>1024*20){
                response.getWriter().write("你上传的文件超过20K,上传失败<br/>");
                continue;
            }

            //获得上传头部
            String headContent= p.getHeader("Content-Disposition");

            //从上传的头部获得文件名
            String fileName=headContent.substring(headContent.lastIndexOf("=")+2,headContent.length()-1);
            System.out.println("****"+fileName);

            //判断上传的文件类型
            if (fileName.endsWith(".jpg")||fileName.endsWith(".png")){
                //防止上传的文件重名
                fileName= UUID.randomUUID()+"#"+fileName;

                //上传文件
                p.write(path.getPath()+File.separator+fileName);
                response.getWriter().write("上传成功!<br/>");
            }else{
                response.getWriter().write("上传文件类型有误,上传失败!<br/>");
            }
        }
    }
}

6.2:Servlet3.0上传完整的表单,包括文件

	eg:/**
 * 用servlet3.0来实现上传整个表单,将表单的每个表单项以part方式提交
 */
@WebServlet("/UploadServlet4")
@MultipartConfig()//注解表示要Servlet3.0进行上传
public class UploadServlet4 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //统一设置编码
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        //获得上传路径
        File path=new File(request.getServletContext().getRealPath("upload"));
        if (!path.exists()){
            path.mkdirs();
        }

        //声明用户对象,用来存数据
        Student stu2=new Student();

        try {
            /*1.上传三个图像文件,并将图像上传地址存在用户对象中*/
            //上传,并得到上传路径+文件名
            		String img1Path = fileUpload1("img1", path, request,response);
            //将当前路径路径+文件名存在学生对象中
            		stu2.setImg1(img1Path);

            //上传,并得到上传路径+文件名
            		String img2Path=fileUpload1("img2",path, request,response);
            //将当前路径路径+文件名存在学生对象中
            		stu2.setImg2(img2Path);

            //上传,并得到上传路径+文件名
            		String img3Path=fileUpload1("img3",path, request,response);
            //将当前路径路径+文件名存在学生对象中
            		stu2.setImg3(img3Path);

            /*2.获得上传普通表单的值*/              
            stu2.setName(request.getParameter("name"));
            stu2.setPassword(request.getParameter("password"));
            stu2.setCity(request.getParameter("city"));
            stu2.setEmail(request.getParameter("email"));
            stu2.setSex(request.getParameter("sex"));
            stu2.setHobby(Arrays.toString(request.getParameterValues("hobby")));

            System.out.println("###"+stu2);
            //省略业务层和dao层对数据库的操作
            response.getWriter().write("注册成功!");

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

    /**
     * 获得每个上传的部分实现文件上传
     * @param name
     * @param path
     * @param response
     * @throws Exception
     * @return String 上传后的文件路径名+文件名
     */
    public String fileUpload1(String name,File path,HttpServletRequest request,HttpServletResponse response) throws Exception {
        //通过name名称获得指定部分
        Part p = request.getPart(name);
        //判断每个上传文件的大小
        if (p.getSize()>1024*20) {
            response.getWriter().write("上传的头像超过20K,上传失败<br/>");
            return null;
        }else {
            //获得当前这部分上传的头部信息
            String headContent=p.getHeader("Content-Disposition");
            System.out.println("headContent:"+headContent+","+p.getName());

            //获得当前这部分上传的文件名
            String fileName=headContent.substring(headContent.lastIndexOf("=")+2,headContent.length()-1);
            if (fileName.endsWith(".jpg")||fileName.endsWith(".png")||fileName.endsWith(".gif")){
                //防止文件重名
                fileName= UUID.randomUUID()+"#"+fileName;
                //上传
                p.write(path.getPath()+File.separator+fileName);
                response.getWriter().write("上传成功");

                //将上传图像路径及文件名存在学生对象中
                return path.getPath()+File.separator+fileName;
            }else{
                response.getWriter().write("上传的头像格式有误,上传失败");
                return null;
            }
        }
    }
}

7.文件下载
7.1:图片下载:选中图片右键另存为->保存到指定路径.
7.2:文件/压缩包下载:

<a href="upload/常用图片.zip">常用图片.zip</a>
<a href="upload/48.2单个文件上传的限制.mp4">48.2单个文件上传的限制.mp4</a>

7.3:中文名文件下载:原理流的读写

	eg:<a href="DownloadServlet?fileName=刚哥.txt">刚哥.txt</a>

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //设置响应内容类型和编码
    response.setContentType("text/html;charset=utf-8");
    //设置请求编码
    request.setCharacterEncoding("utf-8");

    //获得下载的文件名
    String fileName=request.getParameter("fileName");
    //获得下载的文件路径
    String path=request.getServletContext().getRealPath("upload");

    //设置响应头部信息,如果文件名是中文,浏览器会解码,为了抵消浏览器的解码,我先编码
    response.setHeader("Content-Disposition","attachment;fileName="+ URLEncoder.encode(fileName,"utf-8"));

    //下载的本质将文件从服务器端读取,写入给客户端
    IOUtils.copy(new FileInputStream(path+ File.separator+fileName),response.getOutputStream());
}