相信很多朋友再用springmvc时都遇见了一个问题,那就是自带的获取上传的东西太慢,而且不知道如何修改,其实不然,spring框架既然给我们开放了这个接口,就一定遵从了可扩展性的原则,经过查看org.springframework.web.multipart.commons.CommonsMultipartResolver的源代码我们发现(我们在spring中使用commons fileupload处理上传),其中有个public boolean isMultipart(HttpServletRequest request)方法,此方法控制着Spring是否对用户的Request进行文件上传处理,于是自定义一个我们自己的CommonsMultipartResolver,继承自org.springframework.web.multipart.commons.CommonsMultipartResolver,并重写其中的public boolean isMultipart(HttpServletRequest request),在方法中对当前的request进行代理,如果是一个代理实例,则返回false,告知Spring不需要再对当前的request进行文件上传处理;如果不是,则直接调用父类的isMultipart方法

    之前的项目代码不能满足我们的要求所以我们修改了,spring的CommonsMultipartResolver类来自定义我们的上传方法,大概思路时,代理当前HttpServletRequest,被代理的HttpServletRequest返回的是一个代理类,在isMultipart方法中判断有无被代理这样就可以实现我们自己的文件上传处理逻辑了

首先我们先自定义一个文件上传的过滤器Filter

web.xml

<!--文件上传过滤器-->
<filter>
<filter-name>MultiPartFilter</filter-name>
<filter-class>com.cn.interceptor.MultiPartFilter</filter-class>
<init-param>
<param-name>excludeURL</param-name>
<param-value>/res/js/ueditor</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MultiPartFilter</filter-name>
<url-pattern>/res/js/ueditor/*</url-pattern>
</filter-mapping>

上面配置一个文件上传过滤器,需要注意的是,这个过滤器因为代理了当前的servlet请求,所以其中的某些数据会被过滤,比如登录信息,所以一定要配置在登录过滤后面,这样才不会影响正常的框架,其他的过滤器因项目需要稍作更改

下面是代理HttpServletRequest的过滤器代码

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException { boolean jump = false; HttpServletRequest request = (HttpServletRequest) servletRequest;
// 根据web.xml中的配置,判断当前url是否跳过此过滤器
String excludeURL = getFilterConfig().getInitParameter("excludeURL");
if (excludeURL != null && !"".equals(excludeURL)) {
String requestURI = request.getRequestURI();
if (requestURI.indexOf(excludeURL) != -1) {
jump = true;
}
}
if (jump) {
String content_type = request.getContentType();
if (content_type != null && content_type.indexOf("multipart/form-data") != -1) {
try {
/**
*解析上传的文件存入缓存中,并返回一个代理对象
*/
request =parseMultipartContent(request);
String s = request.getClass().toString();
System.out.println(s);
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
} filterChain.doFilter(request, servletResponse);
}

接着我们继承springmvc的CommonsMultipartResolver重写其中的isMultipart

/**
* spring文件文件拦截器
*/
public class CommonsMultipartResolver extends org.springframework.web.multipart.commons.CommonsMultipartResolver { /**
* {@inheritDoc}
* 判断当前request有没有被代理
*
* @see org.springframework.web.multipart.commons.CommonsMultipartResolver#isMultipart(javax.servlet.http.HttpServletRequest)
*/
@Override
public boolean isMultipart(HttpServletRequest request) {
if (request.getClass().toString().indexOf("class com.sun.proxy") != -1) {
return false;
} else {
return super.isMultipart(request);
}
} }

然后再spring配置文件中修改成我们已经写好的类路径

 <bean id="multipartResolver"
class="com.cn.interceptor.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000000" />
</bean>

至此,整个框架正常的流程代码已经完成,我们可以开心的写我们的业务代码啦

下面是一个文件上传的代码,使用java1.7中NIO,比spring代码的操作文件流快了很多

