一:模版准备
1画模版通过Adobe Acrobat 软件,里面有设置字体和多行,居中等

2模版名称必须与java中字段名一致

3设置模版文件居中字体等,可以单击每一个属性也可以按住shift然后鼠标左键多选进行设置

二代码实现
1引入依赖
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
2 引入工具类
package com.cpit.util;
import java.math.BigDecimal;
public class NumberToCN {
private static final String[] CN_UPPER_NUMBER = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
private static final String[] CN_UPPER_MONETRAY_UNIT = {"分", "角", "元", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾",
"佰", "仟", "兆", "拾", "佰", "仟"};
private static final String CN_FULL = "整";
private static final String CN_NEGATIVE = "负";
private static final int MONEY_PRECISION = 2;
private static final String CN_ZEOR_FULL = "零元" + CN_FULL;
public static String number2CNMontrayUnit(BigDecimal numberOfMoney) {
StringBuffer sb = new StringBuffer();
int signum = numberOfMoney.signum();
if (signum == 0) {
return CN_ZEOR_FULL;
}
@SuppressWarnings("deprecation")
long number = numberOfMoney.movePointRight(MONEY_PRECISION).setScale(0, 4).abs().longValue();
long scale = number % 100;
int numUnit = 0;
int numIndex = 0;
boolean getZero = false;
if (!(scale > 0)) {
numIndex = 2;
number = number / 100;
getZero = true;
}
if ((scale > 0) && (!(scale % 10 > 0))) {
numIndex = 1;
number = number / 10;
getZero = true;
}
int zeroSize = 0;
while (true) {
if (number <= 0) {
break;
}
numUnit = (int) (number % 10);
if (numUnit > 0) {
if ((numIndex == 9) && (zeroSize >= 3)) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[6]);
}
if ((numIndex == 13) && (zeroSize >= 3)) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[10]);
}
sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
sb.insert(0, CN_UPPER_NUMBER[numUnit]);
getZero = false;
zeroSize = 0;
} else {
++zeroSize;
if (!(getZero)) {
sb.insert(0, CN_UPPER_NUMBER[numUnit]);
}
if (numIndex == 2) {
if (number > 0) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
}
} else if (((numIndex - 2) % 4 == 0) && (number % 1000 > 0)) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
}
getZero = true;
}
number = number / 10;
++numIndex;
}
if (signum == -1) {
sb.insert(0, CN_NEGATIVE);
}
if (!(scale > 0)) {
sb.append(CN_FULL);
}
return sb.toString();
}
}
3核心代码 注意由于Adobe Acrobat设置左对齐同时不能垂直居中,因此需要手动设置
@PostMapping(value = "/pdfBatchPrint")
public void pdfBatchPrint(HttpServletResponse response, @RequestBody VchPrepareVerchurHeadCondition condition) {
ByteArrayOutputStream pdf = null;
OutputStream os= null;
try {
List<VchPrepareVerchurHead> headList = vchPrepareVerchurHeadService.findVchPrepareVerchurHeadListFromADS(condition);
if(CollectionUtils.isEmpty(headList)){
setHttpResponse(response, "批量打印异常!\n" + "无打印数据");
}
List<VchPrepareHeadAndDetailVO> list = vchPrepareVerchurHeadService.findVchPrepareVerchurHeadAndDetailList2FromADS(headCondition);
Map<String, List<VchPrepareHeadAndDetailVO>> listMap = list.stream().collect(Collectors.groupingBy(e -> e.getHeadId() + ""));
Map<String, List<VchPrepareVerchurHead>> headListMap = headList.stream().collect(Collectors.groupingBy(e -> e.getId() + ""));
response.setHeader("Content-Disposition", "attachment;filename=test_report.pdf");
response.setContentType("application/pdf");
pdf = createPdf(listMap, headListMap);
os = response.getOutputStream();
os.write(pdf.toByteArray());
os.flush();
} catch (Exception e) {
log.error("pdfBatchPrint异常", e);
setHttpResponse(response, "批量打印异常!\n" + e.getLocalizedMessage());
}finally {
IOUtils.closeQuietly(os);
IOUtils.closeQuietly(pdf);
}
}
public ByteArrayOutputStream createPdf(Map<String, List<VchPrepareHeadAndDetailVO>> listMap, Map<String, List<VchPrepareVerchurHead>> headListMap) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Document document = new Document();
PdfCopy copy = new PdfCopy(document, baos);
document.open();
for (Map.Entry<String, List<VchPrepareHeadAndDetailVO>> entry : listMap.entrySet()) {
List<VchPrepareHeadAndDetailVO> value = entry.getValue();
BigDecimal debitAmount = value.stream().filter(e -> "DR".equals(e.getDirection()))
.map(VchPrepareHeadAndDetailVO::getAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal creditAmount = value.stream().filter(e -> "CR".equals(e.getDirection()))
.map(VchPrepareHeadAndDetailVO::getAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
List<VchPrepareVerchurHead> vchPrepareVerchurHeads = headListMap.get(entry.getKey());
VchPrepareVerchurHead vchPrepareVerchurHead = vchPrepareVerchurHeads.get(0);
DecimalFormat decimalFormat = new DecimalFormat("#,##0.00");
String createdBy = vchPrepareVerchurHead.getCreatedBy().equals("system") ? "系统集成" : vchPrepareVerchurHead.getCreatedBy();
List<List<VchPrepareHeadAndDetailVO>> partition = Lists.partition(value, 10);
String pageSize = String.valueOf(partition.size());
int i = 0;
for (List<VchPrepareHeadAndDetailVO> palist : partition) {
S3Object s3Object = ossTemplate.getObject(bucketName, OssPathCst.XK_BACKUPCOL12_EXPORT_TEMP_PATH);
PdfReader templateReader = new PdfReader(s3Object.getObjectContent());
ByteArrayOutputStream singlePageBaos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(templateReader, singlePageBaos);
AcroFields fields = stamper.getAcroFields();
BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
fields.addSubstitutionFont(font);
i++;
String pageNo = String.valueOf(i);
if (pageSize.equals(pageNo)) {
fields.setField("debitAmountStr", decimalFormat.format(debitAmount));
fields.setField("creditAmountStr", decimalFormat.format(creditAmount));
String valueStr = "合计:" + NumberToCN.number2CNMontrayUnit(debitAmount);
String key = "amountStr";
addTextToPdfCenter(fields, stamper, valueStr, key, font);
}
fields.setField("pageNo", pageNo + "/" + pageSize);
fields.setField("acctUser", "test");
fields.setField("createdBy", createdBy);
Map<String, String> map = new HashMap();
Map<String, String> stringStringMap = turnMap(vchPrepareVerchurHead);
Map<String, String> stringStringMap1 = listTurnMap(palist);
map.putAll(stringStringMap1);
for (String key : map.keySet()) {
String valueStr = map.get(key);
addTextToPdfCenter(fields, stamper, valueStr, key, font);
}
fillData(fields, stringStringMap);
stamper.setFormFlattening(true);
stamper.close();
PdfImportedPage filledPage = copy.getImportedPage(new PdfReader(singlePageBaos.toByteArray()), 1);
copy.addPage(filledPage);
}
}
document.close();
return baos;
}
private void setHttpResponse(HttpServletResponse response, String msg) throws BadRequestException {
try {
response.setHeader("Content-type", "text/json;charset=UTF-8");
response.setHeader("IsAlert", "1");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.println(String.format("{\"code\":\"-1\", \"msg\":\"%s\"}", msg));
out.flush();
out.close();
} catch (IOException e) {
throw new BadRequestException("msg");
}
}
public static void fillData(AcroFields fields, Map<String, String> data) throws IOException, DocumentException {
Map<String, AcroFields.Item> formFields = fields.getFields();
for (String key : data.keySet()) {
if (formFields.containsKey(key)) {
String value = data.get(key);
if (StringUtils.isBlank(value)) {
fields.setField(key, "");
} else {
fields.setField(key, value);
}
}
}
}
public static Map<String, String> listTurnMap(List listValue) {
Map<String, String> map = new HashMap<>();
List<Object> list = (List) listValue;
String sb = "lineSummary,accountsNo,accountsNoName,debitAmountStr,creditAmountStr,";
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
Map<String, Object> stringObjectMap = BeanUtil.beanToMap(o);
for (Map.Entry<String, Object> entry : stringObjectMap.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (sb.contains(key) && Objects.nonNull(value)) {
map.put(StrUtil.format("{}.{}{}", "xkList", key, i), String.valueOf(value));
}
}
}
return map;
}
public static Map<String, String> turnMap(Object object) {
Map<String, Object> stringObjectMap = BeanUtil.beanToMap(object);
Map<String, String> map = new HashMap<>();
for (Map.Entry<String, Object> entry : stringObjectMap.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
String sb = "compName,microAppName,voucherHeadCode,accountDate,backupCol12";
if (ObjectUtil.isNotEmpty(value)) {
if (isPrimitiveOrWrapper(value.getClass()) && sb.contains(key)) {
if (key.equals("backupCol12")) {
map.put(key, "记-" + String.valueOf(value));
} else {
map.put(key, String.valueOf(value));
}
} else if ("accountDate".equals(key)) {
String accountDate = DateUtil.getLocalDateStr((Date) value, FormatEnum.FORMAT_DATE_CH);
map.put(key, accountDate);
}
}
}
return map;
}
private static boolean isPrimitiveOrWrapper(Class<?> clazz) {
return clazz.isPrimitive() || clazz.getName().startsWith("java.lang");
}
private static void addTextToPdfCenter(AcroFields form, PdfStamper stamper, String text, String fieldName, BaseFont baseFont) {
int pageNo = form.getFieldPositions(fieldName).get(0).page;
Rectangle signRect = form.getFieldPositions(fieldName).get(0).position;
PdfContentByte contentByte = stamper.getOverContent(pageNo);
PdfPTable table = new PdfPTable(1);
float totalWidth = signRect.getRight() - signRect.getLeft() - 1;
table.setTotalWidth(totalWidth);
Font font = new Font(baseFont, 7, Font.NORMAL);
PdfPCell cell = new PdfPCell(new Phrase(text, font));
cell.setFixedHeight(signRect.getTop() - signRect.getBottom() - 1);
cell.setBorderWidth(0);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
if (fieldName.contains("lineSummary") || fieldName.contains("debitAmountStr") || fieldName.contains("creditAmountStr")) {
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
}
table.addCell(cell);
table.writeSelectedRows(0, -1, signRect.getLeft(), signRect.getTop(), contentByte);
}
三最终效果:
