zoukankan      html  css  js  c++  java
  • Webwork【07】文件上传下载

          Web上传和下载应该是很普遍的一个需求,无论是小型网站还是大并发访问的交易网站。WebWork 当然也提供了很友好的拦截器来实现对文件的上传,让我们可以专注与业务逻辑的设计和实现,在实现上传和下载时顺便关注了下框架上传下载的实现,在本篇博文中总结记录如下。 

    1. 包装 Request 请求

    • 每次客户端请求 Action 时,都会调用 WebWork 调度类 ServletDispatcher.service()方法。

           具体过程请参照: http://www.cnblogs.com/java-class/p/5155793.html

        public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException {
            try {
                if (encoding != null) {
                    try {
                        request.setCharacterEncoding(encoding);
                    } catch (Exception localException) {
                    }
                }
                if (locale != null) {
                    response.setLocale(locale);
                }
                if (this.paramsWorkaroundEnabled) {
                    request.getParameter("foo");
                }
                request = wrapRequest(request); //封装 request请求
                serviceAction(request, response, getNameSpace(request), getActionName(request), getRequestMap(request), getParameterMap(request), getSessionMap(request), getApplicationMap());
            } catch (IOException e) {
                String message = "Could not wrap servlet request with MultipartRequestWrapper!";
                log.error(message, e);
                sendError(request, response, 500, new ServletException(message, e));
            }
        }

          先来看看 wrapRequest 方法做了什么:

        protected HttpServletRequest wrapRequest(HttpServletRequest request) throws IOException {
            if ((request instanceof MultiPartRequestWrapper)) {
                return request;
            }
            if (MultiPartRequest.isMultiPart(request)) {
                request = new MultiPartRequestWrapper(request, getSaveDir(), getMaxSize());
            }
            return request;
        }
    •  首先判断了传进来的 request 是不是已经被封装好的 MultiPartRequestWrapper,如果是就直接返回。
    •  否则再判断 request 的头信息里面的 Content­Type 是不是多类型参数 (multipart/form­data)的请求,如果是就把 request 包装成 WebWork 自己的 MultiPartRequestWrapper 类型,该类型继承HttpServletRequestWrapper

        MultiPartRequest.isMultiPart() 方法实现如下:

     public static boolean isMultiPart(HttpServletRequest request){
            String content_type = request.getHeader("Content-Type");
            return content_type != null && content_type.startsWith("multipart/form-data");
        }
    • webwork.properties 里面配置文件的临时存储目录、还有最大上传大小,其实就是在这个时候起到作用的。
    • 创建 MultiPartRequestWrapper 对象的时候传入的参数是由 getSaveDir() 和 getMaxSize() 方 法 获 得 的 。
    • 在方法里会查找配置里面的 webwork.multipart.saveDir、 webwork.multipart.maxSize 属性,找到则使用该属性指定的临时目录和上传的最大内容,没找到就使用环境的临时目录。

    具体实现如下:

        protected String getSaveDir() {
            String saveDir = Configuration.getString("webwork.multipart.saveDir").trim();
            if (saveDir.equals("")) {
                File tempdir = (File) getServletConfig().getServletContext().getAttribute("javax.servlet.context.tempdir");
                log.info("Unable to find 'webwork.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir");
                if (tempdir != null) {
                    saveDir = tempdir.toString();
                }
            } else {
                File multipartSaveDir = new File(saveDir);
                if (!multipartSaveDir.exists()) {
                    multipartSaveDir.mkdir();
                }
            }
            if (log.isDebugEnabled()) {
                log.debug("saveDir=" + saveDir);
            }
            return saveDir;
        }

    2. 获取文件上传的解析类     

       再来看一下 MultiPartRequestWrapper 的构造函数使如何包装 request 的:

        public MultiPartRequestWrapper(HttpServletRequest request, String saveDir, int maxSize) throws IOException {
            super(request);
            if ((request instanceof MultiPartRequest)) {
                this.multi = ((MultiPartRequest) request);
            } else {
                String parser = "";
                parser = Configuration.getString("webwork.multipart.parser");
                if (parser.equals("")) {
                    log.warn("Property webwork.multipart.parser not set. Using com.opensymphony.webwork.dispatcher.multipart.PellMultiPartRequest");
                    parser = "com.opensymphony.webwork.dispatcher.multipart.PellMultiPartRequest";
                } else if (parser.equals("pell")) {
                    parser = "com.opensymphony.webwork.dispatcher.multipart.PellMultiPartRequest";
                } else if (parser.equals("cos")) {
                    parser = "com.opensymphony.webwork.dispatcher.multipart.CosMultiPartRequest";
                } else if (parser.equals("jakarta")) {
                    parser = "com.opensymphony.webwork.dispatcher.multipart.JakartaMultiPartRequest";
                }
                try {
                    Class baseClazz = MultiPartRequest.class;
                    Class clazz = Class.forName(parser);
                    if (!baseClazz.isAssignableFrom(clazz)) {
                        addError("Class '" + parser + "' does not extend MultiPartRequest");
                        return;
                    }
                    Constructor ctor = clazz.getDeclaredConstructor(new Class[] { Class.forName("javax.servlet.http.HttpServletRequest"), String.class, Integer.TYPE });
                    Object[] parms = { request, saveDir, new Integer(maxSize) };
                    this.multi = ((MultiPartRequest) ctor.newInstance(parms));
                } catch (ClassNotFoundException e) {
                    addError("Class: " + parser + " not found.");
                } catch (NoSuchMethodException e) {
                    addError("Constructor error for " + parser + ": " + e);
                } catch (InstantiationException e) {
                    addError("Error instantiating " + parser + ": " + e);
                } catch (IllegalAccessException e) {
                    addError("Access errror for " + parser + ": " + e);
                } catch (InvocationTargetException e) {
                    addError(e.getTargetException().toString());
                }
            }
        }
    •  首先它判断了传入的 request 是不是 MultiPartRequest 抽象类的子类,如果是就直接把自身的 MultiPartRequest 类型的变量引用 request
    •  否则读取 WebWork 配置 的webwork.multipart.parser 属性,该属性决定 Webwork 内部用什么实现文件上传。 如果没有指定,则默认使用 PellMultiPartRequest 的实现。
    • 找到配置的类后,WebWork 通过 Java 反射创建该类的实例。所有支持的类都是从 MultiPartRequest 继承而来,创建该实例后向上转型,并赋予 MultiPartRequestWrapper 的成员multi。 
    •  WebWork 的文件上传封装了几种通用的 FileUpload lib,并不是自己实现的。
    • 它包括了pell,cos,apache common 三种实现,WebWork 对这三个包进行封装,提供了一 个通用的访问接口 MultiPartRequest,细节实现分别是 PellMultiPartRequest、 CosMultiPartRequest 、JakartaMultiPartRequest
    •  jakarta 支持多个文件使用同一个HTTP参数名。如果直接使用 WebWorkFileUpload 拦截器,推荐使用pell,因为当你上传中文文件名称的文件的时候,只有pell 包会正确的获得中文文件名称,apache common会将文件名称改为xxx.tmp这样的文件名,而cos会乱码, 因此我们唯一的选择只有 pell。
    • cos 的功能比较强大,WebWork 的封装却使它丧失了很多的功能,cos 需要设置 request 的character encoding。WebWork的封装没有设置,所以就导致了cos的乱码问题,当然如果你单独 使用cos,则会避免此类问题。

    3. 项目实战配置和使用

    •  配置文件
    action 配置:
     <action name="uploadAttach" class=".....attach.action.uploadAttach"  caption="上传附件">
        <result name="success" type="dispatcher">
            <param name="location">/result.jsp</param>
        </result>
        <result name="error" type="dispatcher">
            <param name="location">/result.jsp</param>
        </result>       
        <interceptor-ref name="defaultStack" />  
        <interceptor-ref name="fileUploadStack" /> //webwok 上传所需要的拦截栈
     </action>
    
    //拦截栈的定义
    <interceptor-stack name="fileUploadStack">
        <interceptor-ref name="fileUpload"/>  
        <interceptor-ref name="params"/>
    </interceptor-stack>
    
    //拦截栈对应的拦截器
    <interceptor name="fileUpload"   class="com.opensymphony.webwork.interceptor.FileUploadInterceptor"/>
    <interceptor name="params"          class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/>
    public String intercept(ActionInvocation invocation) throws Exception {if (!(ServletActionContext.getRequest() instanceof MultiPartRequestWrapper)) {
                if (log.isDebugEnabled()) {
                    log.debug("bypass " + invocation.getProxy().getNamespace() + "/" + invocation.getProxy().getActionName());
                }
                return invocation.invoke();
            }
            Action action = invocation.getAction();
            ValidationAware validation = null;
            if ((action instanceof ValidationAware)) {
                validation = (ValidationAware) action;
            }
            MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) ServletActionContext.getRequest();
            if (multiWrapper.hasErrors()) {
                Collection errors = multiWrapper.getErrors();
                Iterator i = errors.iterator();
                while (i.hasNext()) {
                    String error = (String) i.next();
                    if (validation != null) {
                        validation.addActionError(error);
                    }
                    log.error(error);
                }
            }
            Enumeration e = multiWrapper.getFileParameterNames();
            while ((e != null) && (e.hasMoreElements())) {
                String inputName = (String) e.nextElement();
    
                String[] contentType = multiWrapper.getContentTypes(inputName);
    
                String[] fileName = multiWrapper.getFileNames(inputName);
    
                File[] file = multiWrapper.getFiles(inputName);
                if (file != null) {
                    for (int i = 0; i < file.length; i++) {
                        log.info("file " + inputName + " " + contentType[i] + " " + fileName[i] + " " + file[i]);
                    }
                }
                if (file == null) {
                    if (validation != null) {
                        validation.addFieldError(inputName, "Could not upload file(s). Perhaps it is too large?");
                    }
                    log.error("Error uploading: " + fileName);
                } else {
                    invocation.getInvocationContext().getParameters().put(inputName, file);
                    invocation.getInvocationContext().getParameters().put(inputName + "ContentType", contentType);
                    invocation.getInvocationContext().getParameters().put(inputName + "FileName", fileName);
                }
            }
            String result = invocation.invoke();
            for (Enumeration e1 = multiWrapper.getFileParameterNames(); e1 != null && e1.hasMoreElements();) {
                String inputValue = (String) e1.nextElement();
                File file[] = multiWrapper.getFiles(inputValue);
                for (int i = 0; i < file.length; i++) {
                    File f = file[i];
                    log.info("removing file " + inputValue + " " + f);
                    if (f != null && f.isFile())
                        f.delete();
                }
            }
            return result;
        }
    • 首先判断当前请求是否为 包含多媒体请求,如果是则记录日志,并执行 Action
    • 然后判断在文件上传过程 MultiPartRequestWrapper 是否含有错误,将错误信息,返回给客户端,不在继续调用 Action
    • 如果上面的判断条件都没有进行,开始遍历 MultiPartRequestWrapper  中的上传文件的参数,并将其中的文件名、文件内容类型放入Action 参数 map 中,供后面的业务类进行操作。
    • 在 WebWork 的 fileupload 拦截器功能中,它提供的 File只 是一个临时文件,Action 执行之后就会被自动删除,你必须在 Action中自己处理文件的存储问题,或者写到服务器的某个目录,或者保存到数据库中。如果你准备写到服务器的某个目录下面的话,你必须自己面临着处理文件同名的问题,但是实际上cos包已经提供了 文件重名的自动重命名规则。 
  • 相关阅读:
    28完全背包+扩展欧几里得(包子凑数)
    HDU 3527 SPY
    POJ 3615 Cow Hurdles
    POJ 3620 Avoid The Lakes
    POJ 3036 Honeycomb Walk
    HDU 2352 Verdis Quo
    HDU 2368 Alfredo's Pizza Restaurant
    HDU 2700 Parity
    HDU 3763 CDs
    POJ 3279 Fliptile
  • 原文地址:https://www.cnblogs.com/java-class/p/5175619.html
Copyright © 2011-2022 走看看