BirtViewer和Struts2框架的整合
最近和同事在做一个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判断了,读者自己可以改进。不多说了,上代码。
方案一:修改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 }
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 }