最近和同事在做一个birt相关的东西<
Birt扫盲>,web这块是用ssh框架,MVC框架用的是struts2。同事负责报表展现这一块,考虑到工期,他选择了使用birt标签来展现birt报表。这一来,问题就出现了。因为web这块是在一个老项目的基础上添加的模块,很多配置都不要再修改,其中就有struts2的核心过滤器,拦截了/*和*.jsp,而如果使用birt标签的话,它自己向birt引擎(配置为servlet)发出的请求通通都被struts2过滤了,结果只要一到含有birt标签的页面,就会报异常:在xx下找不到xxAction。算是个冲突吧。问题的关键点就是:birt标签对于servlet的请求,被struts2的核心过滤器过滤了。如果从零开始做,这或许不是什么难事,但是项目里很多配置都定死了,没办法,只能想其他路子。
方案一:修改birtViewer相关的servlet源码
将birt的servlet的url-mapping配置为类似于/preview.birt的话,是会被struts2的核心过滤器放过的,于是我反编译了birt的servlet的源码,发现请求路径基本都是硬编码的,不管了,一通乱改,基本都是将xxx改成xxx.birt,然后居然可以预览到报表的轮廓了,不过还是有NullPointer,没办法,这么改源码不是办法。
方案二:写过滤器,使对于servlet的请求跳过struts2的处理
今天看struts2的核心过滤器的源码,灵感突然来了,我也写个过滤器,先于struts2的过滤器执行,在过滤器里直接将请求转发到对应的servlet。果然奏效!对于类似的需求,也可以采用同样的办法。
这个url-pattern和代码还没解耦,可以修改web.xml,这样代码就不需要对url判断了,读者自己可以改进。不多说了,上代码。
1
/**
2
* BirtFilter.java 2009-8-21
3
* by shoru
4
*/
5
package
com.shoru.filter;
6
7
import
java.io.IOException;
8
import
java.util.HashMap;
9
import
java.util.Map;
10
import
java.util.Set;
11
12
import
javax.servlet.Filter;
13
import
javax.servlet.FilterChain;
14
import
javax.servlet.FilterConfig;
15
import
javax.servlet.RequestDispatcher;
16
import
javax.servlet.ServletContext;
17
import
javax.servlet.ServletException;
18
import
javax.servlet.ServletRequest;
19
import
javax.servlet.ServletResponse;
20
import
javax.servlet.http.HttpServletRequest;
21
22
/**
23
* BirtViewer和Struts2框架整合必须配置此拦截器。 如下配置web.xml,注意struts2的核心过滤器必须配置在BirtFilter之后。
24
* <filter>
25
* <filter-name>BirtFilter</filter-name>
26
* <filter-class>com.linkage.system.filter.BirtFilter</filter-class>
27
* </filter>
28
* <filter-mapping>
29
* <filter-name>BirtFilter</filter-name>
30
* <url-pattern>/*</url-pattern>
31
* </filter-mapping>
32
*
33
* @description
34
*
@author
Shoru
35
* @date 2009-8-21
36
*
@version
1.0.0
37
*
@since
1.0
38
*/
39
public
class
BirtFilter
implements
Filter {
40
/**
41
* 容器,封装birt相关功能的uri和所对应Servlet名的键值对
42
*/
43
Map
<
String, String
>
map
=
new
HashMap
<
String, String
>
();
44
45
/**
46
* Context.
47
*/
48
ServletContext context;
49
50
/**
51
* debug开关
52
*/
53
static
boolean
debug
=
false
;
54
55
/**
56
* @description
57
*
@author
Shoru
58
* @date 2009-8-21
59
*
@version
1.0.0
60
*/
61
public
void
destroy() {
62
map
=
null
;
63
}
64
65
/**
66
* 过滤birt请求,转发到对应的servlet,以绕过其他过滤器,e.g. struts2
67
*
68
* @description
69
*
@author
Shoru
70
* @date 2009-8-21
71
*
@version
1.0.0
72
*
@param
request
73
*
@param
response
74
*
@param
fc
75
*
@throws
IOException
76
*
@throws
ServletException
77
*/
78
public
void
doFilter(ServletRequest request, ServletResponse response,
79
FilterChain fc)
80
throws
IOException, ServletException {
81
82
HttpServletRequest req
=
(HttpServletRequest)request;
83
String uri
=
req.getRequestURI();
84
if
(debug) {
85
System.out.println(
"
>>>Requesting
"
+
uri
+
"
?
"
86
+
req.getQueryString());
87
}
88
Set
<
String
>
keys
=
map.keySet();
89
90
for
(String key : keys) {
91
/*
92
* TODO:这里的判断只是简单地调用contains方法,这样就带来较多限制。
93
* 比如工程子目录的命名、struts2命名空间等都受到birtViewer的约束。待改进。
94
*/
95
if
(uri.contains(key)) {
96
RequestDispatcher rd
=
this
.context.getNamedDispatcher(map.get(key));
97
if
(rd
!=
null
) {
98
if
(debug) {
99
System.out.println(
"
>>>Redirect successfully executed
"
);
100
}
101
//
跳过其他过滤器,跳转到对应的servlet
102
rd.forward(request, response);
103
}
else
{
104
if
(debug) {
105
System.out.println(
"
>>>Redirect unsuccessfully executed
"
);
106
}
107
}
108
return
;
109
}
110
}
111
112
//
将请求交给下一个过滤器
113
fc.doFilter(request, response);
114
}
115
116
/**
117
* @description
118
*
@author
Shoru
119
* @date 2009-8-21
120
*
@version
1.0.0
121
*
@param
fc
122
*
@throws
ServletException
123
*/
124
public
void
init(FilterConfig fc)
125
throws
ServletException {
126
127
this
.context
=
fc.getServletContext();
128
/*
129
* 这里注意,在项目目录的命名时,不要取和birt内置的一些servlet名重复。 请根据项目的web.xml自行配置。
130
* (包括frameset、run、preview、download、parameter、document、output)
131
*/
132
map.put(
"
frameset
"
,
"
ViewerServlet
"
);
133
map.put(
"
preview
"
,
"
EngineServlet
"
);
134
}
135
}