Java利用POI+JFreeChart 实现excel导出数据和图标(折线统计图)
依赖:
`
org.apache.poi
poi
5.2.3
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</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>5.1.1</version>
</dependency>
<!-- JFreeChart for Chart -->
<dependency>
<groupId>org.jfree</groupId>
<artifactId>jfreechart</artifactId>
<version>1.5.3</version>
</dependency>`
2.代码 注意:JFreeChart 不支持中文,需要字体转换
@Test
public void test() throws Exception {
// 查询每个月的用量
Map<String, Double> monthlyUsage = new LinkedHashMap<>();
//初始化monthlyUsage
monthlyUsage.put("6月-1周", 148.00);
monthlyUsage.put("6月-2周", 196.00);
monthlyUsage.put("6月-3周", 223.00);
monthlyUsage.put("6月-4周", 227.00 );
monthlyUsage.put("7月-1周", 207.00);
monthlyUsage.put("7月-2周", 201.00);
monthlyUsage.put("7月-3周", 213.00);
monthlyUsage.put("7月-4周", 139.00);
monthlyUsage.put("8月-1周", 213.00 );
monthlyUsage.put("8月-2周", 185.00 );
//
Map<String, Double> monthlyUsage2 = new LinkedHashMap<>();
//初始化monthlyUsage
monthlyUsage2.put("6月-1周", 248.00);
monthlyUsage2.put("6月-2周", 296.00);
monthlyUsage2.put("6月-3周", 323.00);
monthlyUsage2.put("6月-4周", 327.00);
monthlyUsage2.put("7月-1周", 307.00);
monthlyUsage2.put("7月-2周", 301.00);
monthlyUsage2.put("7月-3周", 313.00);
monthlyUsage2.put("7月-4周", 239.00);
monthlyUsage2.put("8月-1周", 313.00 );
monthlyUsage2.put("8月-2周", 285.00 );
Map<String, Double> monthlyUsage3 = new LinkedHashMap<>();
//初始化monthlyUsage
monthlyUsage3.put("6月-1周", 396.00);
monthlyUsage3.put("6月-2周", 492.00);
monthlyUsage3.put("6月-3周", 546.00);
monthlyUsage3.put("6月-4周", 554.00);
monthlyUsage3.put("7月-1周", 514.00);
monthlyUsage3.put("7月-2周", 502.00);
monthlyUsage3.put("7月-3周", 526.00);
monthlyUsage3.put("7月-4周", 378.00);
monthlyUsage3.put("8月-1周", 526.00 );
monthlyUsage3.put("8月-2周", 470.00 );
DefaultCategoryDataset dataset2 = new DefaultCategoryDataset();
for (Map.Entry<String, Double> entry : monthlyUsage3.entrySet()) {
dataset2.addValue(entry.getValue(), "总量", entry.getKey());
}
// 创建折线图数据集
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
for (Map.Entry<String, Double> entry : monthlyUsage.entrySet()) {
dataset.addValue(entry.getValue(), "FER", entry.getKey());
}
for (Map.Entry<String, Double> entry : monthlyUsage2.entrySet()) {
dataset.addValue(entry.getValue(), "POCT", entry.getKey());
}
// 创建折线图
JFreeChart chart = ChartFactory.createLineChart(
"湖北妇幼保健院用量统计表", // 图表标题
"时间", // X轴标签
"用量", // Y轴标签
dataset, // 数据集
PlotOrientation.VERTICAL, // 图表方向
true, // 是否显示图例
true, // 是否显示工具提示
false // 是否显示URL
);
// 创建折线图
JFreeChart chart2 = ChartFactory.createLineChart(
"湖北妇幼保健院总用量统计表", // 图表标题
"时间", // X轴标签
"用量", // Y轴标签
dataset2, // 数据集
PlotOrientation.VERTICAL, // 图表方向
true, // 是否显示图例
true, // 是否显示工具提示
false // 是否显示URL
);
// **正确设置字体**
Font titleFont = new Font("宋体", Font.BOLD, 20); // 不能直接实例化 Font,必须使用构造方法
Font labelFont = new Font("宋体", Font.BOLD, 14 );
chart.getTitle().setFont(titleFont);
chart.getLegend().setItemFont(labelFont);
chart2.getTitle().setFont(titleFont);
chart2.getLegend().setItemFont(labelFont);
// 获取图表的 Plot(绘图区域)
CategoryPlot plot = (CategoryPlot) chart.getPlot();
CategoryPlot plot2 = (CategoryPlot) chart2.getPlot();
// 设置 X 轴字体
CategoryAxis domainAxis = plot.getDomainAxis();
CategoryAxis domainAxis2 = plot2.getDomainAxis();
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_90); // 90度竖排
domainAxis.setLabelFont(labelFont); // X 轴标签字体
domainAxis.setTickLabelFont(labelFont); // X 轴刻度字体
domainAxis2.setCategoryLabelPositions(CategoryLabelPositions.UP_90); // 90度竖排
domainAxis2.setLabelFont(labelFont); // X 轴标签字体
domainAxis2.setTickLabelFont(labelFont); // X 轴刻度字体
// 设置 Y 轴字体
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
NumberAxis rangeAxis2 = (NumberAxis) plot2.getRangeAxis();
rangeAxis.setLabelFont(labelFont); // Y 轴标签字体
rangeAxis.setTickLabelFont(labelFont); // Y 轴刻度字体
rangeAxis.setTickUnit(new NumberTickUnit(50));
chart.setBackgroundPaint(Color.WHITE); // 设置整个图表的背景颜色
plot.setBackgroundPaint(new Color(255, 255, 255)); // 绘图区背景色(淡紫色)
plot.setDomainGridlinePaint(Color.GRAY); // X 轴网格线颜色
plot.setRangeGridlinePaint(Color.GRAY); // Y 轴网格线颜色
rangeAxis2.setLabelFont(labelFont); // Y 轴标签字体
rangeAxis2.setTickLabelFont(labelFont); // Y 轴刻度字体
rangeAxis2.setTickUnit(new NumberTickUnit(50));
chart2.setBackgroundPaint(Color.WHITE); // 设置整个图表的背景颜色
plot2.setBackgroundPaint(new Color(255, 255, 255)); // 绘图区背景色(淡紫色)
plot2.setDomainGridlinePaint(Color.GRAY); // X 轴网格线颜色
plot2.setRangeGridlinePaint(Color.GRAY); // Y 轴网格线颜色
// 获取图表渲染器
LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
renderer.setSeriesPaint(0, Color.BLUE); // 修改折线颜色(红色)
renderer.setSeriesStroke(0, new BasicStroke(3.0f)); // 线条加粗
renderer.setSeriesPaint(1, Color.RED); // 第二条线 (HbA1c)
renderer.setSeriesStroke(1, new BasicStroke(3.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL, 0, new float[]{10, 5}, 0)); // 红色虚线
// 设置数据标签
renderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator());
renderer.setDefaultItemLabelsVisible(true);
// 获取图表渲染器
LineAndShapeRenderer renderer2 = (LineAndShapeRenderer) plot2.getRenderer();
renderer2.setSeriesPaint(0, Color.PINK); // 修改折线颜色(红色)
renderer2.setSeriesStroke(0, new BasicStroke(3.0f)); // 线条加粗
// 设置数据标签
renderer2.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator());
renderer2.setDefaultItemLabelsVisible(true);
// 设置数据标签的位置
ItemLabelPosition position = new ItemLabelPosition(
ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER
);
renderer.setDefaultPositiveItemLabelPosition(position);
// 设置数据标签的位置
ItemLabelPosition position2 = new ItemLabelPosition(
ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER
);
renderer2.setDefaultPositiveItemLabelPosition(position2);
// 将图表保存为图片
byte[] chartImageBytes = null;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
ChartUtils.writeChartAsPNG(baos, chart, 800, 600);
chartImageBytes = baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
// 将图表保存为图片
byte[] chartImageBytes2 = null;
try (ByteArrayOutputStream baos2 = new ByteArrayOutputStream()) {
ChartUtils.writeChartAsPNG(baos2, chart2, 800, 600);
chartImageBytes2 = baos2.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
// 将数据写入Excel并插入图表
try (Workbook workbook = new XSSFWorkbook()) {
Sheet sheet = workbook.createSheet("湖北妇幼保健院用量统计表");
CellStyle headerStyle = workbook.createCellStyle();
headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); // 设置前景色为黑色
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); // 填充模式
// 创建表头
Row titleRow = sheet.createRow(0);
Cell titleCell = titleRow.createCell(0);
titleCell.setCellValue("湖北妇幼保健院");
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 3));
CellStyle titleStyle = workbook.createCellStyle();
titleStyle.setAlignment(HorizontalAlignment.CENTER);
titleCell.setCellStyle(titleStyle);
Row headerRow = sheet.createRow(1);
headerRow.createCell(0).setCellStyle(headerStyle);
headerRow.getCell(0).setCellValue("时间");
headerRow.createCell(1).setCellStyle(headerStyle);
headerRow.getCell(1).setCellValue("项目");
headerRow.createCell(2).setCellStyle(headerStyle);
headerRow.getCell(2).setCellValue("类型");
headerRow.createCell(3).setCellStyle(headerStyle);
headerRow.getCell(3).setCellValue("用量");
// 填充数据
int rowNum = 2;
for (Map.Entry<String, Double> entry : monthlyUsage.entrySet()) {
Row row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(entry.getKey());
row.createCell(1).setCellValue("FER");
row.createCell(2).setCellValue("样本");
row.createCell(3).setCellValue(entry.getValue());
}
int rowNum2 = 40;
for (Map.Entry<String, Double> entry : monthlyUsage2.entrySet()) {
Row row = sheet.createRow(rowNum2++);
row.createCell(0).setCellValue(entry.getKey());
row.createCell(1).setCellValue("POCT");
row.createCell(2).setCellValue("样本");
row.createCell(3).setCellValue(entry.getValue());
}
int rowNum3 = 80;
for (Map.Entry<String, Double> entry : monthlyUsage3.entrySet()) {
Row row = sheet.createRow(rowNum3++);
row.createCell(0).setCellValue(entry.getKey());
row.createCell(1).setCellValue("总计");
row.createCell(2).setCellValue("样本");
row.createCell(3).setCellValue(entry.getValue());
}
XSSFDrawing drawing = (XSSFDrawing) sheet.createDrawingPatriarch();
// 插入图表到Excel
if (chartImageBytes != null) {
int pictureIdx = workbook.addPicture(chartImageBytes, Workbook.PICTURE_TYPE_PNG);
XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, 5, 0, 12, 26 );
drawing.createPicture(anchor, pictureIdx);
}
// 插入图表到Excel
if (chartImageBytes2 != null) {
int pictureIdx = workbook.addPicture(chartImageBytes2, Workbook.PICTURE_TYPE_PNG);
XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, 12, 0, 19, 26 );
drawing.createPicture(anchor, pictureIdx);
}
// 写入Excel文件
try (FileOutputStream fileOut = new FileOutputStream("E:/湖北妇幼保健院用量统计表.xlsx")) {
workbook.write(fileOut);
}
} catch (Exception e) {
e.printStackTrace();
}
}