Package org.nutz.mvc.upload

Source Code of org.nutz.mvc.upload.UploadAdaptor

package org.nutz.mvc.upload;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.nutz.filepool.NutFilePool;
import org.nutz.lang.Lang;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.adaptor.PairAdaptor;
import org.nutz.mvc.adaptor.ParamInjector;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.upload.injector.FileInjector;
import org.nutz.mvc.upload.injector.FileMetaInjector;
import org.nutz.mvc.upload.injector.InputStreamInjector;
import org.nutz.mvc.upload.injector.MapListInjector;
import org.nutz.mvc.upload.injector.MapSelfInjector;
import org.nutz.mvc.upload.injector.ReaderInjector;
import org.nutz.mvc.upload.injector.TempFileInjector;

/**
* 本适配器专门处理 HTTP 文件上传(1.b.44及之后的版本,兼容Html5的流式上传)。 它支持多文件,多参数上传。具体的做法是将 HTTP
* 上传的所有内容 包括文件以及名值对都预先缓存下来。其中,文件缓存在磁盘上,名值对缓存在内存中。
* <p>
* 因此,本适配器构造的时候,需要四个参数:
* <ol>
* <li>临时文件存放的目录
* <li>数据缓冲区大小,建议设置为8192
* <li>HTTP 请求的编码方式。
* <li>临时文件的最大数量
* </ol>
* 本适配器提供了四个构造函数,最简单的一个只有一个参数,需要你提供一个临时文件目录,缓冲区大小默认为8192, 临时文件数目默认的为 "2000",HTTP
* 请求的编码方式为 "UTF-8",
* <p>
* 为了能让入口函数了解 HTTP 请求的更多信息,本适配器入口函数声明更多的参数类型:
* <ul>
* <li>java.io.File : 指向已上传至临时目录的文件对象
* <li>org.nutz.mvc.upload.FieldMeta : 描述了一个上传参数的更多属性
* <li>org.nutz.mvc.upload.TempFile : 组合了 File 和 FieldMeta
* </ul>
* 当然,这三种参数,都是需要你在入口函数的参数列表里声明 '@Param' 注解,用来告诉本适配器,你的参数 具体取自请求中的哪一个参数。
*
* <p/>
* <b>Html5流式上传(实验性)的注意事项:
* 参数名默认是filedata,除非req.getHeader("Content-Disposition")中有描述另外的name</b>
*
* @author zozoh(zozohtnt@gmail.com)
* @author wendal(wendal1985@gmail.com)
*
* @see org.nutz.mvc.annotation.Param
*/
public class UploadAdaptor extends PairAdaptor {
    private static final Log log = Logs.get();

    private UploadingContext context;

    public UploadAdaptor() throws IOException {
        context = new UploadingContext(File.createTempFile("nutz", null).getParent());
    }

    public UploadAdaptor(UploadingContext context) {
        this.context = context;
    }

    public UploadAdaptor(String path) {
        context = new UploadingContext(path);
    }

    public UploadAdaptor(String path, int buffer) {
        this(path);
        context.setBufferSize(buffer);
    }

    public UploadAdaptor(String path, int buffer, String charset) {
        this(path);
        context.setBufferSize(buffer);
        context.setCharset(charset);
    }

    public UploadAdaptor(String path, int buffer, String charset, int poolSize) {
        context = new UploadingContext(new NutFilePool(path, poolSize));
        context.setBufferSize(buffer);
        context.setCharset(charset);
    }

    public UploadAdaptor(String path, int buffer, String charset, int poolSize, int maxFileSize) {
        context = new UploadingContext(new NutFilePool(path, poolSize));
        context.setBufferSize(buffer);
        context.setCharset(charset);
        context.setMaxFileSize(maxFileSize);
    }

    public UploadingContext getContext() {
        return context;
    }

    protected ParamInjector evalInjectorBy(Type type, Param param) {
        // TODO 这里的实现感觉很丑, 感觉可以直接用type进行验证与传递
        // TODO 这里将Type的影响局限在了 github issue #30 中提到的局部范围
        Class<?> clazz = Lang.getTypeClass(type);
        if (clazz == null) {
            if (log.isWarnEnabled())
                log.warnf("!!Fail to get Type Class : type=%s , param=%s", type, param);
            return null;
        }

        // Map
        if (Map.class.isAssignableFrom(clazz))
            return new MapSelfInjector();

        if (null == param)
            return super.evalInjectorBy(type, null);

        String paramName = param.value();

        // File
        if (File.class.isAssignableFrom(clazz))
            return new FileInjector(paramName);
        // FileMeta
        if (FieldMeta.class.isAssignableFrom(clazz))
            return new FileMetaInjector(paramName);
        // TempFile
        if (TempFile.class.isAssignableFrom(clazz))
            return new TempFileInjector(paramName);
        // InputStream
        if (InputStream.class.isAssignableFrom(clazz))
            return new InputStreamInjector(paramName);
        // Reader
        if (Reader.class.isAssignableFrom(clazz))
            return new ReaderInjector(paramName);
        // List
        if (List.class.isAssignableFrom(clazz))
            return new MapListInjector(paramName);
        // Other
        return super.evalInjectorBy(type, param);
    }

    public Map<String, Object> getReferObject(ServletContext sc,
                                              HttpServletRequest request,
                                              HttpServletResponse response,
                                              String[] pathArgs) {
        try {
            if (!"POST".equals(request.getMethod()) && !"PUT".equals(request.getMethod())) {
                String str = "Not POST or PUT, Wrong HTTP method! --> " + request.getMethod();
                throw Lang.makeThrow(IllegalArgumentException.class, str);
            }
            // 看看是不是传统的上传
            String contentType = request.getContentType();
            if (contentType == null) {
                throw Lang.makeThrow(IllegalArgumentException.class, "Content-Type is NULL!!");
            }
            if (contentType.contains("multipart/form-data")) { // 普通表单上传
                if (log.isDebugEnabled())
                    log.debug("Select Html4 Form upload parser --> " + request.getRequestURI());
                Uploading ing = new FastUploading();
                return ing.parse(request, context);
            }
            if (contentType.contains("application/octet-stream")) { // Html5
                                                                    // 流式上传
                if (log.isDebugEnabled())
                    log.debug("Select Html5 Stream upload parser --> " + request.getRequestURI());
                Uploading ing = new Html5Uploading();
                return ing.parse(request, context);
            }
            // 100%是没写enctype='multipart/form-data'
            if (contentType.contains("application/x-www-form-urlencoded")) {
                log.warn("Using form upload ? You forgot this --> enctype='multipart/form-data' ?");
            }
            throw Lang.makeThrow(IllegalArgumentException.class, "Unknow Content-Type : "
                                                                 + contentType);
        }
        catch (UploadException e) {
            throw Lang.wrapThrow(e);
        }
        finally {
            Uploads.removeInfo(request);
        }
    }
}
TOP

Related Classes of org.nutz.mvc.upload.UploadAdaptor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.