由於項目業務需要,需要開發一個打印票據的需求。於是前面找了一堆資料來簡單學習了下,就開始自己動手開發起來了,下面直接細說。
首先小票模板的設計就用到了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頁面部分代碼:
最後的效果如下圖:
當然打印機驅動是我自己安裝的,這個看公司用的什麼打印機,這裏我就不介紹打印機配置的步驟了。
僅此記錄下來,歡迎各位大佬指教。