相信不少朋友再用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方法java
以前的項目代碼不能知足咱們的要求因此咱們修改了,spring的CommonsMultipartResolver類來自定義咱們的上傳方法,大概思路時,代理當前HttpServletRequest,被代理的HttpServletRequest返回的是一個代理類,在isMultipart方法中判斷有無被代理這樣就能夠實現咱們本身的文件上傳處理邏輯了web
首先咱們先自定義一個文件上傳的過濾器Filterspring
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請求,因此其中的某些數據會被過濾,好比登陸信息,因此必定要配置在登陸過濾後面,這樣纔不會影響正常的框架,其餘的過濾器因項目須要稍做更改mvc
下面是代理HttpServletRequest的過濾器代碼app
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配置文件中修改爲咱們已經寫好的類路徑ide
<bean id="multipartResolver" class="com.cn.interceptor.CommonsMultipartResolver"> <property name="maxUploadSize" value="100000000" /> </bean>
至此,整個框架正常的流程代碼已經完成,咱們能夠開心的寫咱們的業務代碼啦ui
下面是一個文件上傳的代碼,使用java1.7中NIO,比spring代碼的操做文件流快了不少this
寫在過濾其中的代碼
/** * 解析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(); } }