struts2 文件上传/下载/乱码 碎碎念

我的环境

英文windows xp

location :United states

language for non-Unicode program: Chinese(PRC)

tomcat 6.0

struts2-core-2.2.1

 

网上关于struts file upload/download的文章好多地雷。在我的环境中,花了一个星期才把struts2下上传下载都调好,以下是一点经验。

 

1)使用缺省的jakarta上传空文件会抛出NullPointerException,你可以自己捕捉FileNotFoundException然后自己给一个空的byte[],也可以换用其他的file upload component,比如cos。jakarta把request转存到本时会给一个uuid,cos则是存成request中的fileName。尽管每次处理完这个temp file都会被删掉,但大量并发时上传同名文件还是会有冲突(后一个覆盖前一个)

2)如果你想用cos的话,一定注意,google出来前几个配法都是不成功的 ,正确的配法是

2.1)写一个自己的cos->struts Adaptor (我也是网上找的)

package myapp.view.action.common;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.dispatcher.multipart.MultiPartRequest;

import com.oreilly.servlet.multipart.FilePart;
import com.oreilly.servlet.multipart.MultipartParser;
import com.oreilly.servlet.multipart.ParamPart;
import com.oreilly.servlet.multipart.Part;

@SuppressWarnings("unchecked")
public class CosMultiPartRequest implements MultiPartRequest {
	private static Log log = LogFactory.getLog(CosMultiPartRequest.class);
	private ArrayList<File> alFile;
	private Hashtable<String, ArrayList<?>> files;
	private ArrayList<String> fileNames;
	private ArrayList<String> contentType;
	private ArrayList<String> fileSystemName;
	private Hashtable<String, ArrayList<String>> parameters;
	private Hashtable<String, ArrayList<?>> filePara;
	private ArrayList<String> paraValues;
	private String encode;

	public CosMultiPartRequest() {
		super();
	}

	public String getEncode() {
		return encode;
	}

	public void setEncode(String encode) {
		this.encode = encode;
	}

	public String[] getContentType(String arg0) {
		ArrayList<String> aList = (ArrayList<String>) files.get(arg0
				+ "_ContentType");
		String[] str = new String[aList.size()];
		for (int i = 0; i < aList.size(); i++) {
			str[i] = aList.get(i);
		}
		return str;
	}

	public List getErrors() {
		return Collections.EMPTY_LIST;
	}

	public File[] getFile(String arg0) {
		ArrayList<File> aList = (ArrayList<File>) files.get(arg0);
		File[] file = new File[aList.size()];
		for (int i = 0; i < aList.size(); i++) {
			file[i] = aList.get(i);
		}
		return file;
	}

	public String[] getFileNames(String arg0) {
		ArrayList<String> aList = (ArrayList<String>) files.get(arg0 + "_name");
		String[] stt = new String[aList.size()];
		for (int i = 0; i < aList.size(); i++) {
			stt[i] = aList.get(i);
		}
		return stt;
	}

	public Enumeration<String> getFileParameterNames() {
		return filePara.keys();
	}

	public String[] getFilesystemName(String arg0) {
		ArrayList<String> arrayList = (ArrayList<String>) files.get(arg0
				+ "_SysName");
		String[] ss = new String[arrayList.size()];
		for (int i = 0; i < arrayList.size(); i++) {
			ss[i] = arrayList.get(i);
		}
		return ss;
	}

	public String getParameter(String arg0) {
		if (parameters.keySet().contains(arg0))
			return arg0;
		return "";
	}

	public Enumeration<String> getParameterNames() {
		return parameters.keys();
	}

	public String[] getParameterValues(String arg0) {

		ArrayList<String> al = parameters.get(arg0);
		String[] str = new String[al.size()];
		for (int i = 0; i < al.size(); i++) {
			str[i] = al.get(i);
		}
		return str;
	}

