有报表,就抛不开打印的需求。原本打印功能都是由前端实现,包括了打印标题、页眉页脚、标题行等功能。随着需求越来越多,前端不干了,跟领导反馈实现了一个功能,引发了若干bug(会哭的孩子有奶喝)。所以,不哭的孩子(我这个后端)只能接下了这个后端打印的需求了。该篇文章适合中级以上开发阅读。
开发前需要引入poi包
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
事先声明:
推荐使用XSSF而不是HSSF,因为前者比后者更有优势。具体区别如下:
文件格式
HSSF:是操作Excel97-2003版本,扩展名为.xls。
XSSF:是操作Excel2007版本开始,扩展名为.xlsx。
还有一个更高版本的SXSSF:是在XSSF基础上,POI3.8版本开始提供的一种支持低内存占用的操作方式,扩展名为.xlsx。
兼容性
Excel2007版本可以打开.xls文件,反之则不能。
支持的行列数
.xls支持一个sheet最大行数65536,最大列数256。
.xlsx支持一个sheet最大行数1048576,最大列数16384。
而且.xlsx文件比.xls的压缩率高
/**
* 设置页眉页脚
*
* @author: xxx
* @date: 2023-02-02 09:43:20
* @param xssfSheet 需要设置的sheet页对象
* @param jsonObject 页眉页脚及打印相关配置
* @param queryParam 查询参数:与业务相关,用于获取值,可忽略
*/
private void setHeaderAndFooter(XSSFSheet xssfSheet, JSONObject jsonObject, JSONObject queryParam) {
// 打印设置start
XSSFPrintSetup ps = xssfSheet.getPrintSetup();
// 页眉页脚边距
ps.setHeaderMargin(0.1);
ps.setFooterMargin(0.1);
// 设置默认A4纸张
ps.setPaperSize(XSSFPrintSetup.A4_PAPERSIZE);
// 横向打印
ps.setLandscape(true);
// 将所有列打印在一页
ps.setFitHeight((short)0);
xssfSheet.setFitToPage(true);
// 水平居中
xssfSheet.setHorizontallyCenter(true);
// 设置标题行
int headerStartNum = jsonObject.getInteger("headerStartNum"); // 开始行号
if(0 < headerStartNum) {
int headerEndNum = jsonObject.getInteger("headerEndNum"); // 结束行号
// 下标从0开始
CellRangeAddress rowRangeRef = new CellRangeAddress(headerStartNum - 1, headerEndNum - 1, -1, -1);
xssfSheet.setRepeatingRows(rowRangeRef);
}
// 打印设置end
// 页眉页脚start
JSONObject headerAndFooter = jsonObject.getJSONObject("headerAndFooter");
if (headerAndFooter.size() < 1) {
return;
}
// 定义页眉左中右对象
StringBuffer headerLeft = new StringBuffer(""), headerCenter = new StringBuffer(""), headerRight = new StringBuffer("");
if (null != headerAndFooter) {
// 标题内容
String titleValue = headerAndFooter.getJSONObject("printTitleObj").getString("value");
// 如果有标题,则设置页眉的第一行
if (StringUtils.isNotEmpty(titleValue)) {
headerLeft.append("&B&18 \n&B&9 \n");
headerCenter.append("&B&18" + titleValue + "\n&B&9 \n");
headerRight.append("&B&18 \n&B&9第 &P 页,共 &N 页 \n");
}
// 处理页眉样式
JSONArray printerHeaderList = headerAndFooter.getJSONArray("printerHeaderList");
if (printerHeaderList.size() > 0) {
Header header = xssfSheet.getHeader();
for (int i = 0; i < printerHeaderList.size(); i++) {
JSONObject iJSONObject = printerHeaderList.getJSONObject(i);
JSONArray list = iJSONObject.getJSONArray("list");
for (int j = 0; j < list.size(); j++) {
// 获取内容
// 全部为业务系统自定义内容,为的是获取页眉需要设置的值,可忽略
JSONObject jList = list.getJSONObject(j);
String typeValue = jList.getString("typeValue");
String labelValue = jList.getString("labelValue");
String dsValue = jList.getString("doubleSelectValue");
String inputValue = jList.getString("inputValue");
String selectValue = jList.getString("selectValue");
labelValue = StringUtils.isEmpty(labelValue) ? "" : labelValue + ":";
String value = "";
if ("input".equals(typeValue) && StringUtils.isNotEmpty(inputValue)) {
value = queryParam.getString(inputValue);
}
if ("select".equals(typeValue) && StringUtils.isNotEmpty(selectValue)) {
if (selectValue.indexOf("userInfo__") > -1) {
String fieldName = selectValue.split("__")[1];
String getFieldName = "get" + fieldName.replaceFirst(fieldName.substring(0, 1),
fieldName.substring(0, 1).toUpperCase());
try {
value = UserInfoHolder.getCurrentUserInfo().getClass().getMethod(getFieldName)
.invoke(UserInfoHolder.getCurrentUserInfo()).toString();
} catch (Exception e) {
log.error("获取用户信息异常:" + e.toString());
}
} else if ("other-time-all".equals(selectValue)) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
value = LocalDateTime.now().format(dtf);
} else {
value = queryParam.getString(selectValue + "__showContent");
}
}
if ("doubleSelect".equals(typeValue) && StringUtils.isNotEmpty(dsValue)) {
String ldsValue = jList.getString("labelDoubleSelectValue");
value = queryParam.getString(selectValue) + ldsValue + queryParam.getString(dsValue);
}
value = "&9" + labelValue + value;
if (i > 0) {
value += "\n";
}
// 判断位置并赋值
if (0 == j) {
headerLeft.append(value);
} else if (1 == j) {
headerCenter.append(value);
} else {
headerRight.append(value);
}
}
}
// 赋值页眉内容
header.setLeft(headerLeft.toString());
header.setCenter(headerCenter.toString());
header.setRight(headerRight.toString());
}
// 处理页脚样式
JSONArray printerFooterList = headerAndFooter.getJSONArray("printerFooterList");
if (printerFooterList.size() > 0) {
StringBuffer footLeft = new StringBuffer(""), footCenter = new StringBuffer(""), footRight = new StringBuffer("");
Footer footer = xssfSheet.getFooter();
for (int i = 0; i < printerFooterList.size(); i++) {
// 具体实现同页眉
}
footer.setLeft(footLeft.toString());
footer.setCenter(footCenter.toString());
footer.setRight(footRight.toString());
}
}
}
headerAndFooter:页眉页脚设置的json配置对象;
printTitleObj:标题内容;
printerHeaderList:页眉对象集合,具体不做赘述;
printerFooterList:页脚对象集合。
&B:加粗;
&18:18号字体;
&P:当前页码数;
&N:总页数。