本教程将详细介绍如何使用Java从数据库查询图书数据,并生成格式化的Word统计报告。我们将使用Spring Boot框架和Apache POI库来实现这一功能。
一、项目结构
bash
src/main/java
├── com/example/libraryreport
│ ├── controller
│ │ └── ReportController.java
│ ├── service
│ │ └── BookReportService.java
│ ├── mapper
│ │ └── BookReportMapper.java
│ └── LibraryReportApplication.java
二、核心代码实现
1. 控制器层
java
@RestController
@RequestMapping("/api/reports")
public class ReportController {
@Autowired
private BookReportService bookReportService;
@GetMapping("/books")
public ResponseEntity<String> generateBookReport() {
try {
String fileName = "图书统计报告_" + System.currentTimeMillis() + ".docx";
String outputPath = "reports/" + fileName;
bookReportService.generateReport(outputPath);
return ResponseEntity.ok("报告生成成功: " + outputPath);
} catch (Exception e) {
return ResponseEntity.status(500)
.body("报告生成失败: " + e.getMessage());
}
}
}
2. 数据访问层接口
java
public interface BookReportMapper {
// 获取图书总量
int selectTotalBookCount();
// 按分类统计图书数量
List<Map<String, Object>> selectBooksByCategory();
// 获取热门图书TOP10
List<Map<String, Object>> selectPopularBooks();
// 获取借阅统计
List<Map<String, Object>> selectBorrowStats();
}
3. 服务层实现
java
@Service
public class BookReportService {
@Autowired
private BookReportMapper bookReportMapper;
public void generateReport(String outputPath) throws Exception {
// 创建Word文档
XWPFDocument document = new XWPFDocument();
try {
// 添加报告标题
addTitle(document, "图书馆图书统计报告");
// 添加生成日期
addGenerationDate(document);
// 添加图书总量统计
addTotalBookCount(document);
// 添加分类统计表格
addCategoryStatistics(document);
// 添加热门图书列表
addPopularBooks(document);
// 添加借阅统计
addBorrowStatistics(document);
// 保存文档
saveDocument(document, outputPath);
} finally {
document.close();
}
}
// 创建报告主标题,设置居中、加粗和大号字体
private void addTitle(XWPFDocument document, String titleText) {
XWPFParagraph title = document.createParagraph();
title.setAlignment(ParagraphAlignment.CENTER);
XWPFRun titleRun = title.createRun();
titleRun.setText(titleText);
titleRun.setBold(true);
titleRun.setFontSize(20);
titleRun.setFontFamily("宋体");
// 添加空行
document.createParagraph();
}
// 在右上角添加报告生成日期
private void addGenerationDate(XWPFDocument document) {
XWPFParagraph datePara = document.createParagraph();
datePara.setAlignment(ParagraphAlignment.RIGHT);
XWPFRun dateRun = datePara.createRun();
dateRun.setText("生成日期: " + LocalDate.now().toString());
dateRun.setFontSize(12);
dateRun.setFontFamily("宋体");
// 添加空行
document.createParagraph();
}
// 显示图书馆藏书总量
private void addTotalBookCount(XWPFDocument document) {
int totalCount = bookReportMapper.selectTotalBookCount();
XWPFParagraph sectionTitle = createSectionTitle(document, "一、图书总量统计");
XWPFParagraph content = document.createParagraph();
XWPFRun run = content.createRun();
run.setText(String.format("图书馆目前共有藏书: %s册", formatNumber(totalCount)));
run.setFontSize(14);
run.setFontFamily("宋体");
// 添加空行
document.createParagraph();
}
// 创建分类统计表格,包括序号、分类名称、数量和占比
private void addCategoryStatistics(XWPFDocument document) throws Exception {
// 创建章节标题
XWPFParagraph sectionTitle = createSectionTitle(document, "二、图书分类统计");
// 获取分类数据
List<Map<String, Object>> categories = bookReportMapper.selectBooksByCategory();
int total = bookReportMapper.selectTotalBookCount();
// 创建表格
XWPFTable table = document.createTable(1, 4);
table.setWidth("100%");
// 设置表头
setTableHeader(table, "序号", "图书分类", "数量", "占比");
// 填充数据
int index = 1;
for (Map<String, Object> category : categories) {
XWPFTableRow row = table.createRow();
row.getCell(0).setText(String.valueOf(index++));
row.getCell(1).setText(category.get("categoryName").toString());
int count = Integer.parseInt(category.get("count").toString());
row.getCell(2).setText(formatNumber(count));
double percent = (count * 100.0) / total;
row.getCell(3).setText(String.format("%.1f%%", percent));
}
// 添加汇总行
XWPFTableRow footer = table.createRow();
footer.getCell(1).setText("总计");
footer.getCell(2).setText(formatNumber(total));
footer.getCell(3).setText("100%");
// 添加空行
document.createParagraph();
}
// 列出热门图书TOP10,前三名用蓝色加粗显示
private void addPopularBooks(XWPFDocument document) {
// 创建章节标题
XWPFParagraph sectionTitle = createSectionTitle(document, "三、热门图书TOP10");
List<Map<String, Object>> popularBooks = bookReportMapper.selectPopularBooks();
for (int i = 0; i < popularBooks.size(); i++) {
Map<String, Object> book = popularBooks.get(i);
XWPFParagraph item = document.createParagraph();
item.setIndentationLeft(200);
XWPFRun run = item.createRun();
run.setText(String.format("%d. 《%s》 - %s (借阅量: %s次)",
i + 1,
book.get("title"),
book.get("author"),
formatNumber(Long.parseLong(book.get("borrowCount").toString()))
);
run.setFontSize(12);
run.setFontFamily("宋体");
// 突出显示前三名
if (i < 3) {
run.setBold(true);
run.setColor("0000FF");
}
}
// 添加空行
document.createParagraph();
}
// 创建借阅统计表格,显示每月借阅量和同比增长率
private void addBorrowStatistics(XWPFDocument document) {
// 创建章节标题
XWPFParagraph sectionTitle = createSectionTitle(document, "四、借阅统计");
List<Map<String, Object>> borrowStats = bookReportMapper.selectBorrowStats();
// 创建表格
XWPFTable table = document.createTable(1, 3);
table.setWidth("100%");
// 设置表头
setTableHeader(table, "月份", "借阅量", "同比增长");
// 填充数据
for (Map<String, Object> stat : borrowStats) {
XWPFTableRow row = table.createRow();
row.getCell(0).setText(stat.get("month").toString());
row.getCell(1).setText(formatNumber(Long.parseLong(stat.get("count").toString())));
// 计算同比增长
if (stat.containsKey("growthRate")) {
double growth = Double.parseDouble(stat.get("growthRate").toString());
row.getCell(2).setText(String.format("%.1f%%", growth * 100));
// 设置颜色:增长为红色,下降为绿色
XWPFRun growthRun = row.getCell(2).getParagraphs().get(0).getRuns().get(0);
if (growth > 0) {
growthRun.setColor("FF0000");
} else if (growth < 0) {
growthRun.setColor("00FF00");
}
} else {
row.getCell(2).setText("N/A");
}
}
}
// 辅助方法,创建统一的章节标题格式
private XWPFParagraph createSectionTitle(XWPFDocument document, String title) {
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run = paragraph.createRun();
run.setText(title);
run.setBold(true);
run.setFontSize(16);
run.setFontFamily("宋体");
return paragraph;
}
// 辅助方法,设置表格表头样式
private void setTableHeader(XWPFTable table, String... headers) {
XWPFTableRow headerRow = table.getRow(0);
for (int i = 0; i < headers.length; i++) {
XWPFRun run = headerRow.getCell(i).getParagraphs().get(0).createRun();
run.setText(headers[i]);
run.setBold(true);
run.setFontSize(12);
run.setFontFamily("宋体");
// 设置单元格背景色
headerRow.getCell(i).setColor("D3D3D3");
}
}
// 格式化数字显示,添加千位分隔符
private String formatNumber(long number) {
return String.format("%,d", number);
}
// 保存Word文档到指定路径
private void saveDocument(XWPFDocument document, String outputPath) throws IOException {
// 确保目录存在
File outputFile = new File(outputPath);
outputFile.getParentFile().mkdirs();
try (FileOutputStream out = new FileOutputStream(outputFile)) {
document.write(out);
}
}
}
四、运行效果
文档样式细节
-
字体规范:
- 中文默认使用"宋体",数字/英文自动匹配
- 标题层级分明(20号→16号→14号→12号)
-
数字处理:
- 所有数量自动添加千位分隔符(如
1,200
) - 百分比保留1位小数(如
28.4%
)
- 所有数量自动添加千位分隔符(如
-
颜色标记:
- 蓝色:TOP3热门图书
- 红色/绿色:借阅量增长/下降
- 灰色:表格标题背景
-
布局设计:
- 章节间有适当空行
- 表格宽度占满页面(100%)
- 列表项统一缩进
-
数据完整性:
- 包含总量统计、分类占比、排行榜和趋势分析
- 自动计算百分比和增长率
lua
+------------------------------------------+
| 图书馆图书统计报告 |
| (大标题) |
| |
| 生成日期:2023-05-20 (右上角小字) |
| |
| 一、图书总量统计 |
| 图书馆目前共有藏书:12,345册 |
| |
| 二、图书分类统计 |
| +----+------------+-------+-------+ |
| |序号| 图书分类 | 数量 | 占比 | |
| +----+------------+-------+-------+ |
| |1 |计算机科学 | 3,500 | 28.4% | |
| |2 |文学 | 2,800 | 22.7% | |
| ... |
| | |总计 |12,345 | 100% | |
| +----+------------+-------+-------+ |
| |
| 三、热门图书TOP10 |
| 1. 《Java编程思想》...(蓝色加粗) |
| 2. 《三体》...(蓝色加粗) |
| ... |
| |
| 四、借阅统计 |
| +------------+--------+----------+ |
| | 月份 | 借阅量 | 同比增长 | |
| +------------+--------+----------+ |
| | 2023-01 | 1,200 | +15.2%↑ | |
| | 2023-02 | 980 | -8.3%↓ | |
| ... |
+-----------------------------------------+
五、总结
通过本教程,我们实现了:
- 使用Spring Boot构建Web服务
- 通过MyBatis访问数据库获取统计信息
- 使用Apache POI生成格式化的Word文档
- 实现表格、列表等复杂格式的输出
这个方案可以轻松扩展为其他类型的统计报告生成工具,只需修改SQL查询和Word格式设置即可。