最近有一个业务是根据用户的输入动态生成word,其中包括动态表格,以下是博主的实现方式
1、引入pom依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
这里博主用的是4.1.2版本,之前用的5.x版本总是报InvalidFormatException异常,至今没找到原因,有知道的小伙伴也可以在评论区给出解决办法
2、创建传输对象PersonDto
import lombok.Data;
import java.util.List;
@Data
public class PersonDto {
private String name;//姓名
private Integer age;//年龄
private String practiceDuration;//练习时长
private List<String> interest;//兴趣爱好
}
3、控制层代码
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private TestService testService;
@GetMapping("/export")
public void renewalExport(PersonDto dto, HttpServletResponse response){
testService.export(dto,response);
}
}
ps:传输数据多的话可以使用post请求,使用@RequestBody 注解
4、业务层代码
@Service
@Slf4j
public class TestService {
public void export(PersonDto dto,HttpServletResponse response) {
InputStream in = null;
XWPFDocument doc = null;
try {
// 1. 创建 Word 文档对象
ClassPathResource resource = new ClassPathResource("模板.docx");//如果是doc格式的话下面创建的对象是new HSSFWorkbook()
in = resource.getInputStream();
doc = new XWPFDocument(in);
//创建测试数据
dto.setAge(25);
dto.setName("坤坤");
dto.setPracticeDuration("两年半");
List<String> list = new ArrayList<String>(){{
add("唱");
add("跳");
add("rap");
add("篮球");
}};
dto.setInterest(list);
// 2. 填充文本内容
Map<String, String> textMap = new HashMap<>();
textMap.put("name", dto.getName());
textMap.put("age", String.valueOf(dto.getAge()));
textMap.put("practiceDuration", dto.getPracticeDuration());
for (XWPFParagraph p : doc.getParagraphs()) {
List<XWPFRun> runs = p.getRuns();
if (runs != null) {
for (XWPFRun run : runs) {
String text = run.getText(0);
if (text != null) {
for (Map.Entry<String, String> entry : textMap.entrySet()) {
if (text.contains(entry.getKey())) {
text = text.replace(entry.getKey(), entry.getValue());
run.setText(text, 0);
}
}
}
}
}
}
// 定位到第一个表格并获取其第一行(即标题行)
XWPFTable table = doc.getTables().get(0);
// 获取每列的索引
for (int i = 1; i <= dto.getInterest().size(); i++) {
String data = dto.getInterest().get(i - 1);
XWPFTableRow row = table.createRow();
// 根据列名索引获取单元格(这里以第一列“序号”作为示例)
XWPFTableCell cell1 = row.getCell(0);
if (cell1 == null) {
cell1 = row.createCell();
}
cell1.setText(String.valueOf(i)); // 序号加1
// 根据列名依次填充单元格的文本内容
XWPFTableCell cell2 = row.getCell(1);
if (cell2 == null) {
cell2 = row.createCell();
}
cell2.setText(data); // 产品名称
}
// 将文档保存到输出流中并设置响应头
String fileName = "test.docx";
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes("UTF-8"), "iso-8859-1"));
doc.write(response.getOutputStream());
response.flushBuffer();
} catch (IOException e) {
// 处理异常...
log.error(e.getMessage(),e);
} finally {
try {
in.close();
} catch (Exception e) {
}
}
}
}
5、word模板(放在resources目录下)
6、输出word
以上就是实现word导出的全部过程,博主目前还有一个问题没有解决就是动态表格的内容样式不能根据表头的样式来,希望有小伙计解决并指出。