一、遇到的问题:
接口上传了一个文件,从HttpServletRequest 中获取了文件名、文件内容等信息,后面再从HttpServletRequest 中读取文件名信息、文件内容就读取不到了
二、原因:
因为流是单向的,就像水一样被舀了一瓢就会少一瓢。所以 HttpServletRequest 对象中的 InputStream 或者 Reader 只能使用一次。
三、解决办法:
那该怎么办,复制一份HttpServletRequest 对象,把流转为字节数组存储,使用时再从字节数组中获取,可以解决。
1.用到以下依赖将输入流转化为字节数组:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
2.MyHttpServletRequest类继承HttpServletRequestWrapper:
import org.apache.commons.io.IOUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class MyHttpServletRequest extends HttpServletRequestWrapper {
private byte[] body;
public MyHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
try {
body = IOUtils.toByteArray(request.getInputStream());
} catch (IOException ex) {
body = new byte[0];
}
}
@Override
public ServletInputStream getInputStream() throws IOException {
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
ByteArrayInputStream bais = new ByteArrayInputStream(body);
@Override
public int read() throws IOException {
return bais.read();
}
};
}
}
四、测试:
测试里用到以下依赖来获取文件信息:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.2</version>
</dependency>
public void addNewAttachment(HttpServletRequest request, HttpServletResponse response) throws Exception {
//将request转化为newRequest,便可以使用newRequest多次读取流了
HttpServletRequest newRequest = new MyHttpServletRequestWrapper(request);
//第一次读取
FileItemFactory firlfact1 = new DiskFileItemFactory();
ServletFileUpload sfu1 = new ServletFileUpload(firlfact1);
List<FileItem> list1 = sfu1.parseRequest(newRequest);
for (FileItem fileItem : list1) {
DiskFileItem diskFileItem = (DiskFileItem) fileItem;
String fileName = diskFileItem.getName();
System.out.println(fileName);
}
//第二次读取
FileItemFactory firlfact2 = new DiskFileItemFactory();
ServletFileUpload sfu2 = new ServletFileUpload(firlfact2);
List<FileItem> list2 = sfu1.parseRequest(newRequest);
for (FileItem fileItem : list2) {
DiskFileItem diskFileItem = (DiskFileItem) fileItem;
String fileName = diskFileItem.getName();
tem.out.println(fileName);
}
}
参考:
How to read request.getInputStream() multiple times
HttpServletRequestWrapper example – read httpservletrequest twice