标签:
在使用servlet上传的时候,因为request里面有时候既包含了参数信息还有文件信息,取出来的时候就会很麻烦,所以我们可以根据request取出参数的原理,相当于自定义一个request来实现我们的文件上传和其他参数取出的分离.
介绍这个问题之前,需要先理解几个概念
用下面简单代码解释,也就是A里面包含一个B的实例
Class A{
private B b;
}
用下面代码解释就是A中的方法需要B类的作为参数参与
Class A{
public void f(B b);
}
说到这就想起了装饰者模式,两者都可以说是装饰者模式的一种实现吧.下面要做的也是利用装饰者模式来解决.
从类的结构图,可以看出来HttpServletRequest实现了两个接口,这里我们重点看HttpServletRequestWrapper.
查找API会发现HttpServletRequestWrapper里面管理着HttpServletRequest里面锁调用的方法,因此我们只要自定义一个类,继承HttpServletRequestWrapper,然后利用自定义的类来创建req就可以实现自定义的request了.
自定义前需要引入两个上传组件包
自定义前需要注意:上传数据可能有多值现象,比如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;
}
}
使用就很简单了,直接在处理上传的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>
<%@ 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