欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

iReport整合web(Struts2)后台开发

程序员文章站 2022-05-07 19:21:24
...

上一篇我们大概讲了一下iReport设计器的使用——如何生存模板文件并编译。这次来好好讲下如何整合web环境来进行报表的开发。

开发之前你需要注意的一点是:既然通过web后台来动态绑定数据源,那么,你就必须要意识到,产生模板文件时,不能通过Launch report wizard来产生报表模板,因为在这个向导中,你已经绑定过数据源了,所以这次必须直接透过左边的open this template按钮来修改模板,并自己加上一些Fields和Parameters了。。——这是我做分组得到的惨痛教训!!!

步骤:

1)前端:

<div class="date_select"><font>请选择日期:</font><@s.textfield label="请选择日期" name="transDateFrom" id="date" class="date" theme="simple" placeholder="点击选择日期"/></div>
</div>
<div style="text-align:center">
   <button id="btn_query" class="btn btn-primary">查询</button> 
   <button id="btn_download"  class="btn btn-primary">导出</button> 
</div>
<br/>
 <div id="report" style="text-align:center">
</div>

 其中id为report的div即是呈现报表的区域,之前这个也是困惑我的难点之一:如何把报表渲染到指定区域?

页面上有2个按钮——查询和导出;还有一个输入查询指定日期的数据的日期选择插件,这个插件所产生的值将会作为参数传递到后台。这里又出现了难点之二——如何把参数传给报表?解决方案是把参数值作为后台产生数据源的条件就ok了。。

对应的js为:

$('#btn_query').click(function(){
	  var transDate=$("[name='transDate']").eq(0).val();
	  /*if(transDate==''){
	  		   alert('请选择日期');return;
      }*/
     var url="${request.contextPath}/report/jasper?type=reportSnap&format=HTML&snapDate="+$("[name='transDate']").eq(0).val();
     $.ajax({ 
	 url: url, dataType:"html",headers:{"X-Fragment":"_"},
	 cache:false,success: function(html) { 
		$("#report").empty();
		$("#report").html(html);
	   
	 } 
	}); 
      
  });

 这里的js告诉我们解决第一个困惑的办法,通过ajax请求把报表渲染到指定区域,同时,ajax的dataType为html而不再是典型的json了。

加一个导出成excel的代码吧:

 var transDate=$("[name='transDate']").eq(0).val();
	  if(transDate==''){
	  		   alert('请选择日期');return;
      }
 
	  	var url='${request.contextPath}/report/jasper';
	  	var form = $("<form>");
	  	form.attr("action",url);
	  	form.attr("method","get");
	  	form.attr("style","display:none");
	  	form.append("<input name='type' value='reportTest'>");
	  	form.append("<input name='transDate' value='"+transDate+"'>");
	    form.append("<input name='format' value='XLS'>");
	  	$('body').append(form);
	  	form.submit();
	  	form.remove();

 而导出成pdf格式时,还需要jar包的支持:itextpdf-xxx.jar和itext-pdfa-xxx.jar。

 

2)接下来我们探讨下后台,后台则负责产生动态数据源。

public class ReportAction extends BaseAction {

	private static final long serialVersionUID = -8674663678097055820L;

	private Logger log = LoggerFactory.getLogger(ReportAction.class);

	@Autowired
	private ReportDao reportDao;
	
	@Autowired
	private DB db;
	
	private String snapDate;

	private String type;
	private String title;
	private String format;
	private String appid;
	private Map<Object, Object> reportParameters = new HashMap<Object, Object>();
	private List<? extends Serializable> list;
	
	private String defaultDate;
	
	//分页相关
	private String page;
	
	public String jasper() {
		if (type != null) {
			try {
				getClass().getDeclaredMethods();
				Method method = getClass().getDeclaredMethod(type);
				method.invoke(this, new Object[0]);
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
				throw new RuntimeException("没有此报表");
			} catch (Exception e) {
				log.error("", e);
				throw new RuntimeException(e.getMessage());
			}
		}

		if (list == null || list.isEmpty()) {
			addActionError("没有数据");
			 
		}
		return "jasper";
	}

	public String getDocumentName() {
		try {
			StringBuilder sb = new StringBuilder();
			sb.append(URLEncoder.encode(title, "UTF-8"));
			return sb.toString();
		} catch (UnsupportedEncodingException e) {
			return "";
		}
	}

	public Map<Object, Object> getReportParameters() {
		reportParameters.put("SUBREPORT_DIR", ServletActionContext
				.getServletContext().getRealPath("/WEB-INF/jasper/"));
		JRAbstractLRUVirtualizer virtualizer = new JRGzipVirtualizer(2);
		reportParameters.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);
		return reportParameters;
	}

	public String getLocation() {
		return "/WEB-INF/jasper/" + type + ".jasper";
	}

	//reportSnap报表
	public void reportSnap() {

	List list = new ArrayList();
	long count = 0;
	String transDate = null;
		try {
			list = reportDao.getSnapGroupByApp(snapDate);
			count = list.size();
		} catch (Exception e) {
			log.error("", e);
			addActionError(e.getMessage());
		} finally {
			db.close();
		}
		this.list = list;

		reportParameters.put("su", count + "");
		reportParameters.put("oper_date", DateUtils.parsFormat(new Date(), "yyyy-MM-dd"));
		reportParameters.put("trans_date", transDate);
		
		title = "系统快照报表";
	}
	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getFormat() {
		return format;
	}

	public void setFormat(String format) {
		this.format = format;
	}

	public String getAppid() {
		return appid;
	}

	public void setAppid(String appid) {
		this.appid = appid;
	}

	public void setReportParameters(Map<Object, Object> reportParameters) {
		this.reportParameters = reportParameters;
	}

	public String getPage() {
		return page;
	}

	public void setPage(String page) {
		this.page = page;
	}

	public List<? extends Serializable> getList() {
		return list;
	}

	public void setList(List<? extends Serializable> list) {
		this.list = list;
	}

	public String getSnapDate() {
		return snapDate;
	}

	public void setSnapDate(String snapDate) {
		this.snapDate = snapDate;
	}
}

 别忘记了给这个action在struts.xml中配置起来,以便它包含的一些属性和方法都可以找到,关键的地儿在于result name="jasper" type="jasperreports"这里~~后面的param都是在指定jasperreport报表的一些属性:

(这里是参考的struts2-jasperreports-plugin-2.3.24.jar里面的struts-plugin.xml配置,即参考struts2支持的对jasperreport的配置。。

<package name="default" namespace="/" extends="default">
	<action name="report" class="com.xxxx.action.report.snap.ReportAction">
			<result name="jasper" type="jasperreports">
				<param name="reportParameters">reportParameters</param>
				<param name="contentDisposition">attachment</param><!--这里指定了以附件形式导出时打开询问窗口-->
				<param name="dataSource">list</param><!--数据源绑定在list变量-->
				<param name="format">${format}</param><!--导出附件格式,支持PDF/XLS等-->
				<param name="location">${location}</param><!--指定模板的jasper二进制文件存放位置-->
				<param name="documentName">${documentName}</param>
			</result>
		</action>
</package>

 其中查询的dao省略,dao将返回一个List<Map<String, Object>>类型的数据,Action里通过this.list = 该数据集合 来绑定报表数据源,通过reportParameters.put("oper_date", DateUtils.parsFormat(new Date(), "yyyy-MM-dd"));来向报表的$P{oper_date}传参~~

 

我这里由于用到了分组,所以在dao里面写sql时,对于分组的sql最好加上order by 。这是官方API规定的,分组的时候,要给分组字段order by。

SELECT  
  app_id, 
  snap_date,  
  SUM(total_cnt) total_sum,  
  SUM(succ_cnt) succ_sum,  
  SUM(excp_cnt) excp_sum,  
  SUM(fail_cnt) fail_sum   
FROM  
  itm_snap_tran_count 
GROUP BY app_id , snap_date order by app_id, snap_date

 其中app_id和snap_date为本例的分组字段,那么在模板文件中,我就需要为这两个字段分别都添加在Group Header当中,如:


iReport整合web(Struts2)后台开发
            
    
    博客分类: iRport报表 ireportjasperreportweb整合分组导出 
 并且最最重要的一点:这2个Group Header都要分别指定属性Group Expression为$F{该字段名},否则将无法正常显示(因为我就在此困扰多时,Group by的字段无法显示,为null或显示不正确)!!!

注意:

也不要通过Lauch report wizard按钮导向(会在设计器中绑定好数据源)生成的模板编译文件给web后台,否则会重复group by哦,必须是通过open this wizard的方式修改模板并自己手动加上一些参数和变量所生成的模板才行!

也要注意,dao生成的数据集的每个map的key必须跟模板文件中的 $F{变量名}对应上才能填充进去。。

只需把在js中把format修改为对应的后缀,就可以导出不同格式的报表文件。

当然,千万别忘记把模板文件的编译文件(二进制文件,后缀为.jasper而不是模板文件本身哦)放在WEB-INF/jasper目录下

这里,在页面上渲染,其实就是把报表文件html的格式 export出来,其本质还是导出。。

附上效果图:


iReport整合web(Struts2)后台开发
            
    
    博客分类: iRport报表 ireportjasperreportweb整合分组导出 
 

这个我是使用Cherry Landscape模板做的,黑色部分为外层group by的字段app_id,斜体部分为内嵌的group by的字段snap_date,即在app_id分组的情况下再次以snap_date分组,这也是一大难点之一!!!

 

其实,对于iReport的API我也没有研究得很透彻,因为的确比较难!顺便,附上jasperreports对报表的解析过程图:

iReport整合web(Struts2)后台开发
            
    
    博客分类: iRport报表 ireportjasperreportweb整合分组导出 
 

  • iReport整合web(Struts2)后台开发
            
    
    博客分类: iRport报表 ireportjasperreportweb整合分组导出 
  • 大小: 13.9 KB
  • iReport整合web(Struts2)后台开发
            
    
    博客分类: iRport报表 ireportjasperreportweb整合分组导出 
  • 大小: 10.3 KB
  • iReport整合web(Struts2)后台开发
            
    
    博客分类: iRport报表 ireportjasperreportweb整合分组导出 
  • 大小: 15 KB