• Java中的文件上传(原始Servlet实现)


    从原始的Servlet来实现文件的上传,代码如下:

    参考:https://my.oschina.net/Barudisshu/blog/150026

    采用的是Multipart/form-data的方式上传文件。针对Multipart/form-data方式的上传解释,参考如下文件:

    http://www.onmpw.com/tm/xwzj/network_35.html

    http://892848153.iteye.com/blog/1847467

    http://blog.csdn.net/five3/article/details/7181521

    下面为具体的实现方式:

    1、通过getInputStream()取得上传文件。

    注意:这种方式相当的原始,通过分析body中的字符,然后再进行硬编码切割出文件字节,再进行保存。

    JSP:

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
        <head>
            <title></title>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        </head>
        <body>
            <div>
                <form action="UploadServlet" method="POST" enctype="multipart/form-data">
                    <table>
                        <tr>
                            <td><label for="file1">文件1:</label></td>
                            <td><input type="file" id="file1" name="file"></td>
                        </tr>
                        <tr>
                            <td><label for="file2">文件2:</label></td>
                            <td><input type="file" id="file2" name="file"></td>
                        </tr>
                        <tr>
                            <td><label for="file3">文件3:</label></td>
                            <td><input type="file" id="file3" name="file"></td>
                        </tr>
                        <tr>
                            <td><label for="file3">Text:</label></td>
                            <td><input type="text" id="text1" name="text1"></td>
                        </tr>
                        <tr>
                            <td colspan="2"><input type="submit" value="上传" name="upload"></td>
                        </tr>
                    </table>
                </form>
            </div>
        </body>
    </html>

    Servlet:

    提示:使用了servlet3.0的标注免配置功能。

    package uploadtest;
    
    
    import java.io.DataInputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import java.util.Date;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Servlet implementation class UploadServlet
     */
    @WebServlet("/UploadServlet")
    public class UploadServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
           
        /**
         * @see HttpServlet#HttpServlet()
         */
        public UploadServlet() {
            super();
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
         */
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
        }
    
        /**
         * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
         */
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
            this.processRequest(request, response);
        }
        
        //通过getInputStream()取得上传文件。循环多文件
        /**
         * Processes requests for both HTTP
         * <code>POST</code> methods.
         *
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            response.setContentType("text/html;charset=UTF-8");
            //读取请求Body
            byte[] body = readBody(request);
            //取得所有Body内容的字符串表示
            String textBody = new String(body, "ISO-8859-1");
            
            //取得文件区段边界信息,并通过边界循环获取文件流
            String contentType = request.getContentType();
            String boundaryText = String.format("--%1$s", contentType.substring(contentType.lastIndexOf("=") + 1, contentType.length()));
            for(String tempTextBody : textBody.split(boundaryText)){//多文件循环
                if(tempTextBody.length()>0){
                    //取得上传的文件名称
                    String fileName = getFileName(tempTextBody);
                    if(fileName.length()>0){
                        //取得文件开始与结束位置
                        Position p = getFilePosition(tempTextBody);
                        //输出至文件
                        writeTo(fileName, tempTextBody.getBytes("ISO-8859-1"), p);                
                    }
                }
            }
        }
    
        /**
         * 文件起始位置类
         *
         */
        class Position {
    
            int begin;
            int end;
    
            public Position(int begin, int end) {
                this.begin = begin;
                this.end = end;
            }
        }
    
        /**
         * 获取request的getInputStream,返回byte
         * 
         * @param request 
         * @return
         * @throws IOException
         */
        private byte[] readBody(HttpServletRequest request) throws IOException {
            //获取请求文本字节长度
            int formDataLength = request.getContentLength();
            //取得ServletInputStream输入流对象
            DataInputStream dataStream = new DataInputStream(request.getInputStream());
            byte body[] = new byte[formDataLength];
            int totalBytes = 0;
            while (totalBytes < formDataLength) {
                int bytes = dataStream.read(body, totalBytes, formDataLength);
                totalBytes += bytes;
            }
            return body;
        }
    
        /**
         * 获取文件起始位置
         * 
         * @param request
         * @param textBody
         * @return
         * @throws IOException
         */
        private Position getFilePosition(String textBody) throws IOException {
            //取得实际上传文件的起始与结束位置
            int pos = textBody.indexOf("filename="");
            pos = textBody.indexOf("
    ", pos) + 1;
            pos = textBody.indexOf("
    ", pos) + 1;
            pos = textBody.indexOf("
    ", pos) + 1;
            int begin = ((textBody.substring(0, pos)).getBytes("ISO-8859-1")).length;
            int end = textBody.getBytes("ISO-8859-1").length;
    
            return new Position(begin, end);
        }
    
        /**
         * 获取文件名
         * 
         * @param requestBody
         * @return
         */
        private String getFileName(String requestBody) {
            try {
                String fileName = requestBody.substring(requestBody.indexOf("filename="") + 10);
                fileName = fileName.substring(0, fileName.indexOf("
    "));
                fileName = fileName.substring(fileName.indexOf("
    ") + 1,fileName.indexOf("""));
                // 取扩展名加随机数进行重命名
                fileName = new SimpleDateFormat("yyyyMMddHHmmsssss").format(new Date())+java.util.UUID.randomUUID() + fileName.substring(fileName.lastIndexOf("."),fileName.length());
                return fileName;
            } catch (Exception e) {
                return "";
            }
        }
    
        /**
         * 写文件
         * 
         * @param fileName
         * @param body
         * @param p
         * @throws IOException
         */
        private void writeTo(String fileName, byte[] body, Position p) throws IOException {
            String filePath = this.getServletContext().getRealPath("")+"/Uploads/"+new SimpleDateFormat("yyyyMMdd").format(new Date())+"/";//初始化保存的位置
            Tools.isExistDir(filePath);//看目录是否已经创建        
            FileOutputStream fileOutputStream = new FileOutputStream(filePath + fileName);
            fileOutputStream.write(body, p.begin, (p.end - p.begin));
            fileOutputStream.flush();
            fileOutputStream.close();
        }
    
    } 

    测试工程:https://github.com/easonjim/5_java_example/tree/master/uploadtest/test1

    2、通过getPart()、getParts()取得上传文件。

    Servlet3.0中新增了getPart()和getParts()函数用来处理上传文件,getPart()用于上传单文件,getParts()用于上传多个文件。详细参考:http://blog.csdn.net/new_one_object/article/details/51373802

    同样的,用此方法只支持multipart/form-data请求类型的文件上传。

    还有一点,在Servlet上必须标注特性标记头@MultipartConfig,以表示是multipart/form-data类型的MIME。

    JSP:

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
        <head>
            <title></title>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        </head>
        <body>
            <div>
                <form action="UploadServlet" method="POST" enctype="multipart/form-data">
                    <table>
                        <tr>
                            <td><label for="file1">文件1:</label></td>
                            <td><input type="file" id="file1" name="file1"></td>
                        </tr>
                        <tr>
                            <td><label for="file2">文件2:</label></td>
                            <td><input type="file" id="file2" name="file2"></td>
                        </tr>
                        <tr>
                            <td><label for="file3">文件3:</label></td>
                            <td><input type="file" id="file3" name="file3"></td>
                        </tr>
                        <tr>
                            <td><label for="file3">Text:</label></td>
                            <td><input type="text" id="text1" name="text1"></td>
                        </tr>
                        <tr>
                            <td colspan="2"><input type="submit" value="上传" name="upload"></td>
                        </tr>
                    </table>
                </form>
            </div>
        </body>
    </html>

    Servlet:

    提示:使用了servlet3.0的标注免配置功能。

    package uploadtest;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    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;
    
    /**
     * Servlet implementation class UploadServlet
     */
    @MultipartConfig
    @WebServlet("/UploadServlet")
    public class UploadServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
           
        /**
         * @see HttpServlet#HttpServlet()
         */
        public UploadServlet() {
            super();
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
         */
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
        }
    
        /**
         * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
         */
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
            this.processRequest(request, response);
        }
        
        //通过getPart()、getParts()取得上传文件。单文件
        /**
         * Processes requests for both HTTP
         * <code>POST</code> methods.
         *
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            Part part = request.getPart("file1");//参数就是input标签的name属性,且这个name必须是唯一的
            String fileName = getFileName(part);
            writeTo(fileName, part);
        }
    
        //取得上传文件名
        private String getFileName(Part part) {
            String header = part.getHeader("Content-Disposition");
            String fileName = header.substring(header.indexOf("filename="") + 10, header.lastIndexOf("""));
            // 取扩展名加随机数进行重命名
            fileName = new SimpleDateFormat("yyyyMMddHHmmsssss").format(new Date())+java.util.UUID.randomUUID() + fileName.substring(fileName.lastIndexOf("."),fileName.length());
            return fileName;
        }
    
        //存储文件
        private void writeTo(String fileName, Part part) throws IOException, FileNotFoundException {
            InputStream in = part.getInputStream();
            String filePath = this.getServletContext().getRealPath("")+"/Uploads/"+new SimpleDateFormat("yyyyMMdd").format(new Date())+"/";//初始化保存的位置
            Tools.isExistDir(filePath);//看目录是否已经创建        
            OutputStream out = new FileOutputStream(filePath + fileName);
            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = in.read(buffer)) != -1) {
                out.write(buffer, 0, length);
            }
    
            in.close();
            out.close();
        }
    
    
    }

    通过上面的代码很明显的区别出这个方法简单明了,省去了切割字符串的问题。

    接下来再升级简化一下流的写入,将用到@MultipartConfig特性中的location属性,这个属性将指定一个本地目录,然后调用wtite方法直接写入。不过这个也有一个不好的特点,路径是死的,没法按照自定义输出。

    Servlet改造如下:

    package uploadtest;
    
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    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;
    
    /**
     * Servlet implementation class UploadServlet
     */
    @MultipartConfig(location = "d:\\workspace")
    @WebServlet("/UploadServlet3")
    public class UploadServlet3 extends HttpServlet {
        private static final long serialVersionUID = 1L;
           
        /**
         * @see HttpServlet#HttpServlet()
         */
        public UploadServlet3() {
            super();
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
         */
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
        }
    
        /**
         * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
         */
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
            this.processRequest(request, response);
        }
        
        //通过getPart()、getParts()取得上传文件。单文件
        /**
         * Processes requests for both HTTP
         * <code>POST</code> methods.
         *
         * @param request servlet request
         * @param response servlet response
         * @throws ServletException if a servlet-specific error occurs
         * @throws IOException if an I/O error occurs
         */
        protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            Part part = request.getPart("file1");//参数就是input标签的name属性,且这个name必须是唯一的
            String fileName = getFileName(part);
            //将文件写入location指定的目录
            part.write(fileName);
        }
    
        //取得上传文件名
        private String getFileName(Part part) {
            String header = part.getHeader("Content-Disposition");
            String fileName = header.substring(header.indexOf("filename="") + 10, header.lastIndexOf("""));
            // 取扩展名加随机数进行重命名
            fileName = new SimpleDateFormat("yyyyMMddHHmmsssss").format(new Date())+java.util.UUID.randomUUID() + fileName.substring(fileName.lastIndexOf("."),fileName.length());
            return fileName;
        }
    
    
    }

    对于@MultipartConfig更多的解释,参考:http://blog.csdn.net/chenqipc/article/details/50551450

    测试工程(包含了多文件的实现):https://github.com/easonjim/5_java_example/tree/master/uploadtest/test2

  • 相关阅读:
    设计模式学习笔记——Bridge 桥接模式
    设计模式学习笔记——Adapter 适配器模式
    protoc protobuff安装
    docker-compose启动consul
    docker etcd 环境搭建
    nifi的去重方案设计(二)-外部存储mysql全局去重
    实现一套ES全文检索语法-到Lucene语法的转换工具,以实现在es外部兼容处理文本分词
    nifi的去重方案设计(一)-单队列内去重.md
    k8s 证书过期处理
    部分项目从kafka迁移至pulsar,近期使用中碰到了一些问题,勉强把大的坑踩完了,topic永驻,性能相关
  • 原文地址:https://www.cnblogs.com/EasonJim/p/6554669.html
Copyright © 2020-2023  润新知