需求就是,有人提供了一个excel模板,模板里面的文字和图片都是从数据库或者文件服务器获取的,所有图片是动态的,图片获取也是多张的,需要填充到excel里面,最终返回给前端,所以我就想用freemaker + poi的技术,freemaker做文字填充相对简单点,图片填充就用poi的接口,我到网上找了个现成的demo但是样式全变了,
https://www.cnblogs.com/Hlingoes/p/14828344.html
https://github.com/Hlingoes/freemaker-poi-excel (仓库地址),我按照仓库的demo试里面的是没问题的,但是试我自己的,我的样式就全乱了
如下图
因为poi的api的合并单元格,样式填充我用的不是很熟练,我只有freemaker的api,所以看看有没有现成的解决方案
需求模板图
有点被你误导了__
你到底是要打印功能还是导出excel功能?
首先分为2块。
第一:你要的是打印功能
第二:数据图片动态加载
那么就一个一个来。
1.可以参考这个来实现打印:https://blog.csdn.net/yxh13521338301/article/details/85235442
2.你的数据可以动态从数据库取,然后渲染到页面,其中第一步链接里也有。
chatgpt:
要在Java中使用Freemarker动态生成Excel文档,可以使用POI和JExcelAPI这两个Java库中的一个来操作Excel。建议使用POI,因为它更强大和灵活。
以下是使用POI和Freemarker动态生成Excel文档并包含图片的示例代码:
首先,导入POI和Freemarker库的依赖项。
创建一个Excel模板文件,其中包含Excel的格式和样式,以及包含要动态插入的图片的占位符。
在Java代码中,读取Excel模板文件并将其解析为Freemarker模板。
创建一个数据模型,其中包含要在Excel中动态生成的数据和图片。
使用Freemarker模板将数据模型应用于模板文件,并将结果写入Excel文件。
以下是示例代码:
// 导入依赖项
import java.io.*;
import java.util.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import freemarker.template.*;
public class ExcelGenerator {
public static void main(String[] args) throws Exception {
// 读取Excel模板文件
FileInputStream fis = new FileInputStream("template.xls");
Workbook workbook = new HSSFWorkbook(fis);
// 创建Freemarker模板
Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
cfg.setClassForTemplateLoading(ExcelGenerator.class, "/");
Template template = cfg.getTemplate("template.ftl");
// 创建数据模型
Map<String, Object> data = new HashMap<String, Object>();
data.put("name", "John Doe");
List<String> images = new ArrayList<String>();
images.add("image1.jpg");
images.add("image2.jpg");
images.add("image3.jpg");
data.put("images", images);
// 将数据应用于模板并将结果写入Excel文件
StringWriter sw = new StringWriter();
template.process(data, sw);
String output = sw.toString();
Sheet sheet = workbook.getSheetAt(0);
int rownum = 1;
for (String image : images) {
InputStream is = new FileInputStream(image);
byte[] bytes = IOUtils.toByteArray(is);
int pictureIndex = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG);
Drawing drawing = sheet.createDrawingPatriarch();
CreationHelper helper = workbook.getCreationHelper();
ClientAnchor anchor = helper.createClientAnchor();
anchor.setCol1(1);
anchor.setRow1(rownum);
anchor.setCol2(2);
anchor.setRow2(rownum + 2);
Picture pict = drawing.createPicture(anchor, pictureIndex);
rownum += 3;
}
FileOutputStream fos = new FileOutputStream("output.xls");
workbook.write(fos);
fos.close();
}
}
在上面的代码中,template.xls是Excel模板文件,其中包含Excel的格式和样式,以及包含要动态插入的图片的占位符。template.ftl是Freemarker模板,用于将数据模型应用于Excel模板文件并生成最终的Excel文件。
data是数据模型,其中包含要在Excel中动态生成的数据和图片。在这个例子中,数据模型包含一个名为name的字符串变量和一个名为images的字符串列表,其中包含要动态插入的图片的文件名。
在将数据模型应用于Freemarker模板后,将其写入Excel文件。对于每个要插入的图片,将其作为字节数组读取,将其添加到Excel工作簿中,并使用Drawing和ClientAnchor将其插入到Excel单元格中。
最后,将Excel工作簿写入输出流,并将其保存到名为output.xls的文件中。
请注意,这只是一个简单的示例,您可能需要根据自己的需求进行修改。特别是,您需要注意图片的大小和位置,以便它们不会覆盖其他单元格中的数据。
题主你的问题有点模糊,可以再详细描述下。
图片的样式是动态多张的
这句话的意思该怎么理解。我的理解是后端有多个不确定的图片,需要代码动态选取某一张,将图片渲染到excel中。 这样理解对吗?
动态打印
“动态打印” 这句话应该是渲染的意思吧? 使用ftl将图片渲染,然后生成excel吧。 可以将代码发出来,这边看下什么问题。
关于excel生成的可以参考:关于Java使用EasyExcel导出动态数据为Excel文件示例
结果示例可以参考:https://img-blog.csdnimg.cn/1cc86ee5dffa48669e2b97283585fad2.png
该回答引用ChatGPT
您好,我认为可以通过在Freemarker中使用Java代码,动态地生成包含图片的HTML代码,并将其输出到浏览器中实现动态打印的功能。
在Freemarker中,您可以通过以下方式表示图片:
<img src="path/to/image.jpg" alt="image description">
要动态地生成多张图片的HTML代码,您可以使用Freemarker的循环结构,在模板中循环遍历多个图片,并生成相应的HTML代码。例如,以下代码将生成三个不同的图片:
<#list images as image>
<img src="${image.path}" alt="${image.description}">
</#list>
在Java代码中,您可以通过将图片的URL或字节数组传递给模板来生成包含图片的HTML代码。例如,以下Java代码使用Spring MVC将包含多个图片的HTML代码发送到浏览器:
@GetMapping("/print")
public void print(Model model, HttpServletResponse response) throws IOException {
List<Image> images = getImages(); // 获取图片列表
model.addAttribute("images", images); // 将图片列表添加到模型中
// 渲染模板并将结果发送到浏览器
response.setContentType("text/html");
Template template = configuration.getTemplate("print.ftl");
Writer writer = response.getWriter();
template.process(model.asMap(), writer);
writer.flush();
}
在上面的代码中,getImages()
方法将返回一个包含多个图片的列表。然后,将这些图片添加到Freemarker模型中。最后,使用configuration.getTemplate()
方法获取名为print.ftl
的模板文件,并使用template.process()
方法将模型和输出流作为参数渲染模板。在这个过程中,Freemarker将使用循环结构生成多个HTML代码块,每个代码块包含一个图片。
请注意,为了使此代码正常工作,必须在Spring配置中包含以下代码:
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("/WEB-INF/templates/");
return configurer;
}
上面的代码将Freemarker的模板加载路径设置为/WEB-INF/templates/
。这意味着模板文件必须放置在/WEB-INF/templates/
目录下,以便正确加载模板。
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
实现动态生成 Excel 文档并包含图片的方式有很多种,其中使用 Apache POI 结合 FreeMarker 是一种比较简单易懂的方式。
具体实现步骤如下:
在 Maven 项目中,需要在 pom.xml 文件中添加以下依赖:
<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>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
在 FreeMarker 中定义一个包含图片的模板文件,例如:
```xml
<worksheet xmlns="http://s/
基于最新版ChatGPT4的回答,望采纳!!!有其他问题也可以询问我哦💕(最新版更智能,功能更加强大):
根据您提供的信息,我可以推荐两种解决方案:
直接使用POI API填充文本和图片
您可以使用POI API直接填充文本和图片,而无需使用FreeMarker。以下是一个示例代码,演示如何使用POI API来处理您的Excel模板:
import java.io.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.util.IOUtils;
public class ExcelTemplate {
public static void main(String[] args) throws Exception {
String templatePath = "template.xlsx"; // 模板文件路径
String outputPath = "output.xlsx"; // 输出文件路径
// 从模板文件创建工作簿对象
FileInputStream input = new FileInputStream(new File(templatePath));
XSSFWorkbook workbook = new XSSFWorkbook(input);
input.close();
// 获取第一个工作表
XSSFSheet sheet = workbook.getSheetAt(0);
// 填充文本数据
fillText(sheet, "A2", "John Doe");
fillText(sheet, "B2", "123 Main St.");
fillText(sheet, "C2", "jdoe@example.com");
// 填充图片数据
InputStream imageStream = new FileInputStream(new File("image.jpg"));
byte[] imageData = IOUtils.toByteArray(imageStream);
int pictureIndex = workbook.addPicture(imageData, Workbook.PICTURE_TYPE_JPEG);
imageStream.close();
CreationHelper helper = workbook.getCreationHelper();
Drawing<?> drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = helper.createClientAnchor();
anchor.setCol1(CellReference.convertColStringToIndex("D"));
anchor.setRow1(1);
Picture picture = drawing.createPicture(anchor, pictureIndex);
picture.resize();
// 合并单元格并设置样式
CellStyle style = workbook.createCellStyle();
BorderStyle borderStyle = BorderStyle.THIN;
short borderColor = IndexedColors.BLACK.getIndex();
style.setBorderTop(borderStyle);
style.setBorderRight(borderStyle);
style.setBorderBottom(borderStyle);
style.setBorderLeft(borderStyle);
style.setTopBorderColor(borderColor);
style.setRightBorderColor(borderColor);
style.setBottomBorderColor(borderColor);
style.setLeftBorderColor(borderColor);
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
Font font = workbook.createFont();
font.setFontName("Arial");
font.setFontHeightInPoints((short)12);
font.setBold(true);
style.setFont(font);
sheet.addMergedRegion(CellRangeAddress.valueOf("A4:D4"));
XSSFCell cell = sheet.getRow(3).getCell(0);
cell.setCellValue("This is a merged cell");
cell.setCellStyle(style);
// 保存工作簿到输出文件
FileOutputStream output = new FileOutputStream(new File(outputPath));
workbook.write(output);
output.close();
}
// 辅助方法,填充文本数据到指定单元格
private static void fillText(XSSFSheet sheet, String cellRef, String text) {
XSSFCell cell = sheet.getRow(CellReference.getCellRef(cellRef).getRow()).getCell(CellReference.getCellRef(cellRef).getCol());
cell.setCellValue(text);
}
}
在上述代码中,我们首先从模板文件创建一个XSSFWorkbook对象,然后获取要填充的工作表。接下来,我们使用fillText()方法填充文本数据,并使用POI API将图片插入到单元格中。最后,我们合并单元格并设置单元格样式,然后将工作簿保存到输出文件。
使用FreeMarker和POI API混合解决方案
您可以使用FreeMarker和POI API结合处理Excel模板。以下是一个示例代码,演示如何使用FreeMarker和POI API来处理您的Excel模板:
import java.io.*;
import java.util.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import freemarker.template.*;
public class ExcelTemplate {
public static void main(String[] args) throws Exception {
String templatePath = "template.xlsx"; // 模板文件路径
String outputPath = "output.xlsx"; // 输出文件路径
// 从模板文件创建工作簿对象
FileInputStream input = new FileInputStream(new File(templatePath));
XSSFWorkbook workbook = new XSSFWorkbook(input.close();
// 获取第一个工作表
XSSFSheet sheet = workbook.getSheetAt(0);
// 使用FreeMarker填充文本数据
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("name", "John Doe");
dataModel.put("address", "123 Main St.");
dataModel.put("email", "jdoe@example.com");
String textTemplate = "${name}\n${address}\n${email}";
Template template = new Template("textTemplate", new StringReader(textTemplate), new Configuration());
StringWriter writer = new StringWriter();
template.process(dataModel, writer);
fillText(sheet, "A2", writer.toString());
// 使用POI API插入图片
InputStream imageStream = new FileInputStream(new File("image.jpg"));
byte[] imageData = IOUtils.toByteArray(imageStream);
int pictureIndex = workbook.addPicture(imageData, Workbook.PICTURE_TYPE_JPEG);
imageStream.close();
CreationHelper helper = workbook.getCreationHelper();
Drawing<?> drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = helper.createClientAnchor();
anchor.setCol1(CellReference.convertColStringToIndex("D"));
anchor.setRow1(1);
Picture picture = drawing.createPicture(anchor, pictureIndex);
picture.resize();
// 使用FreeMarker合并单元格并设置样式
String styleTemplate = "<#assign style = workbook.createCellStyle()>" +
"<#assign borderStyle = style.BORDER_THIN>" +
"<#assign borderColor = style.BLACK>" +
"<#assign style.borderTop = borderStyle>" +
"<#assign style.borderRight = borderStyle>" +
"<#assign style.borderBottom = borderStyle>" +
"<#assign style.borderLeft = borderStyle>" +
"<#assign style.topBorderColor = borderColor>" +
"<#assign style.rightBorderColor = borderColor>" +
"<#assign style.bottomBorderColor = borderColor>" +
"<#assign style.leftBorderColor = borderColor>" +
"<#assign style.alignment = style.ALIGN_CENTER>" +
"<#assign style.verticalAlignment = style.VERTICAL_CENTER>" +
"<#assign font = workbook.createFont()>" +
"<#assign font.fontName = 'Arial'>" +
"<#assign font.fontHeightInPoints = 12>" +
"<#assign font.bold = true>" +
"<#assign style.setFont(font)>" +
"<#assign sheet.addMergedRegion(workbook.getCreationHelper().createCellRangeAddress(3,3,0,3))>" +
"<#assign cell = sheet.getRow(3).getCell(0)>" +
"<#assign cell.setCellValue('This is a merged cell')>" +
"<#assign cell.setCellStyle(style)>";
Template styleTemplate = new Template("styleTemplate", new StringReader(styleTemplate), new Configuration());
writer = new StringWriter();
styleTemplate.process(Collections.singletonMap("workbook", workbook), writer);
// 保存工作簿到输出文件
FileOutputStream output = new FileOutputStream(new File(outputPath));
workbook.write(output);
output.close();
}
// 辅助方法,填充文本数据到指定单元格
private static void fillText(XSSFSheet sheet, String cellRef, String text) {
XSSFCell cell = sheet.getRow(CellReference.getCellRef(cellRef).getRow()).getCell(CellReference.getCellRef(cellRef).getCol());
cell.setCellValue(text);
}
}
在上述代码中,我们仍然从模板文件创建一个XSSFWorkbook
对象,并获取要填充的工作表。然后,我们使用FreeMarker填充文本数据,并使用POI API插入图片。接下来,我们使用FreeMarker生成单元格样式,并将其应用于工作表。最后,我们将工作簿保存到输出文件。
需要注意的是,在使用FreeMarker时,您需要将workbook
对象添加到数据模型中,以便在模板中访问它。
java
// 读取Excel模板
Workbook workbook = WorkbookFactory.create(new File("template.xlsx"));
Sheet sheet = workbook.getSheetAt(0);
// 获取模板中的样式和格式
CellStyle cellStyle = sheet.getRow(0).getCell(0).getCellStyle();
Font font = workbook.getFontAt(cellStyle.getFontIndex());
// 使用freemarker填充数据
Configuration cfg = new Configuration(Configuration.VERSION_2_3_30);
cfg.setDefaultEncoding("UTF-8");
cfg.setClassForTemplateLoading(this.getClass(), "/templates");
Template template = cfg.getTemplate("template.ftl");
Map data = new HashMap<>();
data.put("name", "张三");
data.put("age", 20);
data.put("image", new File("image.jpg"));
Writer out = new FileWriter(new File("output.xlsx"));
template.process(data, out);
out.close();
// 将图片插入到Excel文档中
Drawing drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, 1, 2, 4);
Picture picture = drawing.createPicture(anchor, workbook.addPicture(IOUtils.toByteArray(new FileInputStream(new File("image.jpg"))), Workbook.PICTURE_TYPE_JPEG)));
picture.resize(1.0, 1.0);
可以借鉴下
http://www.studyofnet.com/717110295.html
https://blog.csdn.net/leesinbad/category_12207471.html
这里有三篇excel的文章,希望对你有用
使用Freemarker + POI来将数据填充到Excel中,有时确实会出现样式改变的情况,这可能是因为POI处理Excel的方式与Excel本身的处理方式不同,导致部分样式无法被完全还原。通常来说,我们可以尝试以下解决办法:
检查Excel模板中是否存在合并单元格、复杂的边框或者其他特殊样式。如果是这些元素导致的样式变化,可以考虑调整模板中的样式,使得最终生成的Excel与原始样式更加接近。
将POI处理生成的Excel和原始Excel进行比对,查看哪些样式出现了变化,并尝试找到合适的方法进行修复。
对于一些复杂的样式或者需要复杂数据处理逻辑的Excel,可以考虑尝试使用专业的Excel处理库,如Aspose.Cells,其能够更好地处理复杂的样式和数据结构。
如果您不是特别注重样式的还原,可以尝试不使用Excel模板,直接使用POI将数据填充到新建的Excel中,这样就避免了 Excel 模板转换、样式还原等问题。
该回答引用于GPT与OKX小二共同编写:
如果使用 POI 实现动态填充 Excel 模板,最好的方法是:
将 Excel 模板分成三个部分:表头、主体和表尾。
使用 POI 的接口按照以下顺序逐步填充数据内容:
需要注意的是,如果直接使用 POI 接口添加图片到单元格中,可能会导致样式问题,因为样式也受到一些限制。为了避免这些问题,可以在模板中预留图片的位置,并在填充数据时使用 Freemarker 模板引擎生成图片的 HTML 代码,在 POI 中使用该 HTML 代码创建单元格。这样可以确保图片与其他内容的样式保持一致,即使内容超出单元格大小,也可以通过设置单元格的样式来调整。
另外,需要注意的是,如果要使用 POI 处理合并单元格、单元格样式等复杂表格操作,需要严格按照 POI API 的规范进行操作,确保数据的正确性和稳定性。可以参考官方文档来使用 POI 接口。
chatGTP:根据您提供的需求模板图,您需要在Excel中动态填充文本和图片,并且保留模板的样式。下面是我建议的解决方案:
使用POI来读取模板Excel文件,并将其转换成一个可编辑的工作簿对象。
使用FreeMarker来生成一个数据模型,该数据模型包含需要在Excel中填充的文本和图片数据。
使用POI和FreeMarker来填充Excel单元格中的文本和图片数据。对于文本,可以使用POI的接口将文本内容填充到单元格中。对于图片,可以使用POI的接口将图片插入到单元格中,并根据需要调整单元格的大小和位置。
最后,将编辑后的工作簿对象写入新的Excel文件中,并返回给前端。
下面是一个简单的示例代码,演示了如何使用POI和FreeMarker来动态填充Excel模板:
import java.io.*;
import java.util.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import freemarker.template.*;
public class ExcelGenerator {
public static void main(String[] args) {
try {
// 读取Excel模板文件
InputStream inputStream = new FileInputStream("template.xlsx");
Workbook workbook = new XSSFWorkbook(inputStream);
Sheet sheet = workbook.getSheetAt(0);
// 准备数据模型
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("title", "动态生成Excel");
dataModel.put("subtitle", "使用POI和FreeMarker");
dataModel.put("date", new Date());
dataModel.put("image1", new FileInputStream("image1.jpg"));
dataModel.put("image2", new FileInputStream("image2.jpg"));
// 准备FreeMarker配置
Configuration freemarkerCfg = new Configuration(Configuration.VERSION_2_3_30);
freemarkerCfg.setClassForTemplateLoading(ExcelGenerator.class, "/");
freemarkerCfg.setDefaultEncoding("UTF-8");
// 获取FreeMarker模板
Template template = freemarkerCfg.getTemplate("template.ftl");
// 使用FreeMarker填充Excel单元格
StringWriter stringWriter = new StringWriter();
template.process(dataModel, stringWriter);
String outputText = stringWriter.toString();
System.out.println(outputText); // 调试用,可以查看生成的XML内容
// 将生成的XML内容写入Excel单元格
sheet.createRow(2).createCell(0).setCellValue(outputText);
// 插入图片
Row row = sheet.createRow(4);
byte[] imageBytes1 = IOUtils.toByteArray(new FileInputStream("image1.jpg"));
byte[] imageBytes2 = IOUtils.toByteArray(new FileInputStream("image2.jpg"));
int pictureIdx1 = workbook.addPicture(imageBytes1, Workbook.PICTURE_TYPE_JPEG);
int pictureIdx2 = workbook.addPicture(imageBytes2, Workbook.PICTURE_TYPE_JPEG);
Drawing drawing = row.createCell(0).getSheet().createDrawingPatriarch();
ClientAnchor anchor1 = drawing.createAnchor(0, 0, 0, 0, 0, 4, 5, 7);
ClientAnchor anchor2 = drawing.createAnchor(0, 0, 0 , 0, 8, 9);
drawing.createPicture(anchor1, pictureIdx1);
drawing.createPicture(anchor2, pictureIdx2);
// 将编辑后的工作簿对象写入新的Excel文件中
FileOutputStream fileOut = new FileOutputStream("output.xlsx");
workbook.write(fileOut);
fileOut.close();
// 清理资源
workbook.close();
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
上述代码中,我们首先使用POI来读取Excel模板文件,并获取工作簿和工作表对象。接下来,我们使用FreeMarker生成一个数据模型,包含需要在Excel中填充的文本和图片数据。然后,我们使用FreeMarker填充Excel单元格,并将生成的XML内容写入工作表中。最后,我们使用POI插入图片,并将编辑后的工作簿对象写入新的Excel文件中。
需要注意的是,在插入图片时,我们使用了POI的Drawing
对象来创建图片锚点,然后将锚点与图片一起插入到单元格中。锚点的位置可以使用ClientAnchor
对象进行调整。
希望这个示例代码能够帮助你解决Excel模板填充中的问题。如果您有任何疑问,请随时在这里提出。