	public void parse(HttpServletRequest request, String saveDir)
			throws IOException {
		if (log.isDebugEnabled()) {
			log.debug("Parse by CosMultiPartRequest");
		}

		MultipartParser mp = new MultipartParser(request, 1024 * 1024 * 10);
		// actually ,should be injected
		mp.setEncoding("UTF-8");
		Part part;

		files = new Hashtable<String, ArrayList<?>>();
		alFile = new ArrayList<File>();
		fileNames = new ArrayList<String>();
		fileSystemName = new ArrayList<String>();
		contentType = new ArrayList<String>();
		filePara = new Hashtable<String, ArrayList<?>>();
		paraValues = new ArrayList<String>();
		parameters = new Hashtable<String, ArrayList<String>>();

		for (int i = 0; (part = mp.readNextPart()) != null; i++) {
			if (part.isFile()) {
				FilePart fp = (FilePart) part;

				alFile = (ArrayList) files.get(fp.getName());
				if (alFile == null || alFile.size() < 1) {
					alFile = new ArrayList();
				}
				File fil = new File(saveDir + fp.getFileName());
				fp.writeTo(fil);
				alFile.add(fil);

				fileNames = (ArrayList) files.get(fp.getName() + "_name");
				if (fileNames == null || fileNames.size() < 1) {
					fileNames = new ArrayList<String>();
				}
				fileNames.add(fp.getFileName());

				fileSystemName = (ArrayList) files.get(fp.getName()
						+ "_SysName");
				if (fileSystemName == null || fileSystemName.size() < 1) {
					fileSystemName = new ArrayList<String>();
				}
				fileSystemName.add(fp.getFilePath());

				contentType = (ArrayList) files.get(fp.getName()
						+ "_ContentType");
				if (contentType == null || contentType.size() < 1) {
					contentType = new ArrayList<String>();
				}
				contentType.add(fp.getContentType());

				files.put(fp.getName(), alFile);
				files.put(fp.getName() + "_name", fileNames);
				files.put(fp.getName() + "_SysName", fileSystemName);
				files.put(fp.getName() + "_ContentType", contentType);
				filePara.put(fp.getName(), alFile);
			} else if (part.isParam()) {
				ParamPart pp = (ParamPart) part;
				paraValues = parameters.get(pp.getName());
				if (paraValues == null || paraValues.size() < 1) {
					paraValues = new ArrayList<String>();
				}
				paraValues.add(pp.getStringValue());
				parameters.put(pp.getName(), paraValues);

			} else {

			}
		}
	}

 2.2) 在struts.xml中配一个叫cos的bean,把自己写的这个Adaptor配到系统中

    <bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest"
        class="myapp.view.action.common.CosMultiPartRequest" name="cos" scope="prototype">

 

网上很多文章都没提到,struts-default.xml里面是没配cos这个bean的。

 

2.3) 打开 struts中的开关,同样是在struts.xml中

<constant name="struts.multipart.handler
" value="cos" />
 

    这里不要 像网上写的那样配成struts.multipart.parser , 那个属性不起作用的

 

3) 上传时,最好把contentype,fileName用数据库单独存起来,这些信息下载时都要用到。至于内容是存在数据库还是文件系统中随意

 

4) 上传时,文件名为乱码(不是%BC这样的Unicode编码,而是 &#39277; 这样的乱码),这是由于上传(包含File控件)的jsp没有指定编码。把jsp的meta改成

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

 

5)下载时,遇见Can not find a java.io.InputStream with the name [XXX] in the invocation stack。这个异常很误导。可能不是你的param配错了,而是文件找不到,getXXX返回了null。最好在action里处理下,这时直接return INPUT算了。

 

6)下载时,链接中文件名中显示为乱码问题的方法,在tomcat/conf/server.xml中加Encoding参数 ,如下

        <Connector connectionTimeout="20000" port="8081" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
 


这似乎是个bug,见http://www.blogjava.net/wangzhouyu/archive/2007/04/26/113705.html ,原因嘛,是Tomcat对于get param(archor属于get method)没用ISO-8859-1去decode,而是自己搞了一套。很奇怪为什么这个bug现在还没fix

 

7)下载时,点击链接后本地浏览器显示的文件名为乱码,需要这样转一下

String downloadfileName = new String(fileName.getBytes("GBK"),"ISO-8859-1"); 

前面的GBK是怎么来的我也不知道,我只知道后面的"ISO-8859-1"是因为浏览器对fileName按照ISO-8859-1去解析, 可以参见这个文档http://www.busfly.net/csdn/post/449.html

但把GBK hardcoding 在这里就比较urgly了希望知道的同志指点一下这个GBK的来源

 

8)这些中文log下来可能也是编码,需要把log4j.xml的编码改一下,在FILE appender中加一行

<param name="encoding" value="UTF-8" />

 

9)下载时,为了让浏览器正确识别文件类型,刚才让存在数据库的那些contentType和Name就派上用场了

			<result name="success" type="stream">
				<param name="inputName">fileStream</param>
				<param name="contentType">{$attachment.contentType};</param>
				<param name="contentDisposition">attachment;filename="${downloadFileName}"</param>
				<param name="contentCharSet">UTF-8</param>
			</result>

 这里的downloadFileName别忘了按照7)里说的转一下,否则浏览器提示保存时是乱码

 

你可能感兴趣的:(tomcat,bean,struts,servlet,FP)