• JavaWeb中文件上传与下载


    JavaWeb中文件上传与下载

    一、文件上传

    1.文件上传的应用

    比如个人信息的管理,上传头像
    比如商品信息的管理,上传商品的图片
    这些都需要通过浏览器客户端将图片上传到服务器的磁盘上

    文件上传原理
    所谓的文件上传就是服务器端通过request对象获取输入流,将浏览器端上传的数据读取出来,保存到服务器端

    2.客户端浏览器注意事项

    1.请求方式必须是 post
    2.需要使用组件
    3.表单必须设置enctype=“multipart/form-data”

    3.服务器端处理

    通过request对象,获取InputStream, 可以将浏览器提交的所有数据读取到.

    4.上传开源框架-commons-upload

    Apache 开源组织提供了一个用来处理表单文件上传的一个开源组件( Commons-fileupload ),该组件性能优异,并且其API使用极其简单,可以让开发人员轻松实现web文件上传功能,因此在web开发中实现文件上传功能,通常使用Commons-fileupload组件实现。

    使用Commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:Commons-fileupload和commons-io,
    commons-io 不属于文件上传组件的开发jar文件,但Commons-fileupload 组件从1.1 版本开始,它工作时需要commons-io包的支持

    5.文件上传案例

    在浏览器端创建一个可以上传文件的表单,在服务器端通过commons-fileupload完成文件上传。
    浏览器端注意三件事情:
    1.表单的method=post
    2.设置enctype=multipart/form-date
    3.使用具有name属性的file元素
    在服务器端
    1.创建DiskFileItemFactory
    2.创建ServletFileUpload
    3.通过ServletFileUpload的parseRequest方法得到所有的FileItem

    1.设置浏览器端

    • 1
    • 2
    • 3
    • 4

    2.在服务器端操作

    关键类:
    DiskFileItemFactory:ServletFileUpload工厂类
    ServletFileUpload:用于处理文件上传的类
    IOUtils:文件上传IO流类
    BeanUtils:存储表单内文本信息类

    //设置乱码
    upload.setHeaderEncoding(“UTF-8”);

    //ServletFileUpload工厂类
    DiskFileItemFactory factory = new DiskFileItemFactory();
    //处理文件上传的类
    ServletFileUpload upload = new ServletFileUpload(factory);
    try {
    //获得表带内容
    	List<FileItem> items = upload.parseRequest(request);
    		for(FileItem fileItem : items) {
    			if(!fileItem.isFormField()){//判断非文本信息
    			FileOutputStream fos = new 							  									FileOutputStream("C:\\test.jpg");
    			IOUtils.copy(fileItem.getInputStream(),fos);//拷贝
    			fos.close();
    			}
    		}
    } catch (FileUploadException e) {
    e.printStackTrace();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    完善细节
    1.设置保存上传文件的服务器目录

    DiskFileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload upload = new ServletFileUpload(factory);
    try {
    	List items = upload.parseRequest(request);
    	for(FileItem fileItem : items) {
    		if(!fileItem.isFormField()){
    			//获取项目在当前系统下的路径+"upload"
    			String path = this.getServletContext().getRealPath("Nupload");
    			File dir = new File(path);
    			if(!dir.exists())){/判断文件夹是否存在
    			dir.mkdirs();
    		}
    		String filename = fileItem.getName();//获得当前上传文件的名字
    		FileOutputStream fos = new FileOutputStream(new File(dir,filename));
    		IOUtils.copy(fileItem.getInputStream(),fos);fos.close();1
    } catch (FileUploadException e) {
    	e.printStackTrace();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.解决上传文件名是中文的问题,通过item.getName()获取到文件的名称

    a)直接将其改名,不用原来的名字
    b)保存其中文的名字(注意,一般如果是压缩文件供下载的资源,则可以考虑保留其中文名称,否则一般图片直接展示用的,不建议用中文名来保存)

    思考题:文件名重复了怎么办?
    问题:覆盖
    解决方案:
    客户端参与
    方案一:做个文件名的唯一性校验,告诉客户端,这个文件名已经存在(不建议)
    服务端解决
    方案二:重新取个名字(唯一性:时间、UUID)—图片资源
    利用时间保证唯一性:System.currentTimeMillis()

    6.利用UUID保证唯一性

    DiskFileItemFactory factory = new DiskFileItemFactory();
    ServletFileUpload upload = new ServletFileUpload(factory);
    try {
    	List items = upload.parseRequest(request);
    	for(FileItem fileItem : items) {
    		if(!fileItem.isFormField())[
    			//获取项目在当前系统下的路径+"upload"
    			String path = this.getServletContext().getRealPath("\\upload");
    			File dir = new File(path);
    			if(!dir.exists()){//判断文件夹是否存在
    			dir.mkdirs();
    			}
    		UUID randomUUID = UUID.randomUUID();
    		String filename = randomUUID + "_" + fileItem.getName();//获得当前上传文件的名字			FileOutputStream fos = new FileOutputStream(new File(dir,filename));
    		IOUtils.copy(fileItem.getInputStream(),fos);
    		fos.close();
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2,方案三:下载电影压缩包,水野朝阳.zip 保留原有的名字

    for(FileItem fileItem : items) {
    	if(!fileItem.isFormField()){
    	//获取项目在当前系统下的路径+"upload"
    	String path = this.getServletContext().getRealPath("\\upload");
    	File dir = new File(path);
    	if(!dir.exists()){//判断文件夹是否存在
    	dir.mkdirs();
    }
    	//在原来路径的基础上添加时间路径,做到图片不覆盖的效果
    	Date date = new Date();
    	SimpleDateFormat sdf = new SimpleDateFormat("yyyy/M/dd/hhmmss");
    	String datePath = sdf.format(date);File uploadDir = new File(dir,datePath);
    	if(!uploadDir.exists())[
    		uploadDir.mkdirs();
    	}
    	String filename = fileItem.getName());//获得当前上传文件的名字
    	FileOutputStream fos = new FileOutputStream(new File(uploadDir,filename));
    	IOUtils.copy(fileItem.getInputStream(),fos);fos.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    7.获取完整的表单数据

    保存一个完整的表单信息,除了将文件上传到服务器以外,还需要将其他表单项信息保存到对象,并存储到数据中心,而对应的图片信息则保存为保存的路径即可。
    那么怎么获取到其他的表单项数据?item.getFileName(),item.getString()
    为了更好完成对其他表单项的值的获取,需要借助另一个开源框架 BeanUtils
    它除了自身的jar包,还依赖于commons-logging.jar

    //创建一个Map来存储普通的表单项数据
    Mapmap = new HashMap<>();
    //创建一个对象来存储各项数据
    Book book = new Book();
    	for(FileItem item : list){
    		if(item.isFormField()){
    		//普通表单项
    		//System.out.println(item.getFieldName()+":"+item.getString("utf-8"));//实现一个通用的方法来将对应的参数都赋值到对象上
    		map.put(item.getFieldName(),item.getString("utf-8"));
    		}else{
    			//上传文件//创建上传的目录
    			File dir = new File(this.getServletContext().getRealPath("/upload"));
    			if(!dir.exists()){
    			dir.mkdirs();
    			}
    			//设置文件名的唯一性
    			String fileName = item.getName();
    			fileName = FilenameUtils.getName(fileName);
    			fileName = UUID.randomUUID()+"_"+fileName;//上传文件
    		FileOutputStream outputStream = new FileOutputStream(new File(dir, fileName));
    		IOUtils.copy(item.getInputStream(),outputStream);
    		book.setImgUrl("upload"+File.separator+fileName);
    		outputStream.close();
    		}
    		item.delete();
    	}
    		BeanUtils.populate(book,map);
    }		
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    细节:
    有复选框的情况怎么办?

    String name = fileItem.getFieldName();
    String value = fileItem.getString("UTF-8");
    	if(map.get(name) == null){
    		map. put(name, value);
    		}else{
    			map.put(name, map.get(name)+"," + value);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    8.多文件上传案例

    实现多文件的批量上传

    • 1
    • 2
    • 3
    • 4
    • 5

    Ps:展示图片-“upload” + File.separator + datePath + File.separator + filename);

    二、文件下载

    主要实现方式有两种
    1.超链接下载
    2.以超练级的方式下载压缩文件
    3.以超链接的方式下载图片文件
    4.以超链接的方式下载中文文件名的文件
    5.Servlet下载

    有些超链接搞不定的事情就交给Servlet来搞定

    下载photo.zip
    下载pipixia.jpg
    下载头像.zip
    
    
    • 1
    • 2
    • 3
    • 4

    采用流的方式来读和写

    设置响应的头部信息(告诉客户端是以附件的形式下载)
    response.setHeader(“Content-disposition”, “attachment;fileName=”+fileName);
    细节:
    下载的文件名是中文怎么办?

    String realPath = this.getServletContext().getRealPath("download\\头像.zip");
    String fileName = realPath.substring(realPath.lastIndexof(")+1);
    fileName = URLEncoder.encode(fileName,"UTF-8");
    response.setHeader("Content-disposition","attachment;fileName="+fileName);
    FileInputStream fis = new FileInputStream(realPath);
    ServletOutputStream outputStream = response.getOutputStream();
    byte[] b = new byte[1024];
    int len = 0
    while((len = fis.read(b)) != -1){
    	outputStream.write(b,0,len);
    }
    fis.close();
    outputStream.close();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    三、上传与下载

    1.上传

    import javax.servlet.ServletException;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.Part;
    import java.io.IOException;
    
    @WebServlet(urlPatterns = "/upload")
    @MultipartConfig(fileSizeThreshold = 1024*100,maxFileSize = 1024*1024*5,maxRequestSize = 1024*1024*25)
    public class UploadServlet extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String bookName=   request.getParameter("bookName");
            System.out.println("bookName:"+bookName);
            Part part= request.getPart("bookPic");
            String filename= part.getSubmittedFileName();
            String path="/WEB-INF/upload/"+filename;
            // 把逻辑路径转成物理路径
            // 绝对路径 相对路径不一样的
            path=request.getServletContext().getRealPath(path);
            System.out.println(path);
            part.write(path);
            response.getWriter().print(filename+"上传成功");
    
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    2.下载

    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.*;
    
    @WebServlet(urlPatterns = "/download")
    public class DownloadServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          String filename="ggc.docx";
            String path="/WEB-INF/upload/"+filename;
            path=request.getServletContext().getRealPath(path);
            File file=new File(path);
            //准备好了输入流
            InputStream inputStream=new FileInputStream(file);
            response.setHeader("Content-Disposition", "attachment;filename="+filename);
            //浏览器端的输出流
           OutputStream outputStream= response.getOutputStream();
           byte[] datas=new byte[1024];
           int len=0;
           while( (len =inputStream.read(datas))>0){
               outputStream.write(datas,0,len);
           }
           outputStream.close();
           inputStream.close();
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    3.前端

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>文件上传title>
    head>
    <body>
    <form name="frmupload" action="/upload" method="post" enctype="multipart/form-data">
        书名:<input name="bookName" type="text"/><br/>
       附件: <input name="bookPic" type="file"/><br/>
        <input name="btnAdd" type="submit" value="保存"/>
    form>
    body>
    html>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    Hudi数据湖技术引领大数据新风口(三)解决spark模块依赖冲突
    【Linux修炼】5.vim详解
    显示控件——图标类之滑动刻度指示
    用HttpURLConnection来实现retrofit类似功能(由于retrofit不支持5.0以下)
    Unity的IPostprocessBuild:深入解析与实用案例
    遍历map的四种方法及Map.entry详解
    非计算机小白成功转型Python教学分析师,月薪2W后,我的学习经验总结!
    16-CSS3
    docker run 命令详解(新手入门必备)
    Kubernetes(k3s)基础学习(三) -- Deployment、Service、Ingress
  • 原文地址:https://blog.csdn.net/GL280599ZL/article/details/128159267