• 文件上传和下载


      基本的文件上传:

        最基本的文件上传是在不利用其它额外jar包的帮助下,实现上传,这就是其它jar包封装的基础。

        我们在文件上传的时候大多都是利用表单里面的input标签,input标签里面有个type为file,就是定义了一个上传文件的输入框,现在我们要了解的是form表单的enctype属性,这个属性决定的是表单发到服务器之前如何对数据进行编码。

        enctype属性有三个值可取:

          1.application/x-www-form-urlencoded,是表单该属性的默认值,意思是发到服务器之前对所有的数据进行编码。

          2.multipart/form-data,意思是不对字符进行编码,如果你要上传文件,必须用这个值。

          3.text/plain,意思空格转换为 "+" 加号,但不对特殊字符编码。

    下面我们写个简单的html文件,定义一个表单,用input标签进行文件上传:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <title>file.html</title>
        
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="this is my page">
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      </head>
      <body>
        <form action="dealFile.jsp" enctype="multipart/form-data" method="post">
            上传文件:<input type="file" name="file" /><br>
            姓名:<input type="text" name="name" /><br>
            <input type="submit" value="提交"/>
        </form>
      </body>
    </html>

        我们都知道,表单的数据是通过http协议传给服务器的,所以服务器的处理也是从http协议中获取数据,对其进行解析,request对象中有一个getInputStream方法,这个方法可以得到一个输入流,从这个流中我们就可以读取到文件的内容,当然也包括其他表单附带的数据:

    dealFile.jsp:

    <%@ page language="java" import="java.util.*, java.io.*" pageEncoding="UTF-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'dealFile.jsp' starting page</title>
        
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
      </head>
      <body>
        <% 
            request.setCharacterEncoding("UTF-8");
            InputStream is = request.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            String buffer = null;
            out.println(buffer == null);
            while((buffer = br.readLine()) != null) {
                out.println(buffer + "<br>");
            }
        %>
      </body>
    </html>

      下面介绍使用Common-FileUpload框架进行上传,首先你必须引进两个jar包,一个是Commons-FileUpload.jar和Commons-io.jar,这两个jar包百度都可以搜索到:

      我们使用的还是上面的file.html,把它的action改为dealFileByFU.jsp:

    dealFileByFU.jsp:

    <%@page import="org.apache.commons.fileupload.FileItem"%>
    <%@page import="org.apache.commons.fileupload.servlet.ServletFileUpload"%>
    <%@page import="org.apache.commons.fileupload.disk.DiskFileItemFactory"%>
    <%@ page language="java" import="java.util.*, java.io.*" pageEncoding="UTF-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'dealFile.jsp' starting page</title>
        
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <!--
        <link rel="stylesheet" type="text/css" href="styles.css">
        -->
    
      </head>
      
      <body>
        <% 
            //定义上传工厂
            DiskFileItemFactory factory = new DiskFileItemFactory();
            //设置工厂的大小限制
            factory.setSizeThreshold(1024*1024*20);
            //设置文件的存放路径
            factory.setRepository(new File(request.getRealPath("/")));
            //根据工厂创建一个上传文件的ServletFileUpload对象
            ServletFileUpload upload = new ServletFileUpload(factory);
            //设置最大的上传限制
            upload.setSizeMax(1024*1024*20);
            //根绝request对其进行解析,items是所有的表单项
            List items = upload.parseRequest(request);
            //遍历所有的表单项
            for(Iterator it = items.iterator(); it.hasNext();) {
                FileItem item = (FileItem)it.next();
                //判断是普通的表单域还是上传文件域
                if(item.isFormField()) {
                    //拿到对应的字段名和值
                    String name = item.getFieldName();
                    String value = item.getString("UTF-8");
                    out.print(name + " = " + value);
                } else {
                    //拿到字段名
                    String fieldName = item.getFieldName();
                    //拿到文件名
                    String fileName = item.getName();
                    //拿到文件类型
                    String contentType = item.getContentType();
                    //命名文件名
                    FileOutputStream fos = new FileOutputStream(request.getRealPath("/")
                            + System.currentTimeMillis() + 
                            fileName.substring(fileName.lastIndexOf("."), fileName.length()));
                    //判断内存中是否有该文件
                    if(item.isInMemory()) {
                        fos.write(item.get());
                    } else {
                        InputStream is = item.getInputStream();
                        byte[] buffer = new byte[1024];
                        int len;
                        while((len = is.read(buffer)) > 0) {
                            fos.write(buffer, 0, len);
                        }
                        is.close();
                        fos.close();
                    }
                }
            }
        %>
      </body>
    </html>

       接下来介绍的是另外一个小框架COS进行上传,首先我们同样要引入cos.jar包,COS的核心类是MultipartParser,该类用于解析HttpServletRequest请求,取出所有的表单域,每个表单域对应一个Part示例,通过这个Part我们就可以判断这个域是普通的表单域还是文件域。

    dealFileByCOS.jsp:

    <%@page import="com.oreilly.servlet.multipart.FilePart"%>
    <%@page import="com.oreilly.servlet.multipart.ParamPart"%>
    <%@page import="com.oreilly.servlet.multipart.Part"%>
    <%@page import="com.oreilly.servlet.multipart.MultipartParser"%>
    <%@ page language="java" import="java.util.*, java.io.*" pageEncoding="UTF-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'dealFile.jsp' starting page</title>
        
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <!--
        <link rel="stylesheet" type="text/css" href="styles.css">
        -->
    
      </head>
      
      <body>
        <% 
            //使用MultipartParser解析request并且设置最大容量为10M
            MultipartParser mp = new MultipartParser(request, 10*1024*1024);
            //一个part就代表着一个表单域
            Part part;
            while((part = mp.readNextPart()) != null) {
                //取得所有表单域的name的属性值
                String name = part.getName();]
                //判断是普通的表单域还是文件域
                if(part.isParam()) {
                    //强制转化为普通的表单域
                    ParamPart paramPart = (ParamPart)part;
                    String value = paramPart.getStringValue("UTF-8");
                    out.println("Parm: " + name + " = " + value);
                    //String value = paramPart.
                } else if(part.isFile()) {
                    //强制转化为普通的文件域
                    FilePart filePart = (FilePart)part;
                    String fileName = filePart.getFileName();
                    if(fileName != null) {
                        //写进文件中
                        FileOutputStream fos = new FileOutputStream(request.getRealPath("/")
                                + System.currentTimeMillis() + 
                                fileName.substring(fileName.lastIndexOf("."), fileName.length()));
                        InputStream is = filePart.getInputStream();
                        byte[] buffer = new byte[1024];
                        int len;
                        while((len = is.read(buffer)) > 0) {
                            fos.write(buffer, 0, len);
                        }
                        is.close();
                        fos.close();
                    }
                } else {
                    out.println("file : name " + name);
                }
                out.flush();
            }
        %>
      </body>
    </html>

      下面介绍Struts2的文件上传,使用Struts框架进行解析,更加的方便,因为里面已经为我们封装好了实现,但是我们千万不要以为Struts里面的全部上传文件都是自己实现的,它里面也是使用小框架实现的,只是它做了更近一步的封装。

      在Struts2的default.properties配置文件中,我们可以看到:

      所以我们可以发现你导入struts2的jar包的时候是需要导入commons-io.jar和common-fileupload.jar的,struts2默认是使用FileUpload框架。

      下面我们写一个action对应我们的表单域:

    package com.xujianguo.action;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    
    import org.apache.struts2.ServletActionContext;
    
    import com.opensymphony.xwork2.ActionSupport;
    
    @SuppressWarnings("all")
    public class FileUpload extends ActionSupport {
        private String name;
        private File upload;
        private String uploadContentType;
        private String uploadFileName;
        private String savePath;
        
        public String execute() throws Exception {
            FileOutputStream fos = new FileOutputStream(getSavePath() + "\" + getUploadFileName());
            FileInputStream fis = new FileInputStream(getUpload());
            byte[] buffer = new byte[1024];
            int len = 0;
            while((len = fis.read(buffer)) > 0) {
                fos.write(buffer, 0, len);
            }
            return SUCCESS;
        }
        
        public void setSavePath(String value) {
            this.savePath = value;
        }
        
        public String getSavePath() {
            return ServletActionContext.getRequest().getRealPath(savePath);
        }
        
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name= name;
        }
        
        public File getUpload() {
            return upload;
        }
        
        public void setUpload(File upload) {
            this.upload = upload;
        }
    
        public String getUploadContentType() {
            return uploadContentType;
        }
    
        public void setUploadContentType(String uploadContentType) {
            this.uploadContentType = uploadContentType;
        }
    
        public String getUploadFileName() {
            return uploadFileName;
        }
    
        public void setUploadFileName(String uploadFileName) {
            this.uploadFileName = uploadFileName;
        }
    }

       这里必须提醒的是:File类型的变量是对应的表单中input类型为file的name属性的值,其他属性如uploadFileName和uploadContentType都是以它为基础的。

    struts.xml中的action配置:

    <action name="upload" class="com.xujianguo.action.FileUpload">
        <param name="savePath">/upload</param>
        <result name="success">/showFile.jsp</result>
    </action>

     showFile.jsp:

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%@ taglib prefix="s" uri="/struts-tags" %>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'index.jsp' starting page</title>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <!--
        <link rel="stylesheet" type="text/css" href="styles.css">
        -->
      </head>
      
      <body>
            上传成功<br>
            姓名:<s:property value="name"/><br>
            文件为:<img src="<s:property value="'upload/' + uploadFileName" />"/>
      </body>
    </html>

       使用拦截器实现文件过滤:

        Struts2提供了一个文件上传的拦截器-fileUpload,为了让该拦截器起作用,只需要要action中配置一下就ok了,它有两个参数:

          allowedTypes:该参数指定允许上传文件的类型

          maximumSize:该参数指定上传文件的大小,单位为字节。

    struts.xml配置:

    <action name="upload" class="com.xujianguo.action.FileUpload">
                <interceptor-ref name="fileUpload">
                    <param name="allowedTypes">image/bmp,image/png,image/gif,image/jpeg</param>
                    <param name="maximumSize">200000</param>
                </interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref>
                <param name="savePath">/upload</param>
                <result name="success">/showFile.jsp</result>
                <result name="input">/file.html</result>
    </action>

      Struts2多文件上传:

        其实多文件上传跟单文件上传是同样的道理,只是你的Action方面就不能单用一个File类型去接受多个文件了,我们可以改成List<File>对应去存储文件,修改后的文件为:

    package com.xujianguo.action;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.util.List;
    
    import org.apache.struts2.ServletActionContext;
    
    import com.opensymphony.xwork2.ActionSupport;
    
    @SuppressWarnings("all")
    public class MultiFileUpload extends ActionSupport {
        private String name;
        private List<File> upload;
        private List<String> uploadContentType;
        private List<String> uploadFileName;
        private String savePath;
        
        public String execute() throws Exception {
            List<File> files = getUpload();
            for(int i = 0; i < files.size(); i++) {
                FileOutputStream fos = new FileOutputStream(getSavePath() + "\" + getUploadFileName().get(i));
                FileInputStream fis = new FileInputStream(files.get(i));
                byte[] buffer = new byte[1024];
                int len = 0;
                while((len = fis.read(buffer)) > 0) {
                    fos.write(buffer, 0, len);
                }
            }
            return SUCCESS;
        }
        
        public void setSavePath(String value) {
            this.savePath = value;
        }
        
        public String getSavePath() {
            return ServletActionContext.getRequest().getRealPath(savePath);
        }
        
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name= name;
        }
    
        public List<File> getUpload() {
            return upload;
        }
    
        public void setUpload(List<File> upload) {
            this.upload = upload;
        }
    
        public List<String> getUploadContentType() {
            return uploadContentType;
        }
    
        public void setUploadContentType(List<String> uploadContentType) {
            this.uploadContentType = uploadContentType;
        }
    
        public List<String> getUploadFileName() {
            return uploadFileName;
        }
    
        public void setUploadFileName(List<String> uploadFileName) {
            this.uploadFileName = uploadFileName;
        }
    }

      其他方面跟单文件的一致,哈哈,是不是很简单呢,不要给多文件吓到了。

      Struts2的文件下载:

        文件下载也是很简单的,我们简单的演示一下,首先是前端的页面:

    <a href="/Struts2Demo/guo/download.action">图片下载</a>

         前端最核心的就是这一句,访问action,让Struts去处理诸如文件名为中文之类的麻烦问题,接下来就是要配制我们的struts.xml:

            <action name="download" class="com.xujianguo.action.DownloadFile">
                <result name="success" type="stream">
                    <param name="contentType">image/png</param>
                    <param name="contentDisposition">attachment;filename="Snap1.png"</param>
                    <param name="inputName">input</param>
                </result>
            </action>

        我们一一来看里面的属性:

          stream:如果你的要实现文件下载,就必须使用type为stream的result,就是使用一个流。

          contentType:指定你下载文件的类型,我这里是image,如果你要的是文本的话就使用text/plain。

          contentDisposition:这里指定的是文件名和文件的下载方式,我使用的附件的形式,也就是attachment。

          inputName:指定你对应action里面的类型为InputStream的属性,指定的文件的流的获取。

        DownloadFile.java:

    package com.xujianguo.action;
    
    import java.io.InputStream;
    
    import org.apache.struts2.ServletActionContext;
    
    import com.opensymphony.xwork2.ActionSupport;
    
    @SuppressWarnings("serial")
    public class DownloadFile extends ActionSupport {
        public InputStream input;
        
        public InputStream getInput() {
            return ServletActionContext.getServletContext().getResourceAsStream("/upload/Snap1.png");
        }
        
        public void setInput(InputStream input) {
            this.input = input;
        }
        
        public String execute() {
            return SUCCESS;
        }
    }
  • 相关阅读:
    【算法系列学习】Dijkstra求最短路 [kuangbin带你飞]专题四 最短路练习 D
    【算法系列学习】Dijkstra算法变形 [kuangbin带你飞]专题四 最短路练习
    【算法系列学习】Dijkstra单源最短路 [kuangbin带你飞]专题四 最短路练习 A
    【算法系列学习】[kuangbin带你飞]专题十二 基础DP1 G
    【算法系列学习】[kuangbin带你飞]专题十二 基础DP1 F
    【算法系列学习】[kuangbin带你飞]专题十二 基础DP1 E
    【算法系列学习】状压dp [kuangbin带你飞]专题十二 基础DP1 D
    【算法系列学习】[kuangbin带你飞]专题十二 基础DP1 C
    【算法系列学习】[kuangbin带你飞]专题十二 基础DP1 B
    【算法系列学习】DP和滚动数组 [kuangbin带你飞]专题十二 基础DP1 A
  • 原文地址:https://www.cnblogs.com/rayguo/p/3634497.html
Copyright © 2020-2023  润新知