jasperreports在web上的报表展现方式有两种,一种是applet viewer,另外一种是flash viewer,由于前者的实现需要浏览器端装有java运行时,所以只考虑后一种方式
把前面提到的demo之jasper-webapp中flash文件夹下的flash报表查看器jasperreports-flash-4.0.0.swf拷到你本地项目的某个文件夹。
我们参考demo中的swf.html的内容:
<%@ page language="java" contentType="text/html;charset=UTF-8"%> <%@ page import="java.util.*" %> <html> <head> <title> </title> <link rel="stylesheet" type="text/css" href="<%=request.getContextPath() %>/stylesheet.css" title="Style"> </head> <body bgcolor="white"> <object width="100%" height="100%"> <param name="movie" value="flash/jasperreports-flash-4.5.0.swf"/> <embed src="<%=request.getContextPath() %>/flash/jasperreports-flash-4.5.0.swf" FlashVars="jrpxml=<%=request.getContextPath() %>/servlets/xml4swf?jrprint=<%=request.getSession().getId()%>_jrprint&fetchSize=3&time=<%=new Date()%>" width="100%" height="100%"> </embed> </object> </body> </html>
注意到代码中的粗体部分了吗?很显然,我们需要在工程部署文件web.xml中新加一个servlet极其
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>JasperReports Flash Viewer - Web Application Sample</display-name> <servlet> <servlet-name>Xml4SwfServlet</servlet-name> <servlet-class>net.sf.jasperreports.j2ee.servlets.Xml4SwfServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Xml4SwfServlet</servlet-name> <url-pattern>/servlets/xml4swf</url-pattern> </servlet-mapping> <servlet> <servlet-name>SwfServlet</servlet-name> <servlet-class>com.easyway.jaserreport.flash.JasperReportFlashServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>SwfServlet</servlet-name> <url-pattern>/servlets/swf.html</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> <login-config> <auth-method>BASIC</auth-method> </login-config> </web-app>
和demo中的单个用户不同,由于需要区分不同的用户查询报表后生成的JasperPrint对象,我们需要把它set入用户的当前session中。但是我们要怎么把它取出来然后用Xml4SwfServlet来进行展现呢?这个servlet除了一个fetchSize参数,还可以接收哪些参数呢?
幸好jasperreports是开源的,可以直接查看和修改它的源代码。我们来研究一下这个Xml4SwfServlet的实现类net.sf.jasperreports.j2ee.servlets.Xml4SwfServlet.java的祖父类net.sf.jasperreports.j2ee.servlets.BaseHttpServlet.java。
可以发现,BaseHttpServlet定义了一个方法,以List的形式返回session中的所有JasperPrint对象:
public static List getJasperPrintList(HttpServletRequest request){
.......
}
它定义了两个和request对象可以接受的参数名称:
public static final String JASPER_PRINT_LIST_REQUEST_PARAMETER = "jrprintlist";
public static final String JASPER_PRINT_REQUEST_PARAMETER = "jrprint";
然后在getJasperPrintList方法中接收他们,如果参数值不为空,则以这两个参数的值在session中取出它对应的JasperPrint对象或者装有JasperPrint对象的List(由于我们一次查询只返回一个JasperPrint对象,后者可以忽略)——那么,在我们填充报表生成单个的JasperPrint对象set进session中时,我们需要:
request.getSession().setAttribute(request.getSession().getId() + "_jrprint",jasperPrint);
这时参数“jrprint”的值就是request.getSession().getId() + "_jrprint"的值了。
我们再修改自己的报表展现页面ViewReport.jsp(对应demo中的swf.html)中向Xml4SwfServlet发送的参数为:
<embed src="<%=request.getContextPath() %>/flash/jasperreports-flash-4.5.0.swf" FlashVars="jrpxml=<%=request.getContextPath() %>/servlets/xml4swf?jrprint=<%=request.getSession().getId()%>_jrprint&fetchSize=3&time=<%=new Date()%>" width="100%" height="100%"> </embed>
这样就可以区分会话来读取JasperPrint对象进行flash报表展现了。
但我们又会碰到一个新的问题,第一次查询出报表进行展现后,当重新设定查询条件再次进行查询时,发现flash中的报表内容还是和第一次一样,并没有进行更新。
经排查后发现是ViewReport.jsp重新载入时,向服务器端发出的Http请求的url每一次都是一样的,所以浏览器认为服务器端没有更新,直接把缓存内容返回了页面。
那我们就想个办法,每次请求的url都不一样,在请求之后添加时间
嗯,我在参数jrprint的值后加上了当前时间,用分号和原来的值隔开了——这样用户进行报表查询后ViewReport.jsp刷新时浏览器向服务器端发出的请求就每次都不一样啦。大功告成,这样我们就可以在多用户情况下用flash播放器完美的进行报表展现了。
JasperReportFlashServlet
import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JRRuntimeException; import net.sf.jasperreports.engine.JasperFillManager; import net.sf.jasperreports.engine.JasperPrint; import net.sf.jasperreports.j2ee.servlets.BaseHttpServlet; import net.sf.jasperreports.j2ee.servlets.Xml4SwfServlet; /** * * <p>请求查看报表时候查询数据,JasperReportFlashServlet用于填充Flash提供 SWF使用表的数据<p> * * 创建日期 2013-4-28<br> * @author longgangbai<br> * @version $Revision$ 2013-4-28 * @since 3.0.0 */ public class JasperReportFlashServlet extends Xml4SwfServlet { // private static final long serialVersionUID = 1L; public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { ServletContext context = this.getServletConfig().getServletContext(); response.setContentType("text/html"); PrintWriter out = response.getWriter(); try { String reportFileName = context.getRealPath("reports/WebappReport.jasper"); File reportFile = new File(reportFileName); if (!reportFile.exists()) { throw new JRRuntimeException( "File WebappReport.jasper not found. The report design must be compiled first."); } Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put("ReportTitle", "Address Report"); parameters.put("BaseDir", reportFile.getParentFile()); JasperPrint jasperPrint = JasperFillManager.fillReport(reportFileName, parameters, new JasperReportDataSource()); request.getSession().setAttribute(request.getSession().getId()+"_"+BaseHttpServlet.JASPER_PRINT_REQUEST_PARAMETER, jasperPrint); request.getRequestDispatcher("/jasperReportSWF.jsp").forward(request, response); } catch (JRException e) { out.println("<html>"); out.println("<head>"); out.println("<title>JasperReports - Web Application Sample</title>"); out.println("<link rel=\"stylesheet\" type=\"text/css\" href=\"../stylesheet.css\" title=\"Style\">"); out.println("</head>"); out.println("<body bgcolor=\"white\">"); out.println("<span class=\"bnew\">JasperReports encountered this error :</span>"); out.println("<pre>"); e.printStackTrace(out); out.println("</pre>"); out.println("</body>"); out.println("</html>"); } } }