zoukankan      html  css  js  c++  java
  • tomcat实现文件上传下载

    实现下载
    修改server.xml
    修改web.xml
     

    实现上传
    实现客户端的上传
    post请求
    代码实现

    实现服务端的处理
     

    小结
     
     
     
     
    实现下载
    实现下载需要
     - 修改Tomcat中的server.xml
     - 修改web.xml
     
    修改server.xml
    在<Host> </Host>中加入(一般在文件末尾可以找到)
     
    <Context docBase="C://Download" path="/download" reloadable="true" />1
    其中docBase项是本地目录,path项是访问目录
     
    修改web.xml
     
       <servlet>
            <servlet-name>default</servlet-name>
            <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
            <init-param>
                <param-name>debug</param-name>
                <param-value>0</param-value>
            </init-param>
            <init-param>
                <param-name>listings</param-name>
                <param-value>true</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>12345678910111213
    其中listings下确保值是true
    这时在C://Download下存放文件,并打开相应的地址,就能看见文件目录了
     
    实现上传
    实现上传也是分两步

    实现客户端的上传
    实现服务端的处理
     

    实现客户端的上传
     
    post请求
    我们都知道http常用的请求方式有get、post等,其中我们实现文件上传,就是模拟表单采用post方式上传文件
    首先来看一下post报文的格式,以上传一张图片为例
     
    POST/logsys/home/uploadIspeedLog!doDefault.html HTTP/1.1
    Accept: text/plain, */*
    Accept-Language: zh-cn
    Host: 192.168.24.56
    Content-Type:multipart/form-data;boundary=【这里随意设置】
    User-Agent: WinHttpClient
    Content-Length: 3693
    Connection: Keep-Alive123456789
    以上部分是请求的参数,不需要我们完全实现,通过方法传参的方式自动构建
     
    --【这里随意设置】
    Content-Disposition: form-data;name="file1";filename="C://E//a.png"
    Content-Type:application/octet-stream

    <文件的二进制信息>
    --【这里随意设置】--1234567
    这一部分是报文的内容,需要我们通过字符串或者字节流自行拼接,并且格式不能出错

      注意,三处【这里随意设置】的部分必须完全相同
     

    代码实现
     
    public static void uploadFile(String fileName) { 
        try { 
            // 换行符 
            final String newLine = " "; 
            //数据分隔线 
            final String BOUNDARY = "【这里随意设置】";//可以随意设置,一般是用  ---------------加一堆随机字符
            //文件结束标识
            final String boundaryPrefix = "--"; 
            // 服务器的域名 
            URL url = new URL("http://localhost:8070/secondary/HandleFile"); 
            HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
            // 设置为POST情 
            conn.setRequestMethod("POST"); 
            // 发送POST请求必须设置如下两行 
            conn.setDoOutput(true); 
            //conn.setDoInput(true);/不必加,默认为true 
            //conn.setUseCaches(false);//用于设置缓存,默认为true,不改也没有影响(至少在传输单个文件这里没有) 
            // 设置请求头参数 
            //关于keep-alive的说明:https://www.kafan.cn/edu/5110681.html
            //conn.setRequestProperty("connection", "Keep-Alive");//现在的默认设置一般即为keep-Alive,因此此项为强调用,可以不加
            //conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows Nt 5.1; SV1)");//用于模拟浏览器,非必须
            //用于表示上传形式,必须
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); 
            //这里是Charset,网上大多都是Charsert???我的天,笑哭。不过好像没什么影响...不知道哪位大佬解释一下
            conn.setRequestProperty("Charset", "UTF-8");
            //获取conn的输出流用于向服务器输出信息
            OutputStream out = new DataOutputStream(conn.getOutputStream()); 
            //构造文件的结构 
            //写参数头
            StringBuilder sb = new StringBuilder(); 
            sb.append(boundaryPrefix)//表示报文开始
              .append(BOUNDARY)//添加文件分界线
              .append(newLine);//换行,换行方式必须严格约束
            //固定格式,其中name的参数名可以随意修改,只需要在后台有相应的识别就可以,filename填你想要被后台识别的文件名,可以包含路径
            sb.append("Content-Disposition: form-data;name="file";")
                .append("filename="").append(fileName)
                .append(""")
                .append(newLine); 
            sb.append("Content-Type:application/octet-stream"); 
            //换行,为必须格式
            sb.append(newLine); 
            sb.append(newLine); 
            //将参数头的数据写入到输出流中 
            out.write(sb.toString().getBytes()); 
            System.out.print(sb);
            //写文件数据(通过数据输入流) 
            File file = new File(fileName);
            DataInputStream in = new DataInputStream(new FileInputStream( 
                    file)); 
            byte[] bufferOut = new byte[1024]; 
            int bytes = 0; 
            //每次读1KB数据,并且将文件数据写入到输出流中 
            while ((bytes = in.read(bufferOut)) != -1) { 
                out.write(bufferOut, 0, bytes); 
            } 
            in.close();
            //写参数尾 
            out.write(newLine.getBytes()); 
            System.out.print(new String(newLine.getBytes()));
            // 定义最后数据分隔线,即--加上BOUNDARY再加上--。
            sb = new StringBuilder();
            sb.append(newLine)
                .append(boundaryPrefix)
                .append(BOUNDARY)
                .append(boundaryPrefix)
                .append(newLine);
            // 写上结尾标识 
            out.write(sb.toString().getBytes()); 
            System.out.println(sb);
            //输出结束,关闭输出流
            out.flush(); 
            out.close(); 
            //定义BufferedReader输入流来读取URL的响应 ,注意必须接受来自服务器的返回,否则服务器不会对发送的post请求做处理!!这里坑了我好久
            BufferedReader reader = new BufferedReader(new InputStreamReader( 
                    conn.getInputStream())); 
            String line = null; 
            while ((line = reader.readLine()) != null) { 
                System.out.println(line); 
            } 
        } catch (Exception e) { 
            System.out.println("发送POST请求出现异常!" + e); 
            e.printStackTrace(); 
        } 

    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
    注释很清楚,结合post请求的格式理解一下,就不一一解释了
     
    实现服务端的处理
    上述的代码会形成一个post请求到服务器,于是相应的接口的dopost()方法就会相应
    dopost()中做了什么呢?

    获取报文中的文件信息
    处理文件信息,包括识别文件名,识别文件类型(由用户定义,而不是文件后缀)
    存储到本地(服务器端硬盘)

    代码如下:
     
    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;
    //注意导的包
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        //输出到客户端浏览器
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload sup = new ServletFileUpload(factory);//这里要将factory传入,否则会报NullPointerException: No FileItemFactory has been set.
        try{
            List<FileItem> list = sup.parseRequest(request);
            for(FileItem fileItem:list){
                System.out.println(fileItem.getFieldName()+"--"+fileItem.getName());
                if(!fileItem.isFormField()){
                    if("file".equals(fileItem.getFieldName())){
                        //获取远程文件名
                        String remoteFilename = new String(fileItem.getName().getBytes(),"UTF-8");
                        File remoteFile = new File(remoteFilename);
                        //设置服务器端存放文件的位置
                        File locate = new File("C://E//download/",remoteFile.getName());
    //                      locate.getParentFile().mkdirs();//用于确保文件目录存在,如果为单级目录可以去掉
                        locate.createNewFile(); //创建新文件
                        InputStream ins = fileItem.getInputStream();   //FileItem的内容
                        OutputStream ous = new FileOutputStream(locate); //输出
                        try{
                            byte[] buffer = new byte[1024]; //缓冲字节
                            int len = 0;
                            while((len = ins.read(buffer))>-1)
                                ous.write(buffer, 0, len);
                        }finally{
                            ous.close();
                            ins.close();
                        }
                    }
                }      
            }
        }catch (FileUploadException e){}
        out.print("everything is ok");
        out.flush();
        out.close();
    }123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
    同样注释很清楚,不再解释了
    小结
    将上述过程理解清楚后,再结合post报文的格式,那么是否就可以处理多个文件同时上传了呢?如果对客户端的流做出一些大小限制,是不是就可以限制上传大小了?…一个小demo,帮助理解一下基础的实现。
    ---------------------
    作者:Sailist
    来源:CSDN
    原文:https://blog.csdn.net/sailist/article/details/81083205
    版权声明:本文为博主原创文章,转载请附上博文链接!
  • 相关阅读:
    POJ 1673
    POJ 1375
    POJ 1654
    POJ 1039
    POJ 1066
    UVA 10159
    POJ 1410
    POJ 2653
    POJ 2398
    POJ 1556
  • 原文地址:https://www.cnblogs.com/qiu18359243869/p/10933989.html
Copyright © 2011-2022 走看看