struts2上传文件的File属性如何装载
2009-01-12 17:15
316 查看
struts2的文件上传很容易,特别是对上传文件的2进制流解析,操作很透明。只要action有个File类型的属性给setter方法就直接把2进制文件给封装成File了。
开始的时候,我是打算在在servlet中手动解析的,后发现太繁琐要判断2进制文件流的开始和结束还有及加载其中的表单域,还要考率超大文件的内存溢出问题。TMD真不爽。后来打算借鉴一下struts2的代码。但是,struts2怎么把2进制文件变成了File了? File是通常是关联到本地操作系统上的文件,上传的文件是封装在request对象中的,怎么能封装成本地的文件,难道是先传到临时目录在写到指定目录,但考虑到性能问题应该是边传边写的啊。
不知道很不爽啊,感觉就是gf背着你和别的帅哥出去约会一样,并且约会的人是struts2团队的一个老外,想想就更不爽了。于是我就是开始看源码。struts2的上传是用拦截器实现的,打开struts2-core.jar包很容易找到org.apache.struts2.interceptor
这个包,以后瞅瞅一眼就看到FileUploadInterceptor.class这个文件了。打开相应的源码:
/*
*.省略导入文件
*/
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext ac = invocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);
if (!(request instanceof MultiPartRequestWrapper)) {
if (LOG.isDebugEnabled()) {
ActionProxy proxy = invocation.getProxy();
LOG.debug(getTextMessage("struts.messages.bypass.request", new Object[]{proxy.getNamespace(), proxy.getActionName()}, ActionContext.getContext().getLocale()));
}
return invocation.invoke();
}
final Object action = invocation.getAction();
ValidationAware validation = null;
if (action instanceof ValidationAware) {
validation = (ValidationAware) action;
}
MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) request;
if (multiWrapper.hasErrors()) {
for (Iterator errorIter = multiWrapper.getErrors().iterator(); errorIter.hasNext();) {
String error = (String) errorIter.next();
if (validation != null) {
validation.addActionError(error);
}
LOG.error(error);
}
}
Map parameters = ac.getParameters();
// Bind allowed Files
Enumeration fileParameterNames = multiWrapper.getFileParameterNames();
while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {
// get the value of this input tag
String inputName = (String) fileParameterNames.nextElement();
// get the content type
String[] contentType = multiWrapper.getContentTypes(inputName);
if (isNonEmpty(contentType)) {
// get the name of the file from the input tag
String[] fileName = multiWrapper.getFileNames(inputName);
if (isNonEmpty(fileName)) {
// Get a File object for the uploaded File
//这里这么就一下得到file了,看来是multiWrapper的问题
File[] files = multiWrapper.getFiles(inputName);
if (files != null) {
for (int index = 0; index < files.length; index++) {
if (acceptFile(files[index], contentType[index], inputName, validation, ac.getLocale())) {
parameters.put(inputName, files);
parameters.put(inputName + "ContentType", contentType);
parameters.put(inputName + "FileName", fileName);
}
}
}
} else {
LOG.error(getTextMessage("struts.messages.invalid.file", new Object[]{inputName}, ActionContext.getContext().getLocale()));
}
} else {
LOG.error(getTextMessage("struts.messages.invalid.content.type", new Object[]{inputName}, ActionContext.getContext().getLocale()));
}
}
// invoke action
String result = invocation.invoke();
// cleanup
fileParameterNames = multiWrapper.getFileParameterNames();
while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {
String inputValue = (String) fileParameterNames.nextElement();
File[] file = multiWrapper.getFiles(inputValue);
for (int index = 0; index < file.length; index++) {
File currentFile = file[index];
if(LOG.isInfoEnabled()) {
LOG.info(getTextMessage("struts.messages.removing.file", new Object[]{inputValue, currentFile}, ActionContext.getContext().getLocale()));
}
if ((currentFile != null) && currentFile.isFile()) {
currentFile.delete();
}
}
}
return result;
}
/*
*省略一些代码
*/
}
multiWrapper是MultiPartRequestWrapper是这个类型的所以继续产看MultiPartRequestWrapper的代码
public class MultiPartRequestWrapper extends StrutsRequestWrapper {
protected static final Logger LOG = LoggerFactory.getLogger(MultiPartRequestWrapper.class);
Collection<String> errors;
// MultiPartRequest 是得到file的关键
MultiPartRequest multi;
public MultiPartRequestWrapper(MultiPartRequest multiPartRequest, HttpServletRequest request, String saveDir) {
super(request);
multi = multiPartRequest;
try {
multi.parse(request, saveDir);
for (Object o : multi.getErrors()) {
String error = (String) o;
addError(error);
}
} catch (IOException e) {
addError("Cannot parse request: "+e.toString());
}
}
public File[] getFiles(String fieldName) {
if (multi == null) {
return null;
}
//通过multi得到File的
return multi.getFile(fieldName);
}
}
综上我开始查看MultiPartRequest类,但是发现他是个接口,nnd没办法 只有找他的实现类,结果发现是JakartaMultiPartRequest,名字帅的很啊。那就看代码:
public class JakartaMultiPartRequest implements MultiPartRequest {
static final Logger LOG = LoggerFactory.getLogger(MultiPartRequest.class);
// maps parameter name -> List of FileItem objects
private Map<String,List<FileItem>> files = new HashMap<String,List<FileItem>>();
// maps parameter name -> List of param values
private Map<String,List<String>> params = new HashMap<String,List<String>>();
// any errors while processing this request
private List<String> errors = new ArrayList<String>();
private long maxSize;
@Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE)
public void setMaxSize(String maxSize) {
this.maxSize = Long.parseLong(maxSize);
}
//主要就是这个方法解析了request并封装成了File类型
很明显使用了commons-fileupload.jar的框架
public void parse(HttpServletRequest servletRequest, String saveDir)
throws IOException {
DiskFileItemFactory fac = new DiskFileItemFactory();
// Make sure that the data is written to file
//控制上传文件大小的阀值设置成了0,这就会直接写到临时文件去了
fac.setSizeThreshold(0);
if (saveDir != null) {
//设置临时目录
fac.setRepository(new File(saveDir));
}
// Parse the request
try {
ServletFileUpload upload = new ServletFileUpload(fac);
upload.setSizeMax(maxSize);
List items = upload.parseRequest(createRequestContext(servletRequest));
for (Object item1 : items) {
FileItem item = (FileItem) item1;
if (LOG.isDebugEnabled()) LOG.debug("Found item " + item.getFieldName());
if (item.isFormField()) {
LOG.debug("Item is a normal form field");
List<String> values;
if (params.get(item.getFieldName()) != null) {
values = params.get(item.getFieldName());
} else {
values = new ArrayList<String>();
}
// note: see http://jira.opensymphony.com/browse/WW-633
// basically, in some cases the charset may be null, so
// we're just going to try to "other" method (no idea if this
// will work)
String charset = servletRequest.getCharacterEncoding();
if (charset != null) {
values.add(item.getString(charset));
} else {
values.add(item.getString());
}
params.put(item.getFieldName(), values);
} else {
LOG.debug("Item is a file upload");
// Skip file uploads that don't have a file name - meaning that no file was selected.
if (item.getName() == null || item.getName().trim().length() < 1) {
LOG.debug("No file has been uploaded for the field: " + item.getFieldName());
continue;
}
List<FileItem> values;
if (files.get(item.getFieldName()) != null) {
values = files.get(item.getFieldName());
} else {
values = new ArrayList<FileItem>();
}
values.add(item);
//把解析出来的文件都放到这里
files.put(item.getFieldName(), values);
}
}
} catch (FileUploadException e) {
LOG.error("Unable to parse request", e);
errors.add(e.getMessage());
}
}
//根据文件名返回File数组
public File[] getFile(String fieldName) {
List items = (List) files.get(fieldName);
if (items == null) {
return null;
}
List<File> fileList = new ArrayList<File>(items.size());
for (int i = 0; i < items.size(); i++) {
DiskFileItem fileItem = (DiskFileItem) items.get(i);
fileList.add(fileItem.getStoreLocation());
}
return (File[]) fileList.toArray(new File[fileList.size()]);
}
}
开始的时候,我是打算在在servlet中手动解析的,后发现太繁琐要判断2进制文件流的开始和结束还有及加载其中的表单域,还要考率超大文件的内存溢出问题。TMD真不爽。后来打算借鉴一下struts2的代码。但是,struts2怎么把2进制文件变成了File了? File是通常是关联到本地操作系统上的文件,上传的文件是封装在request对象中的,怎么能封装成本地的文件,难道是先传到临时目录在写到指定目录,但考虑到性能问题应该是边传边写的啊。
不知道很不爽啊,感觉就是gf背着你和别的帅哥出去约会一样,并且约会的人是struts2团队的一个老外,想想就更不爽了。于是我就是开始看源码。struts2的上传是用拦截器实现的,打开struts2-core.jar包很容易找到org.apache.struts2.interceptor
这个包,以后瞅瞅一眼就看到FileUploadInterceptor.class这个文件了。打开相应的源码:
/*
*.省略导入文件
*/
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext ac = invocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);
if (!(request instanceof MultiPartRequestWrapper)) {
if (LOG.isDebugEnabled()) {
ActionProxy proxy = invocation.getProxy();
LOG.debug(getTextMessage("struts.messages.bypass.request", new Object[]{proxy.getNamespace(), proxy.getActionName()}, ActionContext.getContext().getLocale()));
}
return invocation.invoke();
}
final Object action = invocation.getAction();
ValidationAware validation = null;
if (action instanceof ValidationAware) {
validation = (ValidationAware) action;
}
MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) request;
if (multiWrapper.hasErrors()) {
for (Iterator errorIter = multiWrapper.getErrors().iterator(); errorIter.hasNext();) {
String error = (String) errorIter.next();
if (validation != null) {
validation.addActionError(error);
}
LOG.error(error);
}
}
Map parameters = ac.getParameters();
// Bind allowed Files
Enumeration fileParameterNames = multiWrapper.getFileParameterNames();
while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {
// get the value of this input tag
String inputName = (String) fileParameterNames.nextElement();
// get the content type
String[] contentType = multiWrapper.getContentTypes(inputName);
if (isNonEmpty(contentType)) {
// get the name of the file from the input tag
String[] fileName = multiWrapper.getFileNames(inputName);
if (isNonEmpty(fileName)) {
// Get a File object for the uploaded File
//这里这么就一下得到file了,看来是multiWrapper的问题
File[] files = multiWrapper.getFiles(inputName);
if (files != null) {
for (int index = 0; index < files.length; index++) {
if (acceptFile(files[index], contentType[index], inputName, validation, ac.getLocale())) {
parameters.put(inputName, files);
parameters.put(inputName + "ContentType", contentType);
parameters.put(inputName + "FileName", fileName);
}
}
}
} else {
LOG.error(getTextMessage("struts.messages.invalid.file", new Object[]{inputName}, ActionContext.getContext().getLocale()));
}
} else {
LOG.error(getTextMessage("struts.messages.invalid.content.type", new Object[]{inputName}, ActionContext.getContext().getLocale()));
}
}
// invoke action
String result = invocation.invoke();
// cleanup
fileParameterNames = multiWrapper.getFileParameterNames();
while (fileParameterNames != null && fileParameterNames.hasMoreElements()) {
String inputValue = (String) fileParameterNames.nextElement();
File[] file = multiWrapper.getFiles(inputValue);
for (int index = 0; index < file.length; index++) {
File currentFile = file[index];
if(LOG.isInfoEnabled()) {
LOG.info(getTextMessage("struts.messages.removing.file", new Object[]{inputValue, currentFile}, ActionContext.getContext().getLocale()));
}
if ((currentFile != null) && currentFile.isFile()) {
currentFile.delete();
}
}
}
return result;
}
/*
*省略一些代码
*/
}
multiWrapper是MultiPartRequestWrapper是这个类型的所以继续产看MultiPartRequestWrapper的代码
public class MultiPartRequestWrapper extends StrutsRequestWrapper {
protected static final Logger LOG = LoggerFactory.getLogger(MultiPartRequestWrapper.class);
Collection<String> errors;
// MultiPartRequest 是得到file的关键
MultiPartRequest multi;
public MultiPartRequestWrapper(MultiPartRequest multiPartRequest, HttpServletRequest request, String saveDir) {
super(request);
multi = multiPartRequest;
try {
multi.parse(request, saveDir);
for (Object o : multi.getErrors()) {
String error = (String) o;
addError(error);
}
} catch (IOException e) {
addError("Cannot parse request: "+e.toString());
}
}
public File[] getFiles(String fieldName) {
if (multi == null) {
return null;
}
//通过multi得到File的
return multi.getFile(fieldName);
}
}
综上我开始查看MultiPartRequest类,但是发现他是个接口,nnd没办法 只有找他的实现类,结果发现是JakartaMultiPartRequest,名字帅的很啊。那就看代码:
public class JakartaMultiPartRequest implements MultiPartRequest {
static final Logger LOG = LoggerFactory.getLogger(MultiPartRequest.class);
// maps parameter name -> List of FileItem objects
private Map<String,List<FileItem>> files = new HashMap<String,List<FileItem>>();
// maps parameter name -> List of param values
private Map<String,List<String>> params = new HashMap<String,List<String>>();
// any errors while processing this request
private List<String> errors = new ArrayList<String>();
private long maxSize;
@Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE)
public void setMaxSize(String maxSize) {
this.maxSize = Long.parseLong(maxSize);
}
//主要就是这个方法解析了request并封装成了File类型
很明显使用了commons-fileupload.jar的框架
public void parse(HttpServletRequest servletRequest, String saveDir)
throws IOException {
DiskFileItemFactory fac = new DiskFileItemFactory();
// Make sure that the data is written to file
//控制上传文件大小的阀值设置成了0,这就会直接写到临时文件去了
fac.setSizeThreshold(0);
if (saveDir != null) {
//设置临时目录
fac.setRepository(new File(saveDir));
}
// Parse the request
try {
ServletFileUpload upload = new ServletFileUpload(fac);
upload.setSizeMax(maxSize);
List items = upload.parseRequest(createRequestContext(servletRequest));
for (Object item1 : items) {
FileItem item = (FileItem) item1;
if (LOG.isDebugEnabled()) LOG.debug("Found item " + item.getFieldName());
if (item.isFormField()) {
LOG.debug("Item is a normal form field");
List<String> values;
if (params.get(item.getFieldName()) != null) {
values = params.get(item.getFieldName());
} else {
values = new ArrayList<String>();
}
// note: see http://jira.opensymphony.com/browse/WW-633
// basically, in some cases the charset may be null, so
// we're just going to try to "other" method (no idea if this
// will work)
String charset = servletRequest.getCharacterEncoding();
if (charset != null) {
values.add(item.getString(charset));
} else {
values.add(item.getString());
}
params.put(item.getFieldName(), values);
} else {
LOG.debug("Item is a file upload");
// Skip file uploads that don't have a file name - meaning that no file was selected.
if (item.getName() == null || item.getName().trim().length() < 1) {
LOG.debug("No file has been uploaded for the field: " + item.getFieldName());
continue;
}
List<FileItem> values;
if (files.get(item.getFieldName()) != null) {
values = files.get(item.getFieldName());
} else {
values = new ArrayList<FileItem>();
}
values.add(item);
//把解析出来的文件都放到这里
files.put(item.getFieldName(), values);
}
}
} catch (FileUploadException e) {
LOG.error("Unable to parse request", e);
errors.add(e.getMessage());
}
}
//根据文件名返回File数组
public File[] getFile(String fieldName) {
List items = (List) files.get(fieldName);
if (items == null) {
return null;
}
List<File> fileList = new ArrayList<File>(items.size());
for (int i = 0; i < items.size(); i++) {
DiskFileItem fileItem = (DiskFileItem) items.get(i);
fileList.add(fileItem.getStoreLocation());
}
return (File[]) fileList.toArray(new File[fileList.size()]);
}
}
相关文章推荐
- struts2文件上传中action类中File类型的属性剖析
- 通过input 的file 控件,上传图片,如何获取文件的大小问题
- java /Spring /jsp 使用input标签 file 如何上传多个文件
- 如何在struts2中上传和下载文件
- html5中的input(type="file")的multiple属性,实现多文件上传,并用js控制文件大小,数量
- ajaxFileUpload+struts2实现异步上传文件
- struts2 上传文件得到的是.tmp 如何得到原有文件名
- 如何设置上传文件控件 input type="file" 的 默认值
- 如何在struts2中结合HttpClient进行文件上传
- ajaxFileUpload+struts2实现多文件上传
- struts2文件上传中,如何限制上传的文件类型
- Struts2-文件上传-<s:file>标签使用
- struts2 如何动态限制控制文件图片上传大小?
- 如何解决struts2中上传文件大小限制的问题
- struts2 上传文件在action 里的属性 name
- FCK和struts2整合,文件上传的时候出现error on file upload,error number:203
- ajaxFileUpload+struts2实现多文件上传
- struts2文件上传如何限制上传文件类型(类型列表)
- struts2如何保存上传后的文件
- struts2文件上传file,contentType,fileName出现null