本文目录导读:

我来为您提供一个完整的Java报表系统案例,使用Spring Boot + MyBatis + Apache POI/JasperReports实现。
项目结构
src/main/java/com/example/report/
├── controller/
│ └── ReportController.java
├── service/
│ ├── ReportService.java
│ └── impl/
│ └── ReportServiceImpl.java
├── mapper/
│ ├── OrderMapper.java
│ └── UserMapper.java
├── entity/
│ ├── Order.java
│ └── User.java
├── utils/
│ └── ExcelExportUtil.java
└── ReportApplication.java
src/main/resources/
├── mapper/
│ ├── OrderMapper.xml
│ └── UserMapper.xml
└── templates/
└── report.jrxml
核心代码实现
实体类
// Order.java
package com.example.report.entity;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class Order {
private Long id;
private String orderNo;
private String customerName;
private BigDecimal amount;
private Integer status;
private Date createTime;
private String statusDesc;
}
// User.java
package com.example.report.entity;
import lombok.Data;
import java.util.Date;
@Data
public class User {
private Long id;
private String username;
private String email;
private String phone;
private Date createTime;
private Integer userStatus;
}
Mapper接口
// OrderMapper.java
package com.example.report.mapper;
import com.example.report.entity.Order;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
@Mapper
public interface OrderMapper {
List<Order> getOrderReport(@Param("startDate") String startDate,
@Param("endDate") String endDate,
@Param("status") Integer status);
List<Map<String, Object>> getOrderStatistics(@Param("startDate") String startDate,
@Param("endDate") String endDate);
}
// UserMapper.java
package com.example.report.mapper;
import com.example.report.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface UserMapper {
List<User> getUserReport(@Param("startDate") String startDate,
@Param("endDate") String endDate);
}
Mapper XML
<!-- OrderMapper.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.report.mapper.OrderMapper">
<select id="getOrderReport" resultType="com.example.report.entity.Order">
SELECT
o.id,
o.order_no AS orderNo,
o.customer_name AS customerName,
o.amount,
o.status,
o.create_time AS createTime,
CASE o.status
WHEN 1 THEN '待付款'
WHEN 2 THEN '已付款'
WHEN 3 THEN '已完成'
WHEN 4 THEN '已取消'
ELSE '未知状态'
END AS statusDesc
FROM orders o
<where>
<if test="startDate != null and startDate != ''">
AND o.create_time >= #{startDate}
</if>
<if test="endDate != null and endDate != ''">
AND o.create_time <= #{endDate}
</if>
<if test="status != null">
AND o.status = #{status}
</if>
</where>
ORDER BY o.create_time DESC
</select>
<select id="getOrderStatistics" resultType="java.util.Map">
SELECT
DATE(create_time) AS date,
COUNT(*) AS orderCount,
COALESCE(SUM(amount), 0) AS totalAmount,
AVG(amount) AS avgAmount
FROM orders
<where>
<if test="startDate != null and startDate != ''">
AND create_time >= #{startDate}
</if>
<if test="endDate != null and endDate != ''">
AND create_time <= #{endDate}
</if>
</where>
GROUP BY DATE(create_time)
ORDER BY date DESC
</select>
</mapper>
<!-- UserMapper.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.report.mapper.UserMapper">
<select id="getUserReport" resultType="com.example.report.entity.User">
SELECT
u.id,
u.username,
u.email,
u.phone,
u.create_time AS createTime,
u.user_status AS userStatus
FROM users u
<where>
<if test="startDate != null and startDate != ''">
AND u.create_time >= #{startDate}
</if>
<if test="endDate != null and endDate != ''">
AND u.create_time <= #{endDate}
</if>
</where>
ORDER BY u.create_time DESC
</select>
</mapper>
Service层
// ReportService.java
package com.example.report.service;
import com.example.report.entity.Order;
import com.example.report.entity.User;
import java.util.List;
import java.util.Map;
public interface ReportService {
List<Order> getOrderReport(String startDate, String endDate, Integer status);
List<User> getUserReport(String startDate, String endDate);
List<Map<String, Object>> getOrderStatistics(String startDate, String endDate);
byte[] exportOrderReportExcel(String startDate, String endDate, Integer status);
byte[] exportUserReportExcel(String startDate, String endDate);
byte[] exportOrderReportPDF(String startDate, String endDate, Integer status);
}
// ReportServiceImpl.java
package com.example.report.service.impl;
import com.example.report.entity.Order;
import com.example.report.entity.User;
import com.example.report.mapper.OrderMapper;
import com.example.report.mapper.UserMapper;
import com.example.report.service.ReportService;
import com.example.report.utils.ExcelExportUtil;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class ReportServiceImpl implements ReportService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private UserMapper userMapper;
@Override
public List<Order> getOrderReport(String startDate, String endDate, Integer status) {
return orderMapper.getOrderReport(startDate, endDate, status);
}
@Override
public List<User> getUserReport(String startDate, String endDate) {
return userMapper.getUserReport(startDate, endDate);
}
@Override
public List<Map<String, Object>> getOrderStatistics(String startDate, String endDate) {
return orderMapper.getOrderStatistics(startDate, endDate);
}
@Override
public byte[] exportOrderReportExcel(String startDate, String endDate, Integer status) {
List<Order> orders = getOrderReport(startDate, endDate, status);
String[] headers = {"订单编号", "客户名称", "订单金额", "订单状态", "创建时间"};
String[] fields = {"orderNo", "customerName", "amount", "statusDesc", "createTime"};
return ExcelExportUtil.exportToExcel(headers, fields, orders);
}
@Override
public byte[] exportUserReportExcel(String startDate, String endDate) {
List<User> users = getUserReport(startDate, endDate);
String[] headers = {"用户名", "邮箱", "手机号", "注册时间", "状态"};
String[] fields = {"username", "email", "phone", "createTime", "userStatus"};
return ExcelExportUtil.exportToExcel(headers, fields, users);
}
@Override
public byte[] exportOrderReportPDF(String startDate, String endDate, Integer status) {
try {
List<Order> orders = getOrderReport(startDate, endDate, status);
// 加载报表模板
File file = ResourceUtils.getFile("classpath:templates/report.jrxml");
JasperReport jasperReport = JasperCompileManager.compileReport(file.getAbsolutePath());
// 准备数据
JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(orders);
Map<String, Object> parameters = new HashMap<>();
parameters.put("startDate", startDate);
parameters.put("endDate", endDate);
// 填充数据
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
// 导出PDF
return JasperExportManager.exportReportToPdf(jasperPrint);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("导出PDF失败", e);
}
}
}
Excel导出工具类
// ExcelExportUtil.java
package com.example.report.utils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.ReflectionUtils;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
public class ExcelExportUtil {
public static <T> byte[] exportToExcel(String[] headers, String[] fields, List<T> dataList) {
try (Workbook workbook = new XSSFWorkbook();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
Sheet sheet = workbook.createSheet("报表数据");
// 创建表头样式
CellStyle headerStyle = workbook.createCellStyle();
Font headerFont = workbook.createFont();
headerFont.setBold(true);
headerFont.setColor(IndexedColors.WHITE.getIndex());
headerStyle.setFont(headerFont);
headerStyle.setFillForegroundColor(IndexedColors.BLUE.getIndex());
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
headerStyle.setAlignment(HorizontalAlignment.CENTER);
// 创建数据样式
CellStyle dataStyle = workbook.createCellStyle();
dataStyle.setAlignment(HorizontalAlignment.CENTER);
// 创建表头行
Row headerRow = sheet.createRow(0);
for (int i = 0; i < headers.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(headers[i]);
cell.setCellStyle(headerStyle);
sheet.autoSizeColumn(i);
}
// 填充数据
int rowNum = 1;
for (T data : dataList) {
Row row = sheet.createRow(rowNum++);
for (int col = 0; col < fields.length; col++) {
Cell cell = row.createCell(col);
Object value = getFieldValue(data, fields[col]);
if (value != null) {
if (value instanceof Date) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
cell.setCellValue(sdf.format(value));
} else {
cell.setCellValue(value.toString());
}
} else {
cell.setCellValue("");
}
cell.setCellStyle(dataStyle);
}
}
workbook.write(outputStream);
return outputStream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("导出Excel失败", e);
}
}
private static Object getFieldValue(Object data, String fieldName) {
try {
Field field = data.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(data);
} catch (NoSuchFieldException | IllegalAccessException e) {
return null;
}
}
}
Controller
// ReportController.java
package com.example.report.controller;
import com.example.report.entity.Order;
import com.example.report.entity.User;
import com.example.report.service.ReportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/report")
public class ReportController {
@Autowired
private ReportService reportService;
@GetMapping("/orders")
public ResponseEntity<ApiResponse<List<Order>>> getOrderReport(
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate,
@RequestParam(required = false) Integer status) {
List<Order> orders = reportService.getOrderReport(startDate, endDate, status);
return ResponseEntity.ok(ApiResponse.success(orders));
}
@GetMapping("/users")
public ResponseEntity<ApiResponse<List<User>>> getUserReport(
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate) {
List<User> users = reportService.getUserReport(startDate, endDate);
return ResponseEntity.ok(ApiResponse.success(users));
}
@GetMapping("/statistics")
public ResponseEntity<ApiResponse<List<Map<String, Object>>>> getOrderStatistics(
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate) {
List<Map<String, Object>> statistics = reportService.getOrderStatistics(startDate, endDate);
return ResponseEntity.ok(ApiResponse.success(statistics));
}
@GetMapping("/export/excel/orders")
public ResponseEntity<byte[]> exportOrderExcel(
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate,
@RequestParam(required = false) Integer status) {
byte[] data = reportService.exportOrderReportExcel(startDate, endDate, status);
String filename = "order_report_" + System.currentTimeMillis() + ".xlsx";
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=" + filename)
.contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
.body(data);
}
@GetMapping("/export/excel/users")
public ResponseEntity<byte[]> exportUserExcel(
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate) {
byte[] data = reportService.exportUserReportExcel(startDate, endDate);
String filename = "user_report_" + System.currentTimeMillis() + ".xlsx";
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=" + filename)
.contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"))
.body(data);
}
@GetMapping("/export/pdf/orders")
public ResponseEntity<byte[]> exportOrderPDF(
@RequestParam(required = false) String startDate,
@RequestParam(required = false) String endDate,
@RequestParam(required = false) Integer status) {
byte[] data = reportService.exportOrderReportPDF(startDate, endDate, status);
String filename = "order_report_" + System.currentTimeMillis() + ".pdf";
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=" + filename)
.contentType(MediaType.APPLICATION_PDF)
.body(data);
}
// 通用响应类
public static class ApiResponse<T> {
private int code;
private String message;
private T data;
public static <T> ApiResponse<T> success(T data) {
ApiResponse<T> response = new ApiResponse<>();
response.setCode(200);
response.setMessage("success");
response.setData(data);
return response;
}
// getter and setter...
public int getCode() { return code; }
public void setCode(int code) { this.code = code; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
public T getData() { return data; }
public void setData(T data) { this.data = data; }
}
}
主启动类
// ReportApplication.java
package com.example.report;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.report.mapper")
public class ReportApplication {
public static void main(String[] args) {
SpringApplication.run(ReportApplication.class, args);
}
}
数据库表结构
-- 订单表
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_no VARCHAR(50) NOT NULL UNIQUE,
customer_name VARCHAR(100) NOT NULL,
amount DECIMAL(10, 2) NOT NULL,
status TINYINT NOT NULL DEFAULT 1 COMMENT '1:待付款 2:已付款 3:已完成 4:已取消',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_create_time (create_time),
INDEX idx_status (status)
);
-- 用户表
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100),
phone VARCHAR(20),
user_status TINYINT DEFAULT 1 COMMENT '1:正常 0:禁用',
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_create_time (create_time)
);
配置文件
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/report_db?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: yourpassword
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.report.entity
configuration:
map-underscore-to-camel-case: true
server:
port: 8080
前端页面示例
<!-- report.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">报表系统</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<script>
// 获取订单报表
async function getOrderReport() {
const startDate = document.getElementById('startDate').value;
const endDate = document.getElementById('endDate').value;
const status = document.getElementById('status').value;
const params = new URLSearchParams();
if (startDate) params.append('startDate', startDate);
if (endDate) params.append('endDate', endDate);
if (status) params.append('status', status);
const response = await fetch(`/api/report/orders?${params}`);
const result = await response.json();
// 渲染表格
renderOrderTable(result.data);
}
// 导出Excel
function exportExcel() {
const startDate = document.getElementById('startDate').value;
const endDate = document.getElementById('endDate').value;
const status = document.getElementById('status').value;
let url = '/api/report/export/excel/orders?';
if (startDate) url += `startDate=${startDate}&`;
if (endDate) url += `endDate=${endDate}&`;
if (status) url += `status=${status}`;
window.open(url, '_blank');
}
// 导出PDF
function exportPDF() {
const startDate = document.getElementById('startDate').value;
const endDate = document.getElementById('endDate').value;
const status = document.getElementById('status').value;
let url = '/api/report/export/pdf/orders?';
if (startDate) url += `startDate=${startDate}&`;
if (endDate) url += `endDate=${endDate}&`;
if (status) url += `status=${status}`;
window.open(url, '_blank');
}
// 渲染订单统计图表
async function renderStatisticChart() {
const startDate = document.getElementById('startDate').value;
const endDate = document.getElementById('endDate').value;
const params = new URLSearchParams();
if (startDate) params.append('startDate', startDate);
if (endDate) params.append('endDate', endDate);
const response = await fetch(`/api/report/statistics?${params}`);
const result = await response.json();
// 使用ECharts渲染统计图
const chart = echarts.init(document.getElementById('statisticChart'));
const dates = result.data.map(item => item.date);
const amounts = result.data.map(item => item.totalAmount);
const option = {
title: { text: '订单金额统计' },
tooltip: {},
xAxis: { data: dates },
yAxis: {},
series: [{
name: '金额',
type: 'bar',
data: amounts
}]
};
chart.setOption(option);
}
</script>
</head>
<body>
<div>
<label>开始日期: <input type="date" id="startDate"></label>
<label>结束日期: <input type="date" id="endDate"></label>
<label>订单状态:
<select id="status">
<option value="">全部</option>
<option value="1">待付款</option>
<option value="2">已付款</option>
<option value="3">已完成</option>
<option value="4">已取消</option>
</select>
</label>
<button onclick="getOrderReport()">查询</button>
<button onclick="exportExcel()">导出Excel</button>
<button onclick="exportPDF()">导出PDF</button>
</div>
<div id="statisticChart" style="width: 600px; height: 400px;"></div>
<table id="orderTable">
<thead>
<tr>
<th>订单编号</th>
<th>客户名称</th>
<th>订单金额</th>
<th>订单状态</th>
<th>创建时间</th>
</tr>
</thead>
<tbody></tbody>
</table>
</body>
</html>
pom.xml依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
</parent>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<!-- Apache POI for Excel -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.2</version>
</dependency>
<!-- JasperReports for PDF -->
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.20.0</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
这个完整的报表系统案例包含了:
- 数据查询:支持按日期范围、状态等多条件筛选
- Excel导出:使用Apache POI实现
- PDF导出:使用JasperReports实现
- 统计分析:支持订单金额统计、趋势分析
- 前端展示:提供查询界面和数据可视化
- RESTful API:提供标准化的数据接口
您可以根据实际需求调整报表类型、添加新的报表功能,或者扩展更多数据可视化方式。