1. 程式人生 > >common-fileUpload和 Spring中MultipartHttpServletRequest實現檔案上傳、以及過濾器的問題

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)

*使用apache-commons-fileupload 上傳

*使用springmvc下的spring-webmvc (MultipartFile )上傳

1、使用apache-commons-fileupload 上傳

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”));