写在过滤其中的代码

 /**
* 解析request对象中的文件,并返回一个代理对象
* @param request
* @return
* @throws Exception
*/
private HttpServletRequest parseMultipartContent(
final HttpServletRequest request) throws Exception {
if (!ServletFileUpload.isMultipartContent(request))
return request; // non-file parameters
final Map<String, String> requestParams = new HashMap<String, String>(); // Parse the request
ServletFileUpload sfu = new ServletFileUpload();
String characterEncoding = request.getCharacterEncoding();
if (characterEncoding == null) {
characterEncoding = "UTF-8";
} sfu.setHeaderEncoding(characterEncoding);
FileItemIterator iter = sfu.getItemIterator(request);
MultipleUploadItems uploads = new MultipleUploadItems(getTempDir(request)); while (iter.hasNext()) {
FileItemStream item = iter.next(); // not a file
if (item.isFormField()) {
InputStream stream = item.openStream();
requestParams.put(item.getFieldName(),
Streams.asString(stream, characterEncoding));
stream.close();
} else {
// it is a file!
String fileName = item.getName();
if (fileName != null && !"".equals(fileName.trim())) {
uploads.addItemProxy(item);
}
}
}
//储存可以重用的请求,不被servlet消费
uploads.writeInto(request);
requestParams.putAll(getParameterMap(request));
// 'getParameter()' method can not be called on original request object
// after parsing
// so we stored the request values and provide a delegate request object
return (HttpServletRequest) Proxy.newProxyInstance(this.getClass()
.getClassLoader(), new Class[]{HttpServletRequest.class},
new InvocationHandler() {
@Override
public Object invoke(Object arg0, Method arg1, Object[] arg2)
throws Throwable {
// 代理的方法
// we replace getParameter() and getParameterValues()
// methods
if ("getParameter".equals(arg1.getName())) {
String paramName = (String) arg2[0];
return requestParams.get(paramName);
} if ("getParameterValues".equals(arg1.getName())) {
String paramName = (String) arg2[0]; // normalize name 'key[]' to 'key'
if (paramName.endsWith("[]"))
paramName = paramName.substring(0,
paramName.length() - 2); if (requestParams.containsKey(paramName))
return new String[]{requestParams
.get(paramName)}; // if contains key[1], key[2]...
int i = 0;
List<String> paramValues = new ArrayList<String>();
while (true) {
String name2 = String.format("%s[%d]",
paramName, i++);
if (requestParams.containsKey(name2)) {
paramValues.add(requestParams.get(name2));
} else {
break;
}
} return paramValues.isEmpty() ? new String[0]
: paramValues.toArray(new String[0]);
} return arg1.invoke(request, arg2);
}
});
} /**
* 返回本地的tmp路径的File对象
* @param request
* @return
* @throws IOException
*/
private File getTempDir(HttpServletRequest request) throws IOException {
if (_tempDir != null)
return _tempDir; _tempDir = new File(_tempDirPath);
if (!_tempDir.isAbsolute()) {
_tempDir = new File(request.getServletContext().getRealPath(_tempDirPath));
} _tempDir.mkdirs();
_logger.info(String.format("using temp dir: %s", _tempDir.getCanonicalPath()));
return _tempDir;
} /**
* 获取所有的请求参数
* @return
*/
public Map getParameterMap(HttpServletRequest request ){
Map properties = request.getParameterMap();
Map returnMap = new HashMap();
Iterator entries = properties.entrySet().iterator();
String name = "";
String value = ""; while(entries.hasNext()) {
Map.Entry entry = (Map.Entry)entries.next();
name = (String)entry.getKey();
Object valueObj = entry.getValue();
if (valueObj == null) {
value = "";
} else if (!(valueObj instanceof String[])) {
value = valueObj.toString();
} else {
String[] values = (String[])valueObj; for(int i = 0; i < values.length; ++i) {
value = values[i] + ",";
} value = value.substring(0, value.length() - 1);
} _logger.info("参数 " + name + " == " + value);
returnMap.put(name, value);
} return returnMap;
}

文件缓存代理类

/**
* 文件代理类
*/
public class MultipleUploadItems { Logger _logger = Logger.getLogger(this.getClass());
List<FileItemStream> _items = new ArrayList<FileItemStream>();
File _tempDir; public List<FileItemStream> items() {
return _items;
} public MultipleUploadItems(File tempDir) {
_tempDir = tempDir;
} /**
* find items with given form field name
*
* @param fieldName
* @return
*/
public List<FileItemStream> items(String fieldName) {
List<FileItemStream> filteredItems = new ArrayList<FileItemStream>();
for (FileItemStream fis : _items) {
if (fis.getFieldName().equals(fieldName))
filteredItems.add(fis);
} return filteredItems;
} public void addItem(FileItemStream fis) {
_items.add(fis);
} public void addItemProxy(final FileItemStream item) throws IOException {
InputStream stream = item.openStream();
//ByteArrayOutputStream os = new ByteArrayOutputStream();
//create a temp source
final File source = File.createTempFile("elfinder_upload_", "", _tempDir);
FileOutputStream os = new FileOutputStream(source);
IOUtils.copy(stream, os);
os.close();
//final byte[] bs = os.toByteArray();
stream.close();
_logger.debug(String.format("saving item: %s", source.getCanonicalPath()));
addItem((FileItemStream) Proxy.newProxyInstance(this.getClass()
.getClassLoader(), new Class[]{FileItemStream.class, Finalizable.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
if ("openStream".equals(method.getName())) {
//return new ByteArrayInputStream(bs);
return new FileInputStream(source);
}
if ("finalize".equals(method.getName())) {
source.delete();
_logger.debug(String.format("removing item: %s", source.getCanonicalPath()));
return null;
}
return method.invoke(item, args);
}
}));
} public void writeInto(HttpServletRequest request)
throws FileUploadException, IOException {
// store items for compatablity
request.setAttribute(FileItemStream.class.getName(), _items);
request.setAttribute(MultipleUploadItems.class.getName(), this);
} /**
* 获取临时上传的文件
* @param request
* @return
*/
public static MultipleUploadItems loadFrom(HttpServletRequest request) {
return (MultipleUploadItems) request
.getAttribute(MultipleUploadItems.class.getName());
} /**
* 清除临时文件
* @param request
*/
public static void finalize(HttpServletRequest request) {
MultipleUploadItems mui = loadFrom(request);
if (mui != null) {
for (FileItemStream fis : mui.items()) {
if (fis instanceof Finalizable) {
((Finalizable) fis).finalize();
}
}
}
} interface Finalizable {
void finalize();
}
}

再springMVC中自定义文件上传处理解决与原spring中MultipartResolve冲突问题的更多相关文章

  1. (转)SpringMVC学习(九)——SpringMVC中实现文件上传

    http://blog.csdn.net/yerenyuan_pku/article/details/72511975 这一篇博文主要来总结下SpringMVC中实现文件上传的步骤.但这里我只讲单个文 ...

  2. 在WebBrowser中通过模拟键盘鼠标操控网页中的文件上传控件(转)

    引言 这两天沉迷了Google SketchUp,刚刚玩够,一时兴起,研究了一下WebBrowser. 我在<WebBrowser控件使用技巧分享>一文中曾谈到过“我现在可以通过WebBr ...

  3. MVC中的文件上传-小结

    web开发中,文件的上传是非常基本功能之一. 在asp.net中,通常做法是利用webservice 来接收文件请求,这样做的好处就是全站有了一个统一的文件上传接口,并且根据网站的实际情况,可以将we ...

  4. ASP.NET中的文件上传大小限制的问题

    一.文件大小限制的问题 首先我们来说一下如何解决ASP.NET中的文件上传大小限制的问题,我们知道在默认情况下ASP.NET的文件上传大小限制为2M,一般情况下,我们可以采用更改WEB.Config文 ...

  5. struts2中的文件上传,文件下载

    文件上传: Servlet中的文件上传回顾 前台页面 1.提交方式post 2.表单类型 multipart/form-data 3.input type=file 表单输入项 后台 apache提交 ...

  6. 转:在Struts 2中实现文件上传

    (本文转自:http://www.blogjava.net/max/archive/2007/03/21/105124.html) 前一阵子有些朋友在电子邮件中问关于Struts 2实现文件上传的问题 ...

  7. javaWeb中的文件上传下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  8. javaWeb中,文件上传和下载

    在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...

  9. JavaWeb中的文件上传和下载功能的实现

    导入相关支持jar包:commons-fileupload.jar,commons-io.jar 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上 ...

随机推荐

  1. what is HTTP OPTIONS verb

    The options verb is sent by browser to see if server accept cross origin request or not, this proces ...

  2. INDEX--创建索引和删除索引时的SCH_M锁

    最近有一个困惑,生产服务器上有一表索引建得乱七八糟,经过整理后需要新建几个索引,再删除几个索引,建立索引时使用联机(ONLINE=ON)创建,查看下服务器负载(磁盘和CPU压力均比较低的情况)后就选择 ...

  3. Oracle数据库中 to_date()与24小时制表示法及mm分钟的显示

      一.在使用Oracle的to_date函数来做日期转换时,时候也许会直接的采用“yyyy-MM-dd HH:mm:ss”的格式作为格式进行转换,但是在Oracle中会引起错误:“ORA 01810 ...

  4. 利用tensorflow训练简单的生成对抗网络GAN

    对抗网络是14年Goodfellow Ian在论文Generative Adversarial Nets中提出来的. 原理方面,对抗网络可以简单归纳为一个生成器(generator)和一个判断器(di ...

  5. JVM概念总结:数据类型、堆与栈

    Java虚拟机中,数据类型可以分为两类:基本类型和引用类型.基本类型的变量保存原始值,即:他代表的值就是数值本身: 引用类型的变量保存引用值,引用值代表了某个对象的引用而不是对象的本身,对象的本身存放 ...

  6. Java 反射机制系列

    http://www.cnblogs.com/KingIceMou/category/1034898.html

  7. php-echo原理

    1.语法分析 unticked_statement: | T_ECHO echo_expr_list ';' ; echo_expr_list: echo_expr_list TSRMLS_CC); ...

  8. Python封装

    什么是封装 在程序设计中,封装(Encapsulation)是对具体对象的一种抽象,即将某些部分隐藏起来,在程序外部看不到,其 含义是其他程序无法调用. 要了解封装,离不开“私有化”,就是将类或者是函 ...

  9. Visual Studio和eclipse的大小写转换快捷键

    Visual Studio: 转小写:ctrl + u 转大写:  ctrl + shift + u eclipse: 转小写:  ctrl + shift + y 转大写:  ctrl + shif ...

  10. 微信小程序自定义弹窗wcPop插件|仿微信弹窗样式

    微信小程序自定义组件弹窗wcPop|小程序消息提示框|toast自定义模板弹窗 平时在开发小程序的时候,弹窗应用场景还是蛮广泛的,但是微信官方提供的弹窗比较有局限性,不能自定义修改.这个时候首先想到的 ...