为了给用户更好体验,最进在struts2添加了上传进度条让用户知道上传过程时间,增加有好度。
由于以前做个 文件上传 没有用过 组件进行解析,直接用servlet 解析的,而现在 struts2 框架使用 commons-fileupload 解析上传文件.
通常我们在action 中声明 file,fileType,等字段 struts2 在执行action 方法时已经把 文件上传解析好了。进行封装后 传到 action, 通过所以无法在action 做文件解析监听.
struts2 上传原理form中设定的提交内容是二进制格式的,Dispatcher类的wrapRequest方法会将请求交由实现MultiPartRequest接口的JakartaMultiPartRequest
类来处理
在Struts2的JakartaMultiPartRequest类实现了MultiPartRequestWrapper接口, 里面的parse方法中才会真正来调用commons-fileupload组件的 ServletFileUpload类对请求进行解析,最后进行封装传入action.
知道原理后,思路也就清晰了。需要监听上传文件,则需要在这动文章.
首先需要在上传文件页面post提交文件, 在commons-fileupload 解析文件时,把解过程存入session, 然后在提交页面用ajax 请求另一个链接,读出session里面的 解析信息。显示在页面。
提交页面
1
<
style
type
="text/css"
>
2
#progressBar
{
width
:
400px
;
height
:
12px
;
background
:
#FFFFFF
;
border
:
1px solid #000000
;
padding
:
1px
;
}
3
#progressBarItem
{
width
:
30%
;
height
:
100%
;
background
:
#FF0000
}
4
</
style
>
5
<
script
type
="text/javascript"
src
="js/jquery.js"
></
script
>
6
<
script
type
="text/javascript"
language
="javascript"
>
7
var
finished
=
true
;
//
上传是否结束
8
function
showStatus(){
9
finished
=
false
;
10
$(
'
#progressBarItem
'
).attr(
'
width
'
,
'
1%
'
);
11
setTimeout(
'
callback()
'
,
1000
);
12
}
13
14
function
callback(){
15
if
(finished)
return
;
16
var
url
=
'
paper/doFileProgress
'
;
17
var
jv
=
ajaxGetReq(url);
18
alert(jv);
19
setTimeout(
'
callback()
'
,
1000
);
20
}
21
</
script
>
22
</
head
>
23
<
body
>
24
<
iframe
name
="upload_iframe"
width
="0"
height
="0"
></
iframe
>
25
<
div
id
="progressBar"
><
div
id
="progressBarItem"
></
div
></
div
><
div
id
="statusInfo"
></
div
>
26
<
form
id
="form1"
method
="post"
action
="paper/addPaper"
enctype
="multipart/form-data"
target
="upload_iframe"
onsubmit
="return showStatus()"
>
27
<
input
type
="file"
name
="file1"
/><
br
/>
28
<
input
type
="file"
name
="file2"
/><
br
/>
29
</
form
>
30
</
body
>
target 属性默认是_self, 如果target 为默认值,则提交后的新页面会在当前窗口显示,造成当前窗口短暂地白屏。在页面添加一个隐藏iframe,把target属性指定为iframe,所以上传文件 当前页面看不来变化
UploadSatatus.java 显示状态类
1
public
class
UploadStatus {
2
3
private
long
bytesRead;
//
已经上传的字节数,单位:字节
4
private
long
contentLength;
//
所有文件的总长度,单位:字节
5
private
int
items;
//
正在上传第几个文件
6
private
long
startTime
=
System.currentTimeMillis();
//
开始上传的时间,用于计算上传速度等
7
}
UploadListener.java 监听类
1
public class UploadListener implements ProgressListener{
2
3
private UploadStatus status;
4
5
public UploadListener(UploadStatus status){
6
this.status = status;
7
}
8
9
10
public void update(long bytesRead, long contentLength, int items) {
11
//上传组件会调用该方法
12
status.setBytesRead(bytesRead); //已读取的数据长度
13
status.setContentLength(contentLength); //文件总长度
14
status.setItems(items); //正在保存第几个文件
15
16
}
接下来 实现 struts2 2.3 版本 MultiPartRequest接口, 把
public class RefactorMultiPartRequest implements MultiPartRequest
复制一份JakartaMultiPartRequest类里面的类代码到 自己新建RefactorMultiPartRequest 类,同时修改parseRequest代码(继承JakartaMultiPartRequest也可以,由于这类里私有方法太多,不适合继承)
1
private
List
<
FileItem
>
parseRequest(HttpServletRequest servletRequest, String saveDir)
throws
FileUploadException {
2
3
UploadStatus status
=
new
UploadStatus();
//
上传状态
4
UploadListener listner
=
new
UploadListener(status);
//
监听器
5
servletRequest.getSession().setAttribute(
"
uploadStatus
"
, status);
//
把状态放到session里去
6
7
8
DiskFileItemFactory fac
=
createDiskFileItemFactory(saveDir);
9
ServletFileUpload upload
=
new
ServletFileUpload(fac);
10
upload.setSizeMax(maxSize);
11
upload.setProgressListener(listner);
//
添加监听器
12
13
return
upload.parseRequest(createRequestContext(servletRequest));
14
}
在struts.xml里面加入覆盖JakartaMultiPartRequest类配置
1
<
bean
type
="org.apache.struts2.dispatcher.multipart.MultiPartRequest"
name
="refactor"
2
class
="org.scirp.common.interceptor.RefactorMultiPartRequest"
scope
="default"
/>
3
4
<
constant
name
="struts.multipart.handler"
value
="refactor"
/>
至于我怎么知道的,我也是阅读了人家文章 strut2 内部原理 , 不过我覆盖失败),调试还是调用原来的JakartaMultiPartRequest类,而不是调用我写的RefactorMultiPartRequest (现在还没解决,不知道是不是少写了配置,我解决方法是 在我项目里新建了一个包路径和JakartaMultiPartRequest一模一样的类,因为jdk 在相同包 java 文件时,会优先调用项目里的类)
然后新建一个读取进度方法
1
/**
2
* 显示文件上传的进度
3
*/
4
public
void
doFileProgress(){
5
response.setHeader(
"
Cache-Control
"
,
"
no-store
"
);
//
禁止浏览器缓存
6
response.setHeader(
"
Pragrma
"
,
"
no-cache
"
);
//
禁止浏览器缓存
7
response.setDateHeader(
"
Expires
"
,
0
);
//
禁止浏览器缓存
8
9
UploadStatus status
=
(UploadStatus)session.getAttribute(ConfigKeys.UPLOAD_STATENAME);
10
if
(status
==
null
){
11
renderText(
"
error
"
);
12
return
;
13
}
14
15
long
startTime
=
status.getStartTime();
//
上传开始时间
16
long
currentTime
=
System.currentTimeMillis();
//
现在时间
17
long
time
=
(currentTime
-
startTime)
/
1000
+
1
;
//
已传输的时间 单位:s
18
19
//
传输速度单位:byte/s
20
double
velocity
=
((
double
)status.getBytesRead())
/
(
double
)time;
21
//
估计总时间
22
double
totalTime
=
status.getContentLength();
23
//
估计剩余时间
24
double
timeLeft
=
totalTime
-
time;
25
//
已经完成的百分比
26
int
percent
=
(
int
)(
100
*
(
double
)status.getBytesRead()
/
(
double
)status.getContentLength());
27
//
已经完成数单位:m
28
double
length
=
((
double
) status.getBytesRead())
/
1024
/
1024
;
29
//
总长度 单位:m
30
double
totalLength
=
((
double
) status.getContentLength())
/
1024
/
1024
;
31
32
//
我用的是json
33
JSONObject json
=
new
JSONObject();
34
json.put(
"
percent
"
, percent);
35
json.put(
"
length
"
, length);
36
json.put(
"
totalLength
"
, totalLength);
37
json.put(
"
velocity
"
, velocity);
38
json.put(
"
time
"
, time);
39
json.put(
"
totalTime
"
, totalTime);
40
json.put(
"
timeLeft
"
, timeLeft);
41
json.put(
"
fileNumber
"
, status.getItems());
42
System.out.println(json.toString());
43
renderText(json.toString());
44
45
}
运行后