首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

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

2012-08-28 
struts2 文件上传/下载/乱码 碎碎念我的环境 英文windows xplocation :United stateslanguage for non-Uni

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 injectedmp.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"        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)里说的转一下,否则浏览器提示保存时是乱码

?

1 楼 daichangfu 2011-01-22   学习一下! 我还有一个问题,请问这样下载文件时,显示文件下载的大小吗?可以显示下载进度条吗? 2 楼 iamlotus 2011-01-27   应该不行,因为没有地方记录file size

热点排行