码迷,mamicode.com
首页 > 移动开发 > 详细

Servlet基于HttpServletRequestWrapper的文件上传

时间:2016-03-09 21:14:05      阅读:304      评论:0      收藏:0      [点我收藏+]

标签:

在使用servlet上传的时候,因为request里面有时候既包含了参数信息还有文件信息,取出来的时候就会很麻烦,所以我们可以根据request取出参数的原理,相当于自定义一个request来实现我们的文件上传和其他参数取出的分离.


一.关联关系和依赖关系

介绍这个问题之前,需要先理解几个概念

  • 关联关系

    用下面简单代码解释,也就是A里面包含一个B的实例

Class A{
    private B b;
}
  • 依靠关系

用下面代码解释就是A中的方法需要B类的作为参数参与

Class A{
    public void f(B b);
}

说到这就想起了装饰者模式,两者都可以说是装饰者模式的一种实现吧.下面要做的也是利用装饰者模式来解决.


二.具体实现

1.HttpServletRequest

从类的结构图,可以看出来HttpServletRequest实现了两个接口,这里我们重点看HttpServletRequestWrapper.

技术分享

查找API会发现HttpServletRequestWrapper里面管理着HttpServletRequest里面锁调用的方法,因此我们只要自定义一个类,继承HttpServletRequestWrapper,然后利用自定义的类来创建req就可以实现自定义的request了.

2.自定义MultipartRequestWrapper

自定义前需要引入两个上传组件包
技术分享

自定义前需要注意:上传数据可能有多值现象,比如checkbox,这样的就是一个数组.另外之前的文件上传使用的是传统的方法traditional API,这里换成Streaming API,相比传统的方式,这种方式更加迅速.

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by nl101 on 2016/3/8.
 */
public class MultipartRequestWrapper extends HttpServletRequestWrapper {

    //存储参数的集合
    private Map<String,String[]> params = new HashMap<>();

    private static String PATH = "E:\\temp\\"; //设置上传路径

    public MultipartRequestWrapper(HttpServletRequest request) {
        super(request);
        setParams(request);//对request进行解析,并存入map中
    }

    /**
     * 通过StreamingAPI的方式上传文件
     */
    private void setParams(HttpServletRequest request){
        //获取上传文件类型
        if (ServletFileUpload.isMultipartContent(request)){
            //创建ServletFileUpload实例
            ServletFileUpload fileUpload = new ServletFileUpload();
            try {
                //解析request请求 返回FileItemStream的iterator实例
                FileItemIterator iter = fileUpload.getItemIterator(request);
                InputStream is = null;//输出流
                //迭代取出
                while (iter.hasNext()){
                    FileItemStream item = iter.next();//获取文件流
                    String name = item.getFieldName();//返回表单中标签的name值
                    is = item.openStream();//得到对应表单的输出流
                    if (item.isFormField()){//如果是非文件域,设置进入map,这里要注意多值处理
                        setFormParam(name,is);//如果不是文件上传,处理
                    }else {
                        if (is.available()>0){//如果输出流的内容大于0
                            String fname = item.getName();//获取文件名
                            Streams.copy(is,new FileOutputStream(PATH+fname),true);//拷贝内容到上传路径
                            params.put(name,new String[]{fname});//把文件名设置进request中
                        }

                    }
                }

            } catch (FileUploadException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else {
            params = request.getParameterMap();//如果不是文件上传请求,则直接设置map
        }
    }

    /**
     * 处理非上传的表单
     * @param name
     * @param is
     */
    private void setFormParam(String name, InputStream is) {
        try {
            if (params.containsKey(name)){//判断当前值name是否已经存储过
                String[] values = params.get(name);//取出已经存储过的值
                values = Arrays.copyOf(values,values.length+1);//把当前数组扩大
                values[values.length-1] = Streams.asString(is);//增加新值
                params.put(name,values);//重新添加到map中
            }else {
                params.put(name,new String[]{Streams.asString(is)});//直接存入参数中
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 返回参数map集合,自定义后上传文件,上传成功则返回文件名
     * @return
     */
    @Override
    public Map<String,String[]> getParameterMap() {
        return params;
    }

    /**
     * 从请求中取出参数
     * @param name
     * @return
     */
    @Override
    public String getParameter(String name) {
        String[] values = params.get(name);
        if(values!=null) {
            return values[0];
        }
        return null;
    }

    /**
     * 从请求中取出多个参数值,如checkbox的值
     * @param name
     * @return
     */
    @Override
    public String[] getParameterValues(String name) {
        String[] values = params.get(name);
        if(values!=null) {
            return values;
        }
        return null;
    }

}

3.使用自定义的request

使用就很简单了,直接在处理上传的Servlet中来再次包装下req即可

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Created by nl101 on 2016/3/9.
 */
public class UploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req = new MultipartRequestWrapper(req);//重新包装
        req.getParameter("username");//接着就可以像往常一样处理请求了
        req.getParameter("file");//接着就可以像往常一样处理请求了
    }
}

别忘记配置WEB.xml文件

<servlet>
        <servlet-name>UploadServlet</servlet-name>
        <servlet-class>com.servlet.UploadServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>UploadServlet</servlet-name>
        <url-pattern>/upload.do</url-pattern>
    </servlet-mapping>

4,jsp测试

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>上传测试</title>
  </head>
  <body>
    <form action="upload.do" method="post" enctype="multipart/form-data">
        <table border="1">
          <tr>
            <td>用户名:<input name="username" type="text"></td>
          </tr>
          <tr>
            <td>上传:<input type="file" name="file"></td>
          </tr>
          <tr>
            <td><input type="submit" value="上传"></td>
          </tr>
        </table>
    </form>
  </body>
</html>

技术分享

这样点击上传,就可以完成上传了,而且我们的处理还是像往常一样通过req.getParameter(“username”),这样用起来省心太多了.

Servlet基于HttpServletRequestWrapper的文件上传

标签:

原文地址:http://blog.csdn.net/u012706811/article/details/50831563

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!