zoukankan      html  css  js  c++  java
  • JSP上传文件 规格严格

    背景:

    3月,公司的实习生来了,每年都会招,招来之后人家看明白你公司环境后,毕业就和你拜拜了。不管怎么样,部门要求培训、要求每天写日报,这下可好,我们组有5个实习生,每个5个Excel,天天如此,而且Excel每个1M,我就得天天删来删去,不仅仅我们小组的,别的小组也这样,于是,我就想能不能部署个傻瓜应用,每天你们上传上去,我去下载,然后我在上传上去。呵呵,这个想法比较幼稚啊。。。。。。。。。。对于开发Web的各位来说。

    我Web的功力实在太差,于是正好前一阵子写了一个web小程序,一直处于开发进展中,我就加个小功能吧,先把原型搭出来。上网查了一下: 如果想要上传的话必须把form的enctype的格式设置成“multipart/form-data”,注意默认是什么URLEncoded的,这个咱也就不关心了。设置完之后,还必须是Post请求,必须的吗,上传文件还能Get?另外Servlet和JSP规范中并没有对这种格式进行解析,因此还得额外自己写代码。我shit,你下载文件只要设置一下响应头,你规范就不能为上传文件多做点东西么,还要我自己额外解析,虽说我对Web了解不多,可Apache我知道,common-fileupload这个组件我可知道,一查API,果真可以处理,等等,既然做了,就先自己造个轮子,毕竟是自己学习又不是做项目;再在网上搜,不错,找到oreilly上的一个开源Servlet工具库,看起来评价不错,我先收藏,慢慢再看。

    对付这种web流,我就两种处理方式:

    1、用HTTPWatch或者类似软件截获HTTP流,分析客户端提交数据

    2、调试阶段在Web应用服务器上打出响应流信息,先别考虑神马性能问题。。。那是后话。

    1、2弄完了,好了发现格式了如下,最好对着RFC看,但是真心看RFC太烂费时间了,不过对于真正想要做好这种类型的事情不仔细研读RFC以及各种浏览器的行为,总是会出现这样或者那样的问题。

    -----------------------------7dc1e411c05fe
    Content-Disposition: form-data; name="upfile"; filename="C:\Documents and Settings\Administrator\桌面\小舅好啊.doc"
    Content-Type: application/msword
    上面这个是文件流开始的元数据信息
     
    multipart/form-data; boundary=---------------------------7dc1e411c05fe
    这个是通过Request获取到的Content-Type,根据这个判断是否MultiPart,注意不仅仅可以传doc,应该MIME的都行,boundary很重要,这个就是处理文件流开始和结尾的。

    通过分析流,发现其实邮件传输和这个大同小异,除了邮件使用了Base64编码吧?印象中好象是。

    在文件流结尾会有这个:

    -------------------------------7dc1e411c05fe
    因此,通过分析boundary确定边界、通过分析Content-Disposition获取文件元信息,当然了,也可以不传文件,这样仅仅什么也不做而已。

    分析完了,奉上我第一版本的粗糙代码,说实话,我这个就是为了研究原理,里面代码存在很大问题,先说出来,别让大家喷我:

    1、编码格式,编码格式很重要,文件名可能是中文,因此需要设置UTF-8或者GBK,但是在解析流的时候,Encoding只能在解析元数据信息的时候的使用,其余时候

    各位还是安心使用ASCII就是字节流吧,这样原来文件是什么,存储的就是什么,肯定不会出现问题,之前我用GBK了,就带来Excel上传每次都有格式问题。

    2、流处理问题,缓冲流的操作,并且读取流需要分阶段来处理,先处理元数据信息,获取完后在处理文件真实信息,避免过多用户上传导致程序繁忙。

    JSP如下,一个简单的JSP

    <%@ page language="java" contentType="text/html; charset=gb2312"
        pageEncoding="gb2312"%>

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
    <title>SOC FileUpload</title>
    </head>
    <body>
        <!--  <%=application.getServerInfo()%><br>-->
        <form method="post" action="/soc/UploadFile"
            enctype="multipart/form-data">
            请选择要上传的文件<input type="file" name="upfile" size="40"><input
                type="submit" value="提交">
        </form>
    </body>
    </html>

    Servlet:

    public class UploadFile extends HttpServlet {
        private static final long serialVersionUID = 1L;

        // 10M
        
    // 这个版本的代码性能问题,读取大数据需要
        
    // 逐步读取
        public static final long MAX_SIZE = 1024 * 1024 * 10;
        static final String FILE_NAME = "filename=\"";
        static final String BOUNDRAY = "boundary=";

        /**
         * 
    @see HttpServlet#HttpServlet()
         
    */
        public UploadFile() {
            super();
            LogUtil.debug("UploadFile load.");
        }

        /**
         * 
    @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
         *      response)
         
    */
        protected void doGet(HttpServletRequest request,
                HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }

        /**
         * 
    @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
         *      response)
         
    */
        protected void doPost(HttpServletRequest request,
                HttpServletResponse response) throws ServletException, IOException {
            // request set encoding
            LogUtil.debug("UploadFile called.");
            LogUtil.debug(request.getServletPath());
            LogUtil.debug(getServletContext().getRealPath(request.getServerName()));
            String base = (getServletContext().getRealPath(request.getServerName()));
            // platform
            base = base.substring(0, base.lastIndexOf(File.separatorChar) + 1);
            String rootPath = base + "upload";

            String contentType = request.getContentType();
            LogUtil.debug(contentType);
            LogUtil.debug("donwload store: " + rootPath);
            if (contentType.indexOf("multipart/form-data") >= 0) {
                int length = request.getContentLength();
                if (length > MAX_SIZE) {
                    response.getWriter().println(
                            "<P> File can't exceed " + MAX_SIZE + "<P><br>");
                    return;
                }

                byte[] total = new byte[length];

                int totalRead = 0;
                int byteRead = 0;

                // not very good
                while (totalRead < length) {
                    byteRead = request.getInputStream().read(total, totalRead,
                            length - totalRead);
                    totalRead += byteRead;
                }

                String raw = new String(total);
                // LogUtil.debug("Raw: " + raw);
                LogUtil.debug("total: " + length + " read: " + totalRead);
                String saveFile = raw.substring(raw.indexOf(FILE_NAME)
                        + FILE_NAME.length());
                saveFile = saveFile.substring(0, saveFile.indexOf("\n"));
                saveFile = saveFile.substring(0, saveFile.lastIndexOf("\""));
                // 判断浏览器
                saveFile = saveFile.substring(saveFile.lastIndexOf("\\") + 1);
                LogUtil.debug("File: " + saveFile);

                String boudary = contentType
                        .substring(contentType.lastIndexOf("=") + 1);
                LogUtil.debug("Bound: " + boudary);

                String destFileName = rootPath + File.separatorChar + saveFile;
                LogUtil.debug(destFileName);

                int pos = raw.indexOf(FILE_NAME);
                pos = raw.indexOf("\n", pos) + 1;
                pos = raw.indexOf("\n", pos) + 1;
                pos = raw.indexOf("\n", pos) + 1;

                int startPosition = raw.substring(0, pos).getBytes().length;
                // -4
                LogUtil.debug("Start: " + raw.substring(0, pos));
                raw = null;
                raw = new String(total, "ascii");

                int boundaryPosition = raw.indexOf(boudary, pos) - 4;

                // LogUtil.debug("Bound: " + raw.substring(0, boundaryPosition));

                int endPosition = raw.substring(0, boundaryPosition).getBytes(
                        "ascii").length;
                // -----------------------------7dc251175d904aa
                
    // -----------------------------7dc251175d904aa--
                
    // ---------------------------7dc251175d904aa
                File file = new File(destFileName);

                if (!file.exists()) {
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
                    file.createNewFile();
                }

                FileOutputStream fout = new FileOutputStream(file);

                int destNumber = endPosition - startPosition;

                LogUtil.debug("Start: " + startPosition + " Boundary: "
                        + boundaryPosition + " End:" + endPosition + " Number: "
                        + destNumber);

                // LogUtil.debug("DestLog: "
                
    // + new String(total, startPosition, destNumber));

                
    // 避免写大文件
                ByteArrayInputStream bin = new ByteArrayInputStream(total,
                        startPosition, destNumber);
                byte[] cache = new byte[8 * 1024];
                int totalWrite = 0;
                while (totalWrite < destNumber) {
                    int cnt = bin.read(cache);
                    fout.write(cache, 0, cnt);
                    fout.flush();
                    totalWrite += cnt;
                }

                System.out.println("Write Total: " + totalWrite);
                fout.close();

                response.getWriter().println("<P>Upload File Successful<P><br>");
                response.getWriter().flush();
            }
        }
    }

    弄完后,我就知道,我这个处理不了多文件,其实也能处理,但是各位看官也看见了,代码写的实在难看,我连重构的欲望都没有,看来写程序必须先思考一下啊。。。奉上一个Oreilly的例子,看看这个多简洁:

    public class UploadFileEx extends HttpServlet {
        private static final long serialVersionUID = 1L;

        /**
         * 
    @see HttpServlet#HttpServlet()
         
    */
        public UploadFileEx() {
            super();
        }

        /**
         * 
    @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
         *      response)
         
    */
        protected void doGet(HttpServletRequest request,
                HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }

        /**
         * 
    @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
         *      response)
         
    */
        protected void doPost(HttpServletRequest request,
                HttpServletResponse response) throws ServletException, IOException {
            // http://www.javaworld.com.tw/confluence/pages/viewpage.action?pageId=692
            int maxPostSize = 5 * 1024 * 1024;
            MultipartRequest multi = new MultipartRequest(request, "d:\\",
                    maxPostSize, "GB2312");
            Enumeration<?> filenames = multi.getFileNames();
            while (filenames.hasMoreElements()) {
                String filename = (String) filenames.nextElement();
                System.out.println("Upload -> " + filename);
             }
        }
    }

    短短几行,功能完成,当然Jar包里面也很多类处理了。核心是封装一个MultipartRequest ,这个类里面调用MultipartParser生成不同的Part,不同的Part有不同的

    处理方法。

    附带两个URL链接:

    http://www.servlets.com/cos/

    http://commons.apache.org/fileupload/

    希望对大家有所帮助。

  • 相关阅读:
    让你的网站(MAXCMS4_0)按地区、年份、语言生成分页面(已经修正)
    IPTV
    超简单,MAX普通版改为资源版方法
    Jmter操作数据库
    JMter中添加断点和关联
    jmeter返回报文乱码问题
    Jmter安装和配置
    JMter压力测试
    今天注册了
    不能登陆后删除Cookies解决
  • 原文地址:https://www.cnblogs.com/diyunpeng/p/2429486.html
Copyright © 2011-2022 走看看