相信很多朋友再用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. Python学习-18.Python中的错误处理(三)

    在某些情况下,我们需要定义自己的异常并且抛出 先定义一个错误: class MyError(BaseException): def __init__(self): pass 上面定义了一个叫MyErr ...

  2. 在 IIS8 中保持网站持续运行

    在早期版本的 IIS 中执行轮询任务不那么可靠.应用程序池回收后,网站不会自动重启,在新的请求激活应用程序之前,轮询任务不起作用.为了解决这个问题,需要引入外力驱动 Web 端执行任务,如图: 此方式 ...

  3. Mac iTerm2登陆CentOS提示warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory

    [报错原因]:没有utf-8这个语系(没添加语言_国名前缀),LC_ALL又没设定值. 服务端解决方法: 在远程系统上, /etc/environment 加入以下两行,重新登陆即可. LANG=en ...

  4. C#实现在图片上动态写内容

    之前在项目上遇到这么一个需求,就是要在图片上写内容,而且要求是动态,我所谓的动态就是在图片上写的内容是动态的.网上找了找,很多人实现了网图片上写内容的功能,但是,并没有实现动态.所以在这里把我的解决办 ...

  5. C# Linq 学习笔记

    刚刚学习了 Siki老师 的C#教程Linq部分,以下是笔记 需要引用命名空间 using System.Linq; 然后我们需要准备数据 武林高手类 /// <summary> /// ...

  6. 微信游戏《全民炫舞》开发公司h3d2 engine和QQ炫舞2 布料系统技术介绍

    H3D公司开发的<全民炫舞>上线了. 蝉联IOS榜首很多天. 整理了一下过去公司游戏引擎开发的历史.有兴趣可以去看看 公司游戏引擎开发历史介绍: http://www.h3d.com.cn ...

  7. 20164317《网络对抗技术》Exp3 免杀原理与实践

    一.实验要求 1.1 正确使用msf编码器(0.5分),msfvenom生成如jar之类的其他文件(0.5分),veil-evasion(0.5分),加壳工具(0.5分),使用shellcode编程( ...

  8. 配置阿里yum源,设置命令

    配置阿里yum源 #linux的软件包管理 安装 软件的方式有三种 .源代码编译安装() .下载python3的源代码 .解压缩源代码 .进入源代码目录,开始编译安装 .配置环境变量 .yum方式安装 ...

  9. JQuery Mobile - 如何让listview不显示向右的箭头?

    先看一下有向右箭头的截图吧 这个listview第二个项目,就有向右的箭头,如果单纯显示具体数据,没有扩展显示的内容,那么这个向右的箭头就是多余的,在这种情况下,最好是去掉这个向右箭头,程序中已经在第 ...

  10. 记一次生产发版时SpringBoot服务停用启用的问题

    近期项目交接,接手了个SpringBoot项目.生产环境里,jar包是通过软链接做成linux服务来启动和停用. 然而,每次通过jenkins构建发版,项目构建完毕,还要手动再去重启服务. 听交接的同 ...