common-fileUpload和 Spring中MultipartHttpServletRequest實現檔案上傳、以及過濾器的問題
遇到一個專案中寫的過濾器有些不明白為什麼那麼寫,其實就是以下的第二部分不理解造成的
二、 使用servlet時:多部件表單上傳對servlet取值問題
1) request.getParameter("..."),這個方法在表單為multiparty/form-data中取不到值
2) 但是我們可以使用 ServletInputStream request.getInputStream();來獲取流資訊
過濾器程式碼MyFilter:
package com.syb.webapp.common.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import com.syb.core.util.StringUtil; /** * * @author sun * * tcl */ public class MyFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String contentType = request.getContentType(); if(!StringUtil.isEmpty(contentType) && contentType.contains("multipart/form-data")) { chain.doFilter(request, response); return; } if(request instanceof HttpServletRequest) { request=new MyHttpServlerRequestWrapper((HttpServletRequest)request); } chain.doFilter(request, response); } @Override public void destroy() { } }
MyHttpServlerRequestWrapper:
package com.syb.webapp.common.filter; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.mock.web.DelegatingServletInputStream; import com.alibaba.fastjson.JSON; /** * * @author sun * * tcl */ public class MyHttpServlerRequestWrapper extends HttpServletRequestWrapper{ public static Logger logger=LoggerFactory.getLogger(MyHttpServlerRequestWrapper.class); private String body=null; private HttpServletRequest request; public MyHttpServlerRequestWrapper(HttpServletRequest request) { super(request); this.request=request; } @Override public ServletInputStream getInputStream() throws IOException { if(body!=null) { final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes()); return new DelegatingServletInputStream(byteArrayInputStream);//此方法作用? } StringBuilder stringBuilder=new StringBuilder(); InputStream inputStream=null; try { inputStream=request.getInputStream(); } catch (Exception e) { logger.error("Error reading the request body…", e); } if(inputStream!=null) { try { BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream)); char[] charBuffer=new char[1024]; int read; while((read=bufferedReader.read(charBuffer))>0) { stringBuilder.append(charBuffer, 0, read); } } catch (Exception e) { logger.error("Fail to read input stream", e); } }else { stringBuilder.append(""); } body=stringBuilder.toString(); final ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(body.getBytes()); return new DelegatingServletInputStream(byteArrayInputStream); } public String getRequestParam() { if("GET".equals(this.getMethod())) { return JSON.toJSONString(getParameterMap()); } if("POST".equals(this.getMethod())) { String contentType = this.getContentType(); if(contentType.contains("applycation/json")) { return this.body; } if(contentType.contains("application/x-www-form-urlencoded")) { return JSON.toJSONString(getParameterMap()); } } return null; } }
以下內容轉自:http://blog.csdn.net/u011278387/article/details/50839034
一、上傳對錶單的要求
1) 表單的提交方式 :"method=post"
2) 表單的型別 :enctype="multipart/form-data"
3) 上傳表單的檔案項:<input type="file" name="xx" /> //其中名字是必須要的
例如: <h1>上傳</h1>
<h2><font color="red"></font></h2>
<form action="" method="post" enctype="multipart/form-data"/>
<p>使用者名稱:<input name="userName" type="text"/></p>
<p>檔案:<input name="xx" type="file"/></br></p>
<p><input type="submit" value="上傳"/></p>
</form>
二、 使用servlet時:多部件表單上傳對servlet取值問題
1) request.getParameter("..."),這個方法在表單為multiparty/form-data中取不到值
2) 但是我們可以使用 ServletInputStream request.getInputStream();來獲取流資訊
三、 多部件表單與普通表單的結構
1) 普通表單項結構 1個頭:content-Disposition,包含name="XXX" 即表單的名字, 表單體就是表單的值
2) 多部件表單普通表單結構 含有2個頭
*content-Disposition,包含name="xx",filname="上傳檔案的路徑";
*content-type: 指上傳的檔案型別,如上傳的是圖片的話格式則為:image/jpeg
四、上傳的元件(這裡介紹2種)
1、使用apache-commons-fileupload 上傳*使用apache-commons-fileupload 上傳
*使用springmvc下的spring-webmvc (MultipartFile )上傳
1) commons-fileupload
*需要的jar(網上可以下載)
commons-fileupload
要使用流所以需要commons-io.jar;
2)上傳三步
*工廠:DiskFileItemFactory
*解析器:ServletFileUpload
*表單項:FileItem
3)相關程式碼
*建立工廠
DiskFileItemFactory fac = new DiskFileItemFactory();
*建立解析器
ServletFileUpLoad sfp = new ServletFileUpLoad(fac);
*使用解析器 獲取FileItem 集合 List<FileItem> items = sfp.parseRequest(reques);
*看下 FileItem的方法
String filename = file.getName(); //檔名稱
String getFileName(); //返回當前表單項的名稱
String fileStr = file.getString(String charset); //返回表單的值;
long fileSize = file.getSize(); //檔案的位元組數
InputStream in = file.getInputStream(); //檔案的對應輸入流
void write(file destFile); //將檔案儲存到指定的目錄
程式碼例子:
request.setCharacterEncoding("utf-8"); //編碼
//建立工廠
DiskFileItemFactory factory = new DiskFileItemFactory();
//建立解析器
ServletFileUpload sfl = new ServletFileUpload(factory);
try {
//解析
List<FileItem> im = sfl.parseRequest(request);
FileItem f1 = im.get(0);
System.out.println("多部件表單項的檔案:"+f1.getFieldName()
+"---名稱:"+f1.getName()+"檔案大小:"+f1.getSize());
try {
//寫往磁碟(也可以寫到伺服器的相應地址)
f1.write(new File("e:\\photo\\cc.jpg"));
} catch (Exception e) {
e.printStackTrace();
}
} catch (FileUploadException e) {
e.printStackTrace();
}
-------------------------------------------
五、上傳的細節2、使用MultipartFile
1) 由於Post一個包含檔案上傳的Form會以multipart/form-data請求傳送給服務 器,必須明確告訴轉發器(DispatcherServlet)如何處理MultipartRequest。首先在專案 配置檔案中宣告一個MultipartResolver:
2) xml 程式碼
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 設定上傳檔案的最大尺寸為1MB(也可以不配置而在程式碼中限制上傳的檔案大小) -->
<property name="maxUploadSize">
<value>1048576</value>
</property>
</bean>
3)、上傳步驟
*請求轉化為多部件的請求
MultipartHttpServletRequest mulReq= (MultipartHttpServletRequest) request;
*獲取
MultipartFile mfile= mulReq.getFile(“多部件表單值的name”);
*寫入到相應的目錄
mfile.transferTo(new File(path));
4)、程式碼例子:
//轉化request
MultipartHttpServletRequest mulReq= (MultipartHttpServletRequest) request;
//獲取上傳表單的name值
String picName = request.getParameter(“picName”);
//解析為多部件檔案
MultipartFile mfile = mulReq.getFile(picName);
//僅僅允許圖片格式
List<String> fileTypes = new ArrayList<String>();
fileTypes.add("jpg");
fileTypes.add("jpeg");
fileTypes.add("bmp");
fileTypes.add("gif");
fileTypes.add("png");
//取得原檔名稱
String orifilename = mfile.getOriginalFilename();
//獲取副檔名
String extensionName=orifilename.substring(orifilename.lastIndexOf(".")+1);
//校驗副檔名
if ( fileTypes.contains(extensionName.toLowerCase())) {
//限制圖片的大小
if(file.getSize() <= 5 * 1024*1024){
mfile.transferTo(new File(path));
}
}
--------------------------------------------
1、檔案儲存在專案的路徑
*檔案儲存可以在web-inf下(安全問題)其他目錄下可能被注入非法程式)
*上傳的檔案儲存webRoot下(因為很多其他的專案都可能要用到上傳的檔案)
2、上傳檔案格式和大小:
*要求上傳的檔案格式為jpg,就不能上傳其他格式
上傳的時候就必須要限制上傳的檔案型別,最好的做法是在前端和後臺都做下校驗。
*上傳檔案的大小需要按要求做限制
3、檔名稱問題:
*上傳檔案出現重名,所以需要我們為檔案加個字首,字首不能重複。可以是uuid (UUID uuid = UUID.randomUUID();)或者時間(System.currentTimeMillis())
*上傳檔案亂碼問題
可以使用這個request.setCharacterEncoding("utf-8");
4、檔案目錄
目錄打撒 一個目錄下不能存放太多的檔案,不同的上傳功能目錄應該歸類存放。
5、快取大小與臨時目錄(主要針對大檔案上傳的)。
Common-FileUpload 中可以設定快取大小和臨時目錄(預設是10k)
方法:DiskFileItemFactory(int sizeThreshold, File repository)
sizeThreshold為定義的快取大小,repository為快取目錄
如 DiskFileItemFactory fa = new DiskFileItemFactory(2*1024, new File(“F:/temp”));