Excel模板功能允许您:
- 📤 上传模板文件 - 上传预设格式和公式的Excel模板
- ✍️ 填充数据 - 通过API向模板指定位置写入数据
- 📥 下载结果 - 导出填充后的Excel文件
- 📊 批量生成报表 - 基于统一模板生成不同数据的报表
- 📄 发票/合同生成 - 自动填充客户信息和金额
- 📈 财务报告 - 填充财务数据自动计算
- 🎓 成绩单/证书 - 批量生成个性化文档
- 📦 订单/物流单 - 动态生成业务单据
创建一个Excel模板,例如 invoice_template.xlsx:
A列 B列 C列
----------------------------------------
1 发票抬头 [公司名称]
2 发票编号 [发票号]
3 日期 [日期]
4
5 项目 单价 数量 金额
6 项目1 100 5 =B6*C6
7 项目2 200 3 =B7*C7
8
9 合计 =SUM(D6:D7)
curl -X POST "http://localhost:8080/api/excel/upload" \
-F "file=@invoice_template.xlsx" \
-F "fileName=invoice_template.xlsx"curl -X POST "http://localhost:8080/api/excel/template/fill-and-download" \
-H "Content-Type: application/json" \
-d '{
"templateFileName": "invoice_template.xlsx",
"downloadFileName": "invoice_2024001.xlsx",
"sheetName": "Sheet1",
"cells": [
{"cellAddress": "B1", "value": "ABC科技有限公司", "valueType": "STRING"},
{"cellAddress": "B2", "value": "INV-2024-001", "valueType": "STRING"},
{"cellAddress": "B3", "value": "2024-10-24", "valueType": "STRING"},
{"cellAddress": "A6", "value": "软件开发服务", "valueType": "STRING"},
{"cellAddress": "B6", "value": 5000, "valueType": "NUMBER"},
{"cellAddress": "C6", "value": 1, "valueType": "NUMBER"},
{"cellAddress": "A7", "value": "技术支持", "valueType": "STRING"},
{"cellAddress": "B7", "value": 2000, "valueType": "NUMBER"},
{"cellAddress": "C7", "value": 2, "valueType": "NUMBER"}
]
}' \
--output invoice_2024001.xlsx结果:公式自动计算,D6=5000, D7=4000, D9=9000
GET /api/excel/download/{fileName}功能:下载服务器上已存在的Excel文件
示例:
curl -O http://localhost:8080/api/excel/download/report.xlsxPOST /api/excel/template/generate功能:基于模板创建新文件并保存到服务器
请求体:
{
"templateFileName": "template.xlsx", // 模板文件名
"outputFileName": "output_001.xlsx", // 输出文件名(可选)
"sheetName": "Sheet1", // Sheet名称
"cells": [ // 要填充的数据
{"cellAddress": "A1", "value": "数据", "valueType": "STRING"}
],
"keepFile": true // 是否保留文件(默认true)
}响应:直接返回生成的Excel文件供下载
示例:
curl -X POST "http://localhost:8080/api/excel/template/generate" \
-H "Content-Type: application/json" \
-d '{
"templateFileName": "sales_template.xlsx",
"outputFileName": "sales_2024_q1.xlsx",
"sheetName": "Sales",
"cells": [
{"cellAddress": "B2", "value": "2024-Q1", "valueType": "STRING"},
{"cellAddress": "B3", "value": 1000000, "valueType": "NUMBER"}
]
}' \
--output sales_2024_q1.xlsxPOST /api/excel/template/fill-and-download功能:填充模板后直接下载,不在服务器保留(推荐)
请求体:
{
"templateFileName": "template.xlsx", // 模板文件名
"downloadFileName": "download.xlsx", // 下载文件名(可选)
"sheetName": "Sheet1", // Sheet名称
"cells": [ // 要填充的数据
{"cellAddress": "A1", "value": "数据", "valueType": "STRING"}
]
}响应:直接返回Excel文件流
示例:
curl -X POST "http://localhost:8080/api/excel/template/fill-and-download" \
-H "Content-Type: application/json" \
-d '{
"templateFileName": "contract_template.xlsx",
"downloadFileName": "contract_xiaoming.xlsx",
"sheetName": "Contract",
"cells": [
{"cellAddress": "B3", "value": "张小明", "valueType": "STRING"},
{"cellAddress": "B4", "value": "130****8888", "valueType": "STRING"},
{"cellAddress": "B8", "value": 50000, "valueType": "NUMBER"}
]
}' \
--output contract_xiaoming.xlsxA列 B列
--------------------------
1 姓名 [员工姓名]
2 工号 [工号]
3 基本工资 [基本工资]
4 绩效奖金 [奖金]
5 应发工资 =B3+B4
6 个人所得税 =B5*0.1
7 实发工资 =B5-B6
import requests
import json
# 员工数据
employees = [
{"name": "张三", "id": "E001", "base": 10000, "bonus": 2000},
{"name": "李四", "id": "E002", "base": 12000, "bonus": 3000},
{"name": "王五", "id": "E003", "base": 15000, "bonus": 5000},
]
url = 'http://localhost:8080/api/excel/template/fill-and-download'
for emp in employees:
payload = {
'templateFileName': 'salary_template.xlsx',
'downloadFileName': f'salary_{emp["id"]}.xlsx',
'sheetName': 'Sheet1',
'cells': [
{'cellAddress': 'B1', 'value': emp['name'], 'valueType': 'STRING'},
{'cellAddress': 'B2', 'value': emp['id'], 'valueType': 'STRING'},
{'cellAddress': 'B3', 'value': emp['base'], 'valueType': 'NUMBER'},
{'cellAddress': 'B4', 'value': emp['bonus'], 'valueType': 'NUMBER'}
]
}
response = requests.post(url, json=payload)
with open(f'output/salary_{emp["id"]}.xlsx', 'wb') as f:
f.write(response.content)
print(f'✅ 已生成: {emp["name"]} 的工资条')A列 B列 C列 D列
---------------------------------------------
1 销售报表
2 报表期间 [期间] 销售员 [姓名]
3
4 产品 数量 单价 金额
5 产品A [数量] [单价] =B5*C5
6 产品B [数量] [单价] =B6*C6
7 产品C [数量] [单价] =B7*C7
8
9 总计 =SUM(D5:D7)
10 佣金(5%) =D9*0.05
const axios = require('axios');
const fs = require('fs');
async function generateSalesReport(salesData) {
const payload = {
templateFileName: 'sales_report_template.xlsx',
downloadFileName: `sales_report_${salesData.period}.xlsx`,
sheetName: 'Report',
cells: [
{cellAddress: 'B2', value: salesData.period, valueType: 'STRING'},
{cellAddress: 'D2', value: salesData.salesPerson, valueType: 'STRING'},
{cellAddress: 'B5', value: salesData.productA.quantity, valueType: 'NUMBER'},
{cellAddress: 'C5', value: salesData.productA.price, valueType: 'NUMBER'},
{cellAddress: 'B6', value: salesData.productB.quantity, valueType: 'NUMBER'},
{cellAddress: 'C6', value: salesData.productB.price, valueType: 'NUMBER'},
{cellAddress: 'B7', value: salesData.productC.quantity, valueType: 'NUMBER'},
{cellAddress: 'C7', value: salesData.productC.price, valueType: 'NUMBER'}
]
};
const response = await axios.post(
'http://localhost:8080/api/excel/template/fill-and-download',
payload,
{ responseType: 'arraybuffer' }
);
fs.writeFileSync(`output/sales_report_${salesData.period}.xlsx`, response.data);
console.log(`✅ 报表已生成: ${salesData.period}`);
}
// 使用示例
const salesData = {
period: '2024-10',
salesPerson: '张销售',
productA: { quantity: 100, price: 99 },
productB: { quantity: 50, price: 199 },
productC: { quantity: 30, price: 299 }
};
generateSalesReport(salesData);合同编号:[合同号]
甲方:[甲方名称]
乙方:[乙方名称]
合同金额:[金额] 元
签订日期:[日期]
有效期至:[到期日期]
付款方式:
首付款(30%):=B5*0.3
中期款(40%):=B5*0.4
尾款(30%):=B5*0.3
public class ContractGenerator {
private static final String API_URL =
"http://localhost:8080/api/excel/template/fill-and-download";
public void generateContract(ContractData data) throws IOException {
// 构建请求
Map<String, Object> request = new HashMap<>();
request.put("templateFileName", "contract_template.xlsx");
request.put("downloadFileName", "contract_" + data.getContractNo() + ".xlsx");
request.put("sheetName", "Contract");
List<Map<String, Object>> cells = new ArrayList<>();
cells.add(createCell("B1", data.getContractNo(), "STRING"));
cells.add(createCell("B2", data.getPartyA(), "STRING"));
cells.add(createCell("B3", data.getPartyB(), "STRING"));
cells.add(createCell("B5", data.getAmount(), "NUMBER"));
cells.add(createCell("B6", data.getSignDate(), "STRING"));
cells.add(createCell("B7", data.getExpireDate(), "STRING"));
request.put("cells", cells);
// 发送请求并保存文件
// ... HTTP客户端代码
System.out.println("✅ 合同已生成: " + data.getContractNo());
}
private Map<String, Object> createCell(String address, Object value, String type) {
Map<String, Object> cell = new HashMap<>();
cell.put("cellAddress", address);
cell.put("value", value);
cell.put("valueType", type);
return cell;
}
}包含学校logo、成绩表格、签章位置等
import pandas as pd
import requests
# 从数据库或CSV读取学生数据
students = pd.read_csv('students.csv')
for _, student in students.iterrows():
payload = {
'templateFileName': 'transcript_template.xlsx',
'downloadFileName': f'transcript_{student["student_id"]}.xlsx',
'sheetName': 'Transcript',
'cells': [
{'cellAddress': 'B2', 'value': student['name'], 'valueType': 'STRING'},
{'cellAddress': 'B3', 'value': student['student_id'], 'valueType': 'STRING'},
{'cellAddress': 'B5', 'value': student['math_score'], 'valueType': 'NUMBER'},
{'cellAddress': 'B6', 'value': student['english_score'], 'valueType': 'NUMBER'},
{'cellAddress': 'B7', 'value': student['physics_score'], 'valueType': 'NUMBER'},
# 总分由模板中的公式自动计算
]
}
response = requests.post(
'http://localhost:8080/api/excel/template/fill-and-download',
json=payload
)
with open(f'transcripts/{student["student_id"]}.xlsx', 'wb') as f:
f.write(response.content)
print(f'✅ 已生成 {len(students)} 份成绩单')虽然API使用单元格地址,但在模板中使用命名区域可以提高可读性:
定义名称:
- CustomerName -> B3
- InvoiceAmount -> D10
在模板中提前设置好所有计算公式:
=SUM(D5:D9) // 总计
=IF(B10>1000,B10*0.9,B10) // 折扣计算
=VLOOKUP(A2,PriceTable,2,FALSE) // 价格查询
模板可以包含条件格式,填充数据后自动生效:
如果金额>10000,单元格背景变红
如果成绩<60,显示为红色
为防止错误数据,可在模板中设置数据验证:
B列:只能输入1-100的数字
C列:只能选择下拉列表中的选项
保护某些单元格不被修改:
锁定:标题行、公式单元格、logo
不锁定:数据输入区域
curl -X POST ".../template/fill-and-download" \
-d '{
"templateFileName": "multi_sheet_template.xlsx",
"sheetName": "2024-Q1", // 动态指定Sheet
"cells": [...]
}'需要填充多个Sheet时,分别调用API:
sheets_data = {
'Summary': [...],
'Details': [...],
'Chart': [...]
}
for sheet_name, cells in sheets_data.items():
# 先生成中间文件
# 然后继续填充下一个Sheet模板中包含图表,数据填充后图表自动更新:
模板包含:
- 数据表(A1:B10)
- 基于数据表的柱状图
填充数据后,图表自动更新
向合并单元格写入数据时,使用合并区域的左上角单元格地址:
{
"cellAddress": "A1", // A1:C1是合并单元格,使用A1
"value": "标题"
}// ❌ 不安全:直接使用用户输入
fileName = userInput;
// ✅ 安全:验证和清理
if (fileName.contains("..") || fileName.contains("/")) {
throw new SecurityException("非法文件名");
}spring:
servlet:
multipart:
max-file-size: 100MB # 上传限制- 模板文件:只读,可多用户并发访问
- 生成文件:建议使用
fill-and-download(临时文件)
建议配置定时任务清理临时目录:
@Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点
public void cleanTempFiles() {
// 删除超过24小时的临时文件
}对于频繁使用的模板,可以考虑缓存:
@Cacheable("templates")
public File getTemplate(String fileName) {
return new File(storagePath, fileName);
}对于大批量生成,使用异步处理:
@Async
public CompletableFuture<File> generateAsync(TemplateRequest req) {
// 异步生成
}# 使用线程池并发生成
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=5) as executor:
futures = [executor.submit(generate_report, data)
for data in batch_data]
for future in futures:
result = future.result()A: 会!模板中的图片、图表、格式都会完整保留。
A: 可以。使用 valueType: "FORMULA" 覆盖原有公式。
A: 使用 fill-and-download 接口,配合线程池并发生成。
A: 可以!生成的是标准Excel文件,可以在Excel中正常打开编辑。
A: 建议使用.xlsx格式,对.xls支持有限。
开始使用模板功能,让您的Excel自动化更上一层楼! 🚀