项目中要用到针式打印机票据打印,本来是使用java printable 通过 Graphic2D输出到图形化方式打印的,运行了一段时间客户对版面个性需要比较多,用输出图形的方式调整太麻烦,而且Graphic2D画表格真的很麻烦,所以后来选择用ireport来定制版面,通过jasperreport api直接输送到打印机上。
目前针式打印几比较通用的纸张是9.5*5.5英寸的,根据不同客户的需求,我们定制了2种版面,因为我们是做服装行业的,一类客户是不管理尺码的,列数比较少纵向打印比较省纸张,另一种是管颜色尺码,以动态尺码为表头,需要用到交叉报表。
数据是从客户端通过socket发送到我的程序上的,所以需要用到javabean数据源。
首先第一步创建测试数据源,创建一个javabean类用于承载数据,创建一个工厂类用于提供数据。
public class JasperDatasourceFactory {
public static Collection createBeanCollection1() throws Exception{
List list_1=new ArrayList();
//填充list_1
return list_1;
}
}
在ireport添加项目的classpath,工具-选项-classpath,添加完之后需要重启ireport,不然找不到。
创建一个ireport空模板,设置报表属性width=369 height=684 及上面提及纸张的纵向模式
创建javabean数据源,并将数据源设为默认数据源:
3.导入数据源字段:
右键导航栏里的根节点,点击edit query,进入后切换到javabean datasource,填写javabean类路径,点击read attributes,把要统计的自动天下到下方的列表中
添加完后,在导航栏的fields节点下就显示这些导入的这些字段,把这些字段一次拖到报表版面的detail 区域,基本的报表就完成了直接可以点击预览,下面是我完整的报表版面:
上面的的布局是通过精心排布完成的,下面有几点要说明的:
1.报表版面上各个栏生成报表如何展现:
Title:故名思议标题栏,如果有多页只在第一页显示
Page Header: 页头,每一页都显示
Column Header:顾名思义就是表头,每一页重复显示
Detail:列表区
PageFooter:页尾,置底显示,每一页显示
summary:合计栏,更在最后一页表格的后面
2.添加合计
列表的合计栏需要放到summary区域,虽然和列表身首异处,但是生成报表的时候绝对是连载一起的。
在导航栏的Variables中添加一个Variables,并在属性对话框里设置统计参数,将创建好的Variables拖到summary栏:
3.如果添加parameter,page header、page footer、summary中有一些报表描述性的内容,通过参数传进来。
在导航栏的parameters节点右键点击添加Parameters,添加好后在下面重命名成你要的参数名,并把它拖拽到报表页面上
4.设置添加边框
中国人总是喜欢条条框框,所以中国式报表大多都有表格,所以需要给表格设置边框。
全选column header、detail、summary中需要加边框的控件,在属性栏中设置style属性为table_td:
5.使用表达式
如批次下方这里,如果是销售单显示"客户",如果是调拨单显示"调出地",在此处添加一个text field 右键点edit expression,填写如下格式:
$P{type}.equals( "21")?"客户:":($P{type}.equals( "22")?"供应商:":"调出店:")
6.设置高度自适应及控件自动偏移,如accountinfo这个参数,如果内容多发生换行,如果不设置自动拉升内容会被遮掉,如果设置了自动拉伸,下面的内容会被遮挡。
选择需要自动拉伸和自动偏移的控件,设置属性:
stretch type:relative to tallest height 设置自动拉伸
position type: float 设置自动偏移,如果上面一行控件拉伸,下面的控件自动下移。
如果同一行有多个控件,需要设置组,否则可能有因为偏移导致对不起的情况,归组操作方式,选择这一行所有控件,右键点击group selected elements。
至此,第一类报表的模板已完成,可以点击预览展现,不过用参数的地方都显示为null。
打印效果:
下面是如何使用jasperreport直接输出到打印机上:
String sourceFileName = "/jasper/" + paper.getModefile();
Collection datasource = printer.getList();//这里是我获取数据集的地方
Map parameters = printer.getParam();//报表里要用到parameters,存放在map里
JRBeanCollectionDataSource beanColDataSource =
new JRBeanCollectionDataSource(datasource);
InputStream reportStream=null;
try {
//报表变异jasper文件的文件流
reportStream=new FileInputStream(URLDecoder.decode(AppUtil.rootPath+sourceFileName, "UTF-8"));
JasperPrint jasperPrint = JasperFillManager.fillReport(reportStream, parameters, beanColDataSource);
//设置成打印横向
jasperPrint.setOrientation(OrientationEnum.LANDSCAPE);
//获取打印服务
PrintService printService = null;
if (printerName.equals("default")) {
printService = PrintServiceLookup.lookupDefaultPrintService();
} else {
PrintService[] printlist = PrintServiceLookup.lookupPrintServices(null, null);
//printService=printlist[0];
for (int i = 0; i < printlist.length; i++) {
if (printerName.equals(printlist[i].getName())) {
printService = printlist[i];
break;
}
}
}
JRAbstractExporter je = new MyJRPrintServiceExporter();//自带的JRPrintServiceExporter对自定义打印纸张有点瑕疵,原因不是很清楚,我做了继承并修改了JRPrintServiceExporter一段代码就可以了,稍后贴出代码
//设置打印内容
je.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
//设置指定打印机
je.setParameter(JRPrintServiceExporterParameter.PRINT_SERVICE, printService);
//有些个性化的参数,我在我的设置类里再设置
printer.setFormat(jasperPrint, je);
je.exportReport();
上面提及的JRPrintServiceExporter中,需要把
printerJob.setPrintable(this, pageFormat);
替换成
pageFormat.setPaper(paper);
Book pBook = new Book();
pBook.append(this, pageFormat,jasperPrint.getPages().size());
printerJob.setPageable(pBook);
接下来讲一下交叉报表的制作方法:
交叉报表是对一组原始数据进行多维度的统计,类似Office的数据透视表,例如如下的数据源:
款号 名称 颜色 尺码 数量 单价 金额
A 马甲 红 S 2 200 400
A 马甲 红 M 2 200 400
B 皮衣 黑 S 3 500 1500
B 皮衣 黑 M 4 500 2000
通过交叉报表输出如下格式的报表
尺码
款号 名称 颜色 S M 总数 单价 总金额
A 马甲 红 2 2 4 200 800
B 皮衣 黑 3 4 7 500 3500
合计 5 6 11 700 4300
ireport中
首先第一步,按上述方式创建数据源,并导入查询属性(字段)到fields中。
第二步从组件面板中拖拽crosstab到summary栏,注意必须是summary栏。在制作交叉报表的时候column header、column footer 、detail栏没有用处可以隐去,其他栏还是按照上面介绍ireport band一样的显示方式。
接前所述,将crosstab拖拽到summary band的时候,会弹出交叉报表创建向导:
1.选择dataset 为 main report dataset
2.选择两个行分组