【转载】webwork上传下载文件的问题总结
系统的架构是webwork+spring+hibernate,数据库是SQLServer2000.
因为是第一次用webwork,所以也是到网上搜代码搜例子,现在才发现baidu和google有些不一样啊。
通过这几天的baidu和google,发现网友们的笔记对我们来说真是重要啊,于是乎在做完了这些之后,也打算总结一下,一来让自己把思路理顺,二来方便大家用的到的时候直接粘贴。
先说说文件的上传吧:
首先看xwork的配置文件;
<!-- 文档上传 -->
<action name="uploadFileAction" class=".......action.UploadFileAction">
<param name="rootPathKey">fileRoot</param>
<result name="input" type="dispatcher">
<param name="location">uploadDoc.jsp</param>
</result>
<interceptor-ref name="fileUpload">
<param name="maximumSize">10485760</param>
</interceptor-ref>
<interceptor-ref name="params"/>
<interceptor-ref name="autowireDefault"/>
</action>
第一个参数是我自己配在action里设置根目录的一个key值,
第三个是最重要的,就是那个maximumSize,他是用来设置webwork允许上传的文件大小。
不过根据试验结果来看,他要和webwork.properties里的一个设置一起才能起作用,
webwork.multipart.maxSize=10485760;
这个要记得写到webwork.properties里面来。
这下再来看看action的方法吧:
action里重要的就是要设置属性来接受这些webwork上传上来的数据,
这里面就有一个非常非常郁闷的问题了,就是在上传的页面里的那个input框的name属性和这些变量是有关系的,
比如在heml页面的name=“docFile”, 那么在action里的接受上传文件的file的名字就该设置为docFile,而接受文件类型的属性就该设置为docFileContentType,千万不要忘了get和set方法。
<input name="docFile" type="file" class="textbox" id="docFile">
private java.io.File docFile;
private String docFileContentType;
之后就可以用这两个变量来进行io操作了。
上传比较简单,做下载的时候可是碰到了一个大大的问题。
起初是在网上搜的代码,也使用webwork设置的,xwork配置如下:
<!-- 文档下载-->
<action name="downloadFileAction" class="....action.DownloadFileAction">
<result name="download" type="stream">
<param name="contentType">application/octet-stream</param>
<param name="inputName">docStream</param>
<param name="bufferSize">1024</param>
<param name="contentDisposition">
attachment;filename="${filename}"
</param>
</result>
<interceptor-ref name="params"/>
<interceptor-ref name="autowireDefault"/>
</action>
然后action里是这么设置的:
先要设置这几个属性,分别对应配置文件的不同参数:
private InputStream docStream;
private String contentType;
private String contentDisposition;
private int bufferSize;
private String filename;
然后将filename设置为我们需要的filename,在将一个inputstream赋给docStream,
然后return "download";
起初这么做还可以,可是后来不知道怎么突然不行了,郁闷了半天,(写这个的时候打算完了再试试这种方法。)一直报一个
ClientAbortException: java.net.SocketException: Connection reset by peer: socket write error的异常,而浏览器的动作就是突然打开准备下载的窗口又迅速消失了,我以为是我的浏览器设置的原因,就跑到同事那里试试,果不其然,通过了,happy中。
可是下午测试时又出问题了,才发现是IE7的问题,在ie6上都没有问题,于是开始怀疑webwork的下载。
打算自己用response写一个下载了。
经过了测试,不行,还是原来的错误,于是道网上搜例子,看来看去还是和我的差不多,于是就变态的改header,改contenttype,改contentDisposition,反正是觉得那不顺眼就改那里,还是不行。
于是我把代码直接贴到一个servlet里面,浏览器直接进入servlet,弹出下载框了。
更加郁闷中。
在郁闷中下班的时间来了,路上还在想是不是因为buffersize设的太小了,艾,遇到比较变态的问题时很多问题都不得不考虑,虽然现在想想是比较可笑的。
今天早上来了一直在搜那个异常的信息,搜到的几乎最全的答案就是这个:
由于处理http连接时,正在输出内容时,用户关闭了IE,会出现一个个"ClientAbortException",属于I/O处理中出现的一个异常,应用服务器应该会捕捉。
Connection reset by peer的原因:
经常出现的Connection reset by peer: 原因可能是多方面的,不过更常见的原因是:
①:服务器的并发连接数超过了其承载量,服务器会将其中一些连接Down掉;
②:客户关掉了浏览器,而服务器还在给客户端发送数据;
③:浏览器端按了Stop
加上由于在IE6里面通过了,我更怀疑是浏览器中止了流的输出。
最后终于有了一个让我发现突破口的现象了,因为是在js里面用window.open指向action的,当我把昨天那个servlet写到js里面是,竟然也出现了同样的状况,于是开始怀疑是提交action的方式不对才导致IE7出现这个错误的。于是我就又把这个servlet用
超链接的方式访问了一下,没问题。于是我想到了利用超链接的方式来访问action的方法,ok。
最后,终于在js里通过这样的方式解决了一个IE7的下载bug。
$("downloadhref").href = "downloadFileAction.action?fileId="+id[0];
$("downloadhref").click();
最后在列上一个webwork文件下载时文件名乱码的解决方法,也是在网上搜的,
public String toUtf8String(String s) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c >= 0 && c <= 255) {
sb.append(c);
} else {
byte[] b;
try {
b = Character.toString(c).getBytes("utf-8");
} catch (Exception ex) {
System.out.println(ex);
b = new byte[0];
}
for (int j = 0; j < b.length; j++) {
int k = b[j];
if (k < 0)
k += 256;
sb.append("%" + Integer.toHexString(k).toUpperCase());
}
}
}
return sb.toString();
}
利用最原始的response的下载方式
//文件下载
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition","attachment;filename="+this.filename);
//输出流
ServletOutputStream out = response.getOutputStream();
//输入流
java.io.File f = new java.io.File(path);
BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));
byte b[] = new byte[this.bufferSize];
int bytesRead = 0;
while ((bytesRead = in.read(b, 0 , this.bufferSize)) != -1)
{
out.write(b, 0, bytesRead); //写数据;
}
in.close();
out.close();
- 单击 开始、 单击 运行,键入 %,然后单击 确定。
- 删除 Temp 文件夹中的所有文件。
- 单击 开始,然后单击 控制面板。
- 双击 Internet 选项。
- 在 常规 选项卡上单击 删除文件,单击以选中 删除所有脱机内容 复选框,然后单击 确定。
- 在桌面上右键单击 回收站 并单击 清空回收站,然后单击 是。
参考 http://support.microsoft.com/kb/938200/zh-cn