Aspose-words export PDF guide: Java export template PDF with pictures
Hello everyone, long time no see. I’ve been busy recently, so I’ve been writing less and less blogs. During the development process, I encountered a need to export PDF, export according to the template style, and deal with image problems. I’m scratching my head. To be honest, I’ve been exposed to Excel export before. Wave this demand point uses Aspose.Words to export the pitfalls encountered in PDF export and how to export it.
Introduction to a Jar package
Aspose.Words is a commercial .NET class library that enables applications to handle large document tasks. Aspose.Words supports different formats such as Doc, Docx, PDF, etc. Using this class library can generate, modify, convert and print documents without using Microsoft.Word. Using Aspose.Words in a project can have the following benefits.
What I share today is to use Aspose.Words to export PDF and pictures in Java. The maven dependencies are as follows
<dependency>
<groupId>com.luhuiguo</groupId>
<artifactId>aspose-words</artifactId>
<version>23.1</version>
</dependency>
Two export steps
Let's first take a look at the exported blank template
and observe this template. We can see that there are four places that need to be processed: realName, addr, picture 1, picture 2, and patrol check-in. First, execute to see the effect.
What we need to do is to save this template Word first, and then put it in our project. For example, I put it in the Resources directory here. Let’s gossip
and upload the code! !
@ApiOperation("测试PDF导出")
@GetMapping("/api/ffp/dict/PDFTest")
public ApiResult<Boolean> PDFTest(HttpServletResponse response,@RequestParam Long id) throws Exception {
FfpFileInfo fileInfo = ffpFileInfoService.getById(id);
if (ObjectUtil.isEmpty(fileInfo)) {
return ApiResult.error(602, "文件不存在");
}
String base64 = baseS3Service.downloadWithBase64(fileInfo.getFileKey());
byte[] bytes = Base64.getDecoder().decode(base64);
ClassPathResource classPathResource= new ClassPathResource("/templateFile/demo.docx");
InputStream inputStream = classPathResource.getInputStream();
Document document=new Document(inputStream);
Map paramsMap = new HashMap();
paramsMap.put("realname","Spring不止春天");
paramsMap.put("addr","四川");
PdfUtils.replaceText(paramsMap,document);
PdfUtils.replaceBookMarkImage( bytes,document);
String name="测试测试";
File tempFile = File.createTempFile(name, ".pdf");
//插入表格
DocumentBuilder builder = new DocumentBuilder(document);
NodeCollection runs = document.getChildNodes(NodeType.PARAGRAPH, true);
for (int i = 0; i < runs.getCount(); i++){
Node node = runs.get(i);
String text = node.getText();
System.out.println(text);
if (text.contains("巡防打卡")){
builder.moveTo(node);
Table table = builder.startTable();
// Insert a cell
builder.insertCell();
table.autoFit( AutoFitBehavior.AUTO_FIT_TO_CONTENTS );
table.setAlignment(1);
builder.getCellFormat().setWidth(135);
builder.write( "打卡时间" );
builder.insertCell();
builder.write( "日志" );
builder.insertCell();
builder.write( "打卡地址" );
// End row
builder.endRow();
// start a next row and set its properties
builder.getRowFormat().setHeight( 40 );
builder.getCellFormat().setWidth(135);
builder.insertCell();
builder.write( "2023:09:01:" );
builder.getCellFormat().setWrapText(true);
builder.insertCell();
builder.write( "进行了打卡的日志" );
builder.getCellFormat().setWrapText(true);
builder.insertCell();
builder.write( "四川省成都市武侯区1111111111111111111" );
builder.getCellFormat().setWrapText(true);
builder.endRow();
//第二行
builder.insertCell();
builder.write( "2023:09:01:" );
builder.getCellFormat().setWrapText(true);
builder.insertCell();
builder.write( "进行了打卡的日志" );
builder.getCellFormat().setWrapText(true);
builder.insertCell();
builder.write( "四川省成都市武侯区2222222222222222222222" );
builder.getCellFormat().setWrapText(true);
builder.endRow();
// End table
builder.endTable();
}
}
document.save(new FileOutputStream(tempFile), SaveFormat.PDF);
InputStream fis = new BufferedInputStream(new FileInputStream(tempFile));
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
// 清空response
response.reset();
String filename=tempFile.getName();
// 设置响应的头部信息
response.setContentType("application/octet-stream;charset=UTF-8");
String fileName = new String(filename.getBytes("gb2312"), "iso8859-1");
response.setHeader("Content-disposition", "attachment;filename=" + fileName);
OutputStream ouputStream = response.getOutputStream();
ouputStream.write(buffer);
ouputStream.flush();
ouputStream.close();
tempFile.delete();
return ApiResult.success(true);
}
Next, let me explain the PDF processing in three different formats, such as simple parameter replacement, image insertion, and list insertion.
A simple parameter substitution
The two parameters realName and addr belong to simple replacement values for processing. You can see that there is such a section in the code
that replaceText is the real replacement method. The method is as follows:
/***
* 进行Word文件中的参数替换,方便转为PDF进行导出
* @author jiazl
* @date 2023/6/15 17:54
* @param paramMap,doc
* @return void
**/
public static void replaceText(Map<String, String> paramMap, Document doc) throws Exception {
FindReplaceOptions opt = new FindReplaceOptions();
for (Map.Entry<String, String> entry : paramMap.entrySet()) {
String key = String.format("{%s}", entry.getKey());
String value = Objects.isNull(entry.getValue()) ? "" : entry.getValue();
doc.getRange().replace(key, value, opt);
}
int replace = doc.getRange().replace(Pattern.compile(PARAM_MATCH), "", opt);
if (replace > 0) {
logger.error("未知参数:{}", JSON.toJSONString(paramMap));
}
}
The meaning of this code is to find the {%s} parameter in Word, and use the Map of paramMap to replace the value. This is very simple and will not be described in detail.
Insertion of two pictures
Careful comrades have already discovered that the API I gave has parameters. What is this parameter? It is a file ID. To insert a picture at the place we want to insert, we need to find the node in Word. For example: the method of inserting a picture is
:
/***
* 进行Word文件中的图片插入(单处地方,单个图片)
* @author jiazl
* @date 2023/6/15 17:54
* @param doc
* @return void
**/
public static void replaceBookMarkImage( byte[] bytes, Document doc) throws Exception {
DocumentBuilder db = new DocumentBuilder(doc);
NodeCollection runs = doc.getChildNodes(NodeType.PARAGRAPH, true);
for (int i = 0; i < runs.getCount(); i++) {
Node node = runs.get(i);
String text = node.getText();
System.out.println(text);
if (text.contains("图片1")) {
db.moveTo(node);
db.insertImage(bytes, 119.4, 64);
}
}
}
In the template pdf, it is here
that when he finds this node, it will execute
db.moveTo(node);
db.insertImage(bytes, 119.4, 64);
These two methods, the first is to transfer the operation object to this node, and the second is to insert the picture, 119.4 and 64 are the set picture size respectively.
(Of course, here is a Demo interface, so the node search picture 1 is hard-coded. You can pass in the node you want to find as a parameter, so that the code will be stronger!)
Insertion of three columns
My family, it’s too difficult. I have browsed many websites, and few people write clearly about list insertion, because this Jar package was repackaged by a domestic boss (genuine foreign charges), without comments, I tried it out one by one, please give me a thumbs up~~ For the operation of the list, we mainly look at this part of the
code
//插入表格
DocumentBuilder builder = new DocumentBuilder(document);
NodeCollection runs = document.getChildNodes(NodeType.PARAGRAPH, true);
for (int i = 0; i < runs.getCount(); i++){
Node node = runs.get(i);
String text = node.getText();
System.out.println(text);
if (text.contains("巡防打卡")){
builder.moveTo(node);
Table table = builder.startTable();
// Insert a cell
builder.insertCell();
table.autoFit( AutoFitBehavior.AUTO_FIT_TO_CONTENTS );
table.setAlignment(1);
builder.getCellFormat().setWidth(135);
builder.write( "打卡时间" );
builder.insertCell();
builder.write( "日志" );
builder.insertCell();
builder.write( "打卡地址" );
// End row
builder.endRow();
// start a next row and set its properties
builder.getRowFormat().setHeight( 40 );
builder.getCellFormat().setWidth(135);
builder.insertCell();
builder.write( "2023:09:01:" );
builder.getCellFormat().setWrapText(true);
builder.insertCell();
builder.write( "进行了打卡的日志" );
builder.getCellFormat().setWrapText(true);
builder.insertCell();
builder.write( "四川省成都市武侯区1111111111111111111" );
builder.getCellFormat().setWrapText(true);
builder.endRow();
//第二行
builder.insertCell();
builder.write( "2023:09:01:" );
builder.getCellFormat().setWrapText(true);
builder.insertCell();
builder.write( "进行了打卡的日志" );
builder.getCellFormat().setWrapText(true);
builder.insertCell();
builder.write( "四川省成都市武侯区2222222222222222222222" );
builder.getCellFormat().setWrapText(true);
builder.endRow();
// End table
builder.endTable();
}
}
Here, as a demo test interface, two rows of data are hard-coded, and when applied to specific businesses, you can use the for loop to insert.
Is this familiar? The insertion list is also to find the node that needs to be inserted, and then
the effect is like this. As
for the data insertion, please see:
the overall effect is as follows .
It should be noted that sometimes some fields are too long
builder.getCellFormat().setWrapText(true);
This method in the code is to let him break the line in the box
Three summary and some points for attention
1 Because for bloggers, inserting pictures, inserting tables, and replacing template parameters are already enough to meet most of the development tasks. The deeper reason is that bloggers are lazy, so they don't understand it.
2 This Jar package has requirements for pictures, after some tests by bloggers. JPG, JPEG, and PNG can all export pictures, but if you criticize WEBP by name, you will report an error, because I am a lazy dog, and I have forgotten what I did wrong.
3 Adhere to the attitude of copying. If you have any questions about the methods in the blogger’s article, you can privately message the blogger. The blogger will reply when he sees it. Don’t worry, it’s not a big cake.
4 Some operations such as assigning values to the response by the blogger at the end are useless. Swagger does not support exporting and downloading files. If you use PostMan to adjust the interface, you will find that
the blogger has worked hard and cannot solve the problem of the suffix, so the blogger put it badly and let the front end handle it.
5 Note that in the code
Map paramsMap = new HashMap();
paramsMap.put("realname","Spring不止春天");
paramsMap.put("addr","四川");
This paramsMap should correspond to the PDF, otherwise an error will be reported, and any mistakes will be forgotten.
6 Some people will say, what about the word picture in the final effect? It's really smart, just replace it again, just replace the word "picture" with an empty string, because of the space, the code is not included.
7 Originally, I also wanted to write well, but I am really a lazy dog. I am sorry everyone, but I can guarantee that the code is good, it is used normally, and it is OK! If you have any questions, please feel free to contact~