由于项目业务需要,需要开发一个打印票据的需求。于是前面找了一堆资料来简单学习了下,就开始自己动手开发起来了,下面直接细说。
首先小票模板的设计就用到了Jaspersoft Studio这个软件(如果需要可以联系我或者官网上能下载到: https://community.jaspersoft.com/community-download)。
1.模板设计。
设计模板的步骤就不一一细说了,前面转载的文章也有提到,可以去看看。直接上已经做好的模板,如下图:
数据来源是 json数据源,先写一个json文件并且类型、名称要对应与之连接。
而两者连接需要xml文件,再新建一个xml文件。
最后进行连接匹配,如下图:
最后将其生成的.jasper文件放到项目中去,如图:
2.工具类。
到此,模板就设计完成了,下面就是利用java代码进行赋值并且连接打印机打印了。
给出jasperReport的工具类,代码如下:
package com.yd.wb.report.jasperReport;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JRPrintPage;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.export.HtmlExporter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import net.sf.jasperreports.engine.query.JsonQueryExecuterFactory;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleHtmlExporterOutput;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;
import net.sf.jasperreports.export.SimpleXlsxReportConfiguration;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
import util.JCDFJsonUtil;
/**
* @Description 打印PDF格式报表的工具类
* 使用步骤:
* 1.通过spring mvc生成json格式的业务数据
* 2.将上一步生成的json数据保存成文件(调用exportJasperReport时将ReportType设置成JSON)
* 3.在Jaspersoft@Studio创建DataAdapter, 类型为JSON File, 将上一步生成的文件作为数据源
* 4.在Jaspersoft@Studio创建Jasper Report
* 5.将编译好的jasper复制到WEB-INF下的report目录下
* 6.调整Controller将输出的ReportType调整成真实的类型, 运行输出
* 注意:
* 在Jasper Report创建时一定要增加一个 SUBREPORT_DIR 用于存储子报表路径
*
*/
@Component
public class JasperResolver {
private Logger logger = Logger.getLogger(JasperResolver.class);
@Autowired
private ResourceLoader resourceLoader;
/**
* @Description 将JSON填充到JasperReport格式化输出
* @param data 单报表输出的数据 Map<String, Object>
* @param reportFileName 报表文件名
* @param reportType 报表类型
* @return void
*
*/
public void exportJasperReport(Map<String, Object> data, String reportFileName, ReportType reportType,
HttpServletRequest request, HttpServletResponse response) throws Exception{
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
list.add(data);
exportJasperReport(list, reportFileName, reportType, request, response);
}
/**
* @Description 将JSON填充到JasperReport格式化输出, 支持连打, 每一个List下的Item为一个Report
* @param data 多报表输出 List<Map<String, Object>>
* @param reportFileName 报表文件名
* @param reportType 报表类型
* @return void
*
*/
public void exportJasperReport(List<Map<String, Object>> data, String reportFileName, ReportType reportType,
HttpServletRequest request, HttpServletResponse response) throws Exception{
exportJasperReport(data, "/WEB-INF/report/", reportFileName, reportType, request, response);
}
/**
* @Description 具体的实现方法
* @param data 要打印的数据
* @param reportPath jasper文件所在的路径
* @param reportFileName 报表文件名
* @param reportType 报表类型
* @return void
*
*/
private void exportJasperReport(List<Map<String, Object>> data, String reportPath, String reportFileName, ReportType reportType,
HttpServletRequest request, HttpServletResponse response) throws Exception{
OutputStream os = null;
JasperPrint jasperPrint = null;
try {
//JSON直接输出
if(reportType == ReportType.JSON){
response.setContentType("text/html;charset=UTF-8");
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache, must-revalidate");
response.setHeader("Pragma", "no-cache");
try {
response.getWriter().write(JCDFJsonUtil.fromObjctToJson(data, null));
response.getWriter().flush();
response.getWriter().close();
} catch (IOException e) {
e.printStackTrace();
}
return;
}
//获取页面输出流
os = response.getOutputStream();
//设置页面类型及编码
response.setContentType(reportType.getMimeType() + "; charset=utf-8");
//清除页面缓存
response.setDateHeader("Expires", 0);
//设置文件名
response.setHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(UUID.randomUUID() + reportType.getSuffix(), "utf-8"));
JasperReport report = (JasperReport)JRLoader.loadObject(resourceLoader.getResource(reportPath + reportFileName + ".jasper").getInputStream());
//创建HashMap来添加报表参数
Map<String, Object> parameters = new HashMap<String, Object>();
//添加标题参数, 确保密钥与JasPrar报表中命名参数的名称相同
String classesPath = this.getClass().getClassLoader().getResource("").getPath();
String servletContextRealPath = classesPath.substring(0, classesPath.lastIndexOf("WEB-INF"));
parameters.put("SUBREPORT_DIR", servletContextRealPath + reportPath);
for(Map<String, Object> item : data){
String json = JCDFJsonUtil.fromObjctToJson(item, null);
//将JSON字符串转换为字节数组,从JSON流创建JSON数据源
ByteArrayInputStream jsonDataStream = new ByteArrayInputStream(json.getBytes("utf-8"));
parameters.put(JsonQueryExecuterFactory.JSON_INPUT_STREAM, jsonDataStream);
if(null == jasperPrint){
jasperPrint = JasperFillManager.fillReport(report, parameters);
} else { //连打
JasperPrint jasperPrintTemp = JasperFillManager.fillReport(report, parameters);
List<JRPrintPage> pages = jasperPrintTemp.getPages();
for (JRPrintPage page : pages) {
jasperPrint.addPage(page);
}
}
}
switch(reportType){
case PDF:
JRPdfExporter pdfExporter = new JRPdfExporter();
pdfExporter.setExporterInput(new SimpleExporterInput(jasperPrint));
pdfExporter.setExporterOutput(new SimpleOutputStreamExporterOutput(os));
pdfExporter.exportReport();
break;
case XLSX:
Map<String, String> dateFormats = new HashMap<String, String>();
dateFormats.put("EEE, MMM d, yyyy", "ddd, mmm d, yyyy");
JRXlsxExporter xlsxExporter = new JRXlsxExporter();
SimpleXlsxReportConfiguration configuration = new SimpleXlsxReportConfiguration();
xlsxExporter.setExporterInput(new SimpleExporterInput(jasperPrint));
xlsxExporter.setExporterOutput(new SimpleOutputStreamExporterOutput(os));
configuration.setDetectCellType(Boolean.TRUE);
configuration.setFormatPatternsMap(dateFormats);
xlsxExporter.setConfiguration(configuration);
xlsxExporter.exportReport();
break;
default:
HtmlExporter htmlExporter = new HtmlExporter();
htmlExporter.setExporterInput(new SimpleExporterInput(jasperPrint));
htmlExporter.setExporterOutput(new SimpleHtmlExporterOutput(os));
htmlExporter.exportReport();
break;
}
if(null != os){
os.flush();
}
} finally {
if(null != os){
try {
os.close();
} catch (Exception e) {
logger.error(e);
}
}
}
}
}
package com.yd.wb.report.jasperReport;
import java.util.HashMap;
import java.util.Map;
/**
* @Description 打印PDF格式报表的类型的枚举类
*
*/
public enum ReportType {
PDF(".pdf",1,"application/pdf"),
XLSX(".xlsx",2,"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
HTML(".html",4,"text/html"),
JSON(".json",4,"application/json");
/**后缀*/
private String suffix;
/**枚举值*/
private int value;
/**页面类型*/
private String mimeType;
private ReportType(String suffix, int value, String mimeType){
this.suffix = suffix;
this.value = value;
this.mimeType = mimeType;
}
//在枚举类型上实现fromString方法
private static final Map<String, ReportType> stringToEnum = new HashMap<String, ReportType>();
static {
//从常量名初始化映射到enum常量
for(ReportType item : values()){
stringToEnum.put(item.toString(), item);
}
}
//返回字符串的BLAH,如果字符串无效,则为nul
public static ReportType fromString(String name){
return stringToEnum.get(name);
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
}
3.java代码获取值
controller层代码:
……………………………………………………………有关别的项目的代码就不显示了。
@Autowired
private JasperResolver jasperResolver;
private static final String C_ACTION_PRINT = "printTickets";
/**
* 打印小票
*/
@RequestMapping(value="/printTickets")
public CIPResponseMsg print(HttpServletRequest request,HttpServletResponse response,String serial_no,String trans_doc_id,String gross_weight,String net_weight){
CIPResponseMsg msg = new CIPResponseMsg();
//String trans_doc_id = request.getParameter("trans_doc_id");
//Integer gross_weight = Integer.parseInt(request.getParameter("gross_weight"));
Integer grossWeight = Integer.parseInt(gross_weight);
try {
/*1、模板一:网点车未过磅小票。
网点车未过磅判断逻辑:【毛重KG】字段为0,发车凭证300开头*/
if(grossWeight == 0 && trans_doc_id.startsWith("300")){
List<Map<String, Object>> data = dataService.queryData(serial_no);
jasperResolver.exportJasperReport(data, "TICKETS_NETPOINT_CARS1", ReportType.PDF, request, response);
}else if(grossWeight > 0 && trans_doc_id.startsWith("300")){
/*2、模板二:网点车已过磅小票。
网点车车已过磅判断逻辑:【毛重KG】字段为大于0,发车凭证300开头*/
List<Map<String, Object>> data = dataService.queryOverweight(serial_no);
jasperResolver.exportJasperReport(data, "TICKETS_NETPOINT_CARS2", ReportType.PDF, request, response);
}else if(trans_doc_id.startsWith("68")){
/*3、模板三:网络车小票 网络车判断逻辑:发车凭证68开头。*/
List<Map<String, Object>> data = dataService.query(serial_no,trans_doc_id,net_weight);
jasperResolver.exportJasperReport(data, "TICKETS_NETPOINT_CARS3", ReportType.PDF, request, response);
}
} catch (CIPServiceException e) {
CIPErrorCode error = e.getErrorCode();
msg.errorCode = error.code;
msg.msg = error.name;
} catch (CIPDaoException e) {
CIPErrorCode error = e.getErrorCode();
msg.errorCode = error.code;
msg.msg = error.name;
} catch (CIPRuntimeException e) {
CIPErrorCode error = e.getErrorCode();
msg.errorCode = error.code;
msg.msg = error.name;
} catch (Exception e) {
log.error(e);
}
return msg;
}
service层代码:
/**
* 打印
* 模板一:网点车未过磅小票。
*/
@Override
public List<Map<String, Object>> queryData(String ids) {
//定义一个list,封装结果集
List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
//将传过来的id字符串转成id数组
String[] idArr = ids.split(",");
for (String serial_no : idArr) {
//定义一个paraMap,封装查询参数
Map<String, Object> paraMap = new HashMap<String, Object>();
paraMap.put("serial_no", serial_no);
//定义一个data,封装结果
Map<String, Object> data = new HashMap<String,Object>();
//查询信息
Map<String, Object> map = dataDao.queryData(paraMap);
if(map != null){
Set<Entry<String, Object>> entrySet = map.entrySet();
for (Entry<String, Object> entry : entrySet) {
data.put(entry.getKey(), entry.getValue());
}
}
list.add(data);
}
return list;
}
dao层代码:
/**
* 打印功能
*/
@Override
public Map<String, Object> queryData(Map<String, Object> paraMap) {
Map<String, Object> map = null;
String sql = "SELECT b.com_name weight_site,DATE_FORMAT(create_time, '%Y-%m-%d %H:%i:%s') create_time,serial_no,b.com_name start_site_name,concat('(', a.start_site, ')') start_site,car_id,trans_doc_id,ifnull(c.emp_name,a.operator) operator,SYSDATE() FROM wb_busi_gross_weight a "
+ " LEFT JOIN wb_base_com b ON a.weight_site = b.com_bm LEFT JOIN wb_base_emp c on a.operator = c.emp_id WHERE a.serial_no = ?";
//Object[] obj = {trans_doc_id};
Object serial_no = paraMap.get("serial_no");
try {
map = jdbcTemplate.queryForMap(sql,serial_no);
return map;
} catch (Exception e) {
log.error(e);
return map;
}
}
sql语句,注意:查询后的字段要求与json文件的key相对应。
SELECT
b.com_name weight_site,
DATE_FORMAT(
create_time,
'%Y-%m-%d %H:%i:%s'
) create_time,
serial_no,
b.com_name start_site_name,
concat('(', a.start_site, ')') start_site,
car_id,
trans_doc_id,
ifnull(c.emp_name, '') operator,
SYSDATE()
FROM
wb_busi_gross_weight a
LEFT JOIN wb_base_com b ON a.weight_site = b.com_bm
LEFT JOIN wb_base_emp c ON a.operator = c.emp_id
WHERE
a.serial_no = '?'
html页面部分代码:
最后的效果如下图:
当然打印机驱动是我自己安装的,这个看公司用的什么打印机,这里我就不介绍打印机配置的步骤了。
仅此记录下来,欢迎各位大佬指教。