通用导入导出功能设计方案
一、数据库设计
1、数据库ER图
erDiagram
excel_config ||--o{ sheet_config : "1:n"
sheet_config ||--o{ column_config : "1:n"
excel_config ||--o{ export_column_config : "1:n"
excel_config ||--o{ export_condition : "1:n"
sheet_config ||--o{ import_validation : "1:n"
excel_config {
BIGINT config_id PK
VARCHAR(50) business_key
BOOLEAN template_mode
BOOLEAN import_mode
BOOLEAN export_mode
VARCHAR(20) sheet_strategy
}
sheet_config {
BIGINT sheet_id PK
BIGINT config_id FK
VARCHAR(100) sheet_pattern
INTEGER start_row
VARCHAR(100) target_table
}
column_config {
BIGINT column_id PK
BIGINT sheet_id FK
VARCHAR(5) excel_col
VARCHAR(100) db_column
VARCHAR(20) data_type
VARCHAR(100) format_pattern
}
export_column_config {
BIGINT export_id PK
BIGINT config_id FK
VARCHAR(100) db_column
VARCHAR(100) excel_header
INTEGER display_order
VARCHAR(100) format_pattern
}
import_validation {
BIGINT validation_id PK
BIGINT sheet_id FK
VARCHAR(20) rule_type
TEXT rule_expression
VARCHAR(255) error_message
}
export_condition {
BIGINT condition_id PK
BIGINT config_id FK
VARCHAR(50) param_name
VARCHAR(20) data_type
BOOLEAN required
}
2、完整表结构DDL
sql
-- 主配置表
CREATE TABLE excel_config (
config_id BIGSERIAL PRIMARY KEY,
business_key VARCHAR(50) UNIQUE NOT NULL,
template_mode BOOLEAN DEFAULT FALSE,
import_mode BOOLEAN DEFAULT FALSE,
export_mode BOOLEAN DEFAULT FALSE,
sheet_strategy VARCHAR(20) CHECK (sheet_strategy IN ('first','all','by_name')),
file_types VARCHAR(50)[] CHECK (file_types <@ ARRAY['xls','xlsx','csv']),
version INTEGER DEFAULT 1 NOT NULL
);
COMMENT ON TABLE excel_config IS '核心配置表';
COMMENT ON COLUMN excel_config.sheet_strategy IS '多Sheet处理策略';
-- Sheet配置表
CREATE TABLE sheet_config (
sheet_id BIGSERIAL PRIMARY KEY,
config_id BIGINT NOT NULL REFERENCES excel_config(config_id),
sheet_pattern VARCHAR(100),
start_row INTEGER DEFAULT 1 NOT NULL,
end_row_detect BOOLEAN DEFAULT TRUE,
target_table VARCHAR(100) NOT NULL,
UNIQUE(config_id, sheet_pattern)
);
COMMENT ON COLUMN sheet_config.end_row_detect IS '自动检测结束行';
-- 列配置表
CREATE TABLE column_config (
column_id BIGSERIAL PRIMARY KEY,
sheet_id BIGINT NOT NULL REFERENCES sheet_config(sheet_id),
excel_col VARCHAR(5) NOT NULL CHECK (excel_col ~ '^[A-Z]+$'),
db_column VARCHAR(100) NOT NULL,
data_type VARCHAR(20) CHECK (data_type IN ('string','number','date','boolean')),
required BOOLEAN DEFAULT FALSE,
format_pattern VARCHAR(100),
header_style VARCHAR(50),
data_style VARCHAR(50),
UNIQUE(sheet_id, excel_col)
);
-- 导出列配置表
CREATE TABLE export_column_config (
export_id BIGSERIAL PRIMARY KEY,
config_id BIGINT NOT NULL REFERENCES excel_config(config_id),
db_column VARCHAR(100) NOT NULL,
excel_header VARCHAR(100) NOT NULL,
display_order INTEGER NOT NULL CHECK (display_order > 0),
format_pattern VARCHAR(100),
security_level INTEGER CHECK (security_level BETWEEN 1 AND 3),
mask_pattern VARCHAR(100),
permission_code VARCHAR(50),
UNIQUE(config_id, db_column)
);
-- 导入验证规则表
CREATE TABLE import_validation (
validation_id BIGSERIAL PRIMARY KEY,
sheet_id BIGINT REFERENCES sheet_config(sheet_id),
rule_type VARCHAR(50) NOT NULL CHECK (rule_type IN ('file','sheet','cell','business')),
rule_expression TEXT NOT NULL,
error_message VARCHAR(255) NOT NULL,
CONSTRAINT valid_sheet CHECK (
(rule_type = 'file' AND sheet_id IS NULL) OR
(rule_type != 'file' AND sheet_id IS NOT NULL)
)
);
-- 导出条件表
CREATE TABLE export_condition (
condition_id BIGSERIAL PRIMARY KEY,
config_id BIGINT NOT NULL REFERENCES excel_config(config_id),
param_name VARCHAR(50) NOT NULL,
data_type VARCHAR(20) CHECK (data_type IN ('date','number','string')),
required BOOLEAN DEFAULT FALSE,
default_value VARCHAR(100),
UNIQUE(config_id, param_name)
);
3、索引建议
sql
-- 主表索引
CREATE INDEX idx_business_key ON excel_config(business_key);
CREATE INDEX idx_sheet_mapping ON sheet_config(config_id, target_table);
-- 导出配置索引
CREATE INDEX idx_export_order ON export_column_config(config_id, display_order);
CREATE INDEX idx_export_security ON export_column_config(security_level);
-- 导入验证索引
CREATE INDEX idx_validation_type ON import_validation(rule_type);
CREATE INDEX idx_sheet_validations ON import_validation(sheet_id);
-- 导出条件索引
CREATE INDEX idx_export_params ON export_condition(config_id, param_name);
4、使用示例
场景1:合同模板配置(模板导出)
sql
-- 启用模板模式
INSERT INTO excel_config (business_key, template_mode, sheet_strategy)
VALUES ('contract', TRUE, 'by_name');
-- 配置Sheet
INSERT INTO sheet_config (config_id, sheet_pattern, target_table)
VALUES (1, '^合同主表$', 'contract_main');
-- 配置列
INSERT INTO column_config (sheet_id, excel_col, db_column, data_type, format_pattern)
VALUES
(1, 'A', 'contract_no', 'string', 'text'),
(1, 'B', 'sign_date', 'date', 'yyyy-MM-dd');
场景2:数据导入验证规则
sql
-- 文件级验证
INSERT INTO import_validation (rule_type, rule_expression, error_message)
VALUES
('file', 'size < 10485760', '文件大小不能超过10MB'),
('file', 'fileType IN (xlsx)', '仅支持xlsx格式');
-- 列级验证
INSERT INTO import_validation (sheet_id, rule_type, rule_expression, error_message)
VALUES
(1, 'cell', 'regex:^HT\d{8}$', '合同编号格式错误'),
(1, 'cell', 'range:amount > 0', '金额必须大于0');
场景3:数据导出配置
sql
-- 导出列配置
INSERT INTO export_column_config
(config_id, db_column, excel_header, display_order, security_level)
VALUES
(1, 'contract_no', '合同编号', 1, 1),
(1, 'amount', '合同金额', 2, 2);
-- 导出条件
INSERT INTO export_condition
(config_id, param_name, data_type, required)
VALUES
(1, 'start_date', 'date', TRUE),
(1, 'end_date', 'date', TRUE);
5、典型查询示例
获取完整导出配置
sql
SELECT
ec.business_key,
ecc.excel_header,
ecc.db_column,
ecc.format_pattern,
excon.param_name
FROM excel_config ec
JOIN export_column_config ecc USING (config_id)
LEFT JOIN export_condition excon USING (config_id)
WHERE ec.business_key = 'contract'
ORDER BY ecc.display_order;
获取导入验证规则
sql
SELECT
iv.rule_type,
iv.rule_expression,
iv.error_message,
s.sheet_pattern
FROM import_validation iv
LEFT JOIN sheet_config s USING (sheet_id)
WHERE s.config_id = 1
ORDER BY
CASE iv.rule_type
WHEN 'file' THEN 1
WHEN 'sheet' THEN 2
WHEN 'cell' THEN 3
ELSE 4
END;
二、核心设计
1、类设计
typescript
classDiagram
direction TB
class BaseExcelController {
<<abstract>>
#excelService: ExcelService
+exportTemplate(HttpServletResponse, String): void
+importData(MultipartFile, String): Result<?>
+exportData(HttpServletResponse, ExportRequest): void
#getDictService()*: DictService
#beforeImport(ImportContext): void
#afterExport(ExportContext): void
}
class ContractController {
+ContractController()
+customExport(HttpServletResponse, ContractQuery): void
}
class ExcelService {
<<interface>>
+generateTemplate(HttpServletResponse, String): void
+processImport(MultipartFile, String): ImportResult
+processExport(HttpServletResponse, ExportRequest): void
}
class ExcelServiceImpl {
-configRepository: ConfigRepository
-dictService: DictService
-sqlBuilder: DynamicSQLBuilder
+validateFile(ValidationContext): boolean
+parseDataBySheets(ValidationContext): Map~String, List~Map~~
}
class ValidationHandler {
<<interface>>
+validate(ValidationContext): void
+next(): ValidationHandler
+setNext(ValidationHandler): void
}
class FileValidation {
-next: ValidationHandler
+doValidate(ValidationContext): void
}
class SheetValidation {
-next: ValidationHandler
+doValidate(ValidationContext): void
}
class DynamicSQLBuilder {
+buildInsertSQL(String, Set~String~): String
+createParameterSource(Map~String,Object~): SqlParameterSource
}
class ImportContext {
-file: MultipartFile
-errors: List~CellError~
+getParsedData(): Map~String, List~Map~~
+addError(CellError): void
}
class ExportContext {
-queryParams: Map~String, Object~
-resultSet: Stream~Map~String, Object~~
+getResultStream(): Stream~Map~String, Object~~
}
BaseExcelController <|-- ContractController : 继承
BaseExcelController o--> ExcelService : 依赖
ExcelServiceImpl ..|> ExcelService : 实现
ExcelServiceImpl --> DynamicSQLBuilder : 组合
ExcelServiceImpl --> ConfigRepository : 组合
ValidationHandler <|.. FileValidation : 实现
ValidationHandler <|.. SheetValidation : 实现
FileValidation --> SheetValidation : 责任链
ExcelServiceImpl --> ValidationHandler : 使用
ImportContext <.. ExcelServiceImpl : 创建
ExportContext <.. ExcelServiceImpl : 创建
关键设计说明:
-
继承结构:
BaseExcelController ContractController
-
具体业务控制器(如
ContractController
)继承自基类BaseExcelController
-
必须实现抽象方法:
csharpprotected abstract DictService getDictService();
-
-
策略模式集成:
BaseExcelController ExcelService ExcelServiceImpl
-
通过依赖注入的
ExcelService
实现三大场景核心逻辑 -
具体实现类
ExcelServiceImpl
包含:javapublic class ExcelServiceImpl implements ExcelService { // 主要组件 private final ConfigRepository configRepository; private final DynamicSQLBuilder sqlBuilder; // 批处理方法 private void batchInsertMultiTable(...); }
-
-
验证责任链:
ValidationHandler FileValidation SheetValidation
-
验证流程按
File → Sheet → Cell → Business
顺序执行 -
验证器类的主要方法:
scalapublic class FileValidation extends ValidationChain { @Override protected void doValidate(ValidationContext ctx) { // 1. 校验文件类型/大小 // 2. 校验文件数字签名 } }
-
-
上下文对象:
ImportContext ExcelServiceImpl ExportContext
-
ImportContext
封装导入过程数据:swiftpublic class ImportContext { private final MultipartFile file; private List<CellError> errors; private Map<String, Object> parsedData; }
-
ExportContext
封装导出查询参数:typescriptpublic class ExportContext { private Map<String, Object> queryParams; private Stream<Map<String, Object>> resultStream; }
-
典型调用流程示例
java
JdbcTemplateDynamicSQLBuilderValidationHandlerExcelServiceContractControllerClientJdbcTemplateDynamicSQLBuilderValidationHandlerExcelServiceContractControllerClientalt[验证失败][验证成功]POST /contract/import + Excel文件processImport(file, "contract")执行验证链返回错误列表错误结果buildInsertSQL()生成动态SQL批量插入数据插入结果成功结果返回响应
2、BaseController核心设计
less
public abstract class BaseExcelController {
@Autowired
protected ExcelService excelService;
// 导出模板
@GetMapping("/template")
public void exportTemplate(HttpServletResponse response,
@RequestParam String businessKey) {
excelService.generateTemplate(response, businessKey);
}
// 导入数据
@PostMapping("/import")
public Result<?> importData(@RequestParam MultipartFile file,
@RequestParam String businessKey) {
ImportResult result = excelService.processImport(file, businessKey);
return Result.success(result);
}
// 导出数据
@PostMapping("/export")
public void exportData(HttpServletResponse response,
@RequestBody ExportRequest request) {
excelService.processExport(response, request);
}
// 需要子类实现的钩子方法
protected abstract DictService getDictService();
protected void beforeImport(ImportContext context) {}
protected void afterExport(ExportContext context) {}
}
3、验证流程设计(责任链模式)
3.1. 验证处理器接口
csharp
public interface ValidationHandler {
void validate(ValidationContext context);
ValidationHandler next();
ValidationHandler setNext(ValidationHandler next);
}
// 基础验证链
public class ValidationChain implements ValidationHandler {
private ValidationHandler next;
public void validate(ValidationContext context) {
doValidate(context);
if (next != null) {
next.validate(context);
}
}
protected abstract void doValidate(ValidationContext context);
}
3.2. 多级验证实现
scala
// 文件验证
public class FileValidation extends ValidationChain {
protected void doValidate(ValidationContext ctx) {
// 验证文件类型、大小、病毒扫描等
}
}
// Sheet验证
public class SheetValidation extends ValidationChain {
protected void doValidate(ValidationContext ctx) {
// Sheet数量、名称匹配等
}
}
// 单元格验证
public class CellValidation extends ValidationChain {
private final DictService dictService;
protected void doValidate(ValidationContext ctx) {
ctx.getRowData().forEach((col, value) -> {
validateDataType(colConfig, value);
validateDict(colConfig, value);
});
}
private void validateDict(ColumnConfig config, Object value) {
if (config.hasDict()) {
if (!dictService.isValid(config.getDictType(), value)) {
ctx.addError("无效字典值: " + value);
}
}
}
}
4、动态SQL构建器
4.1. 动态元数据处理
typescript
public class DynamicSQLBuilder {
public String buildInsertSQL(String table, Set<String> columns) {
String fields = String.join(",", columns);
String placeholders = columns.stream()
.map(c -> ":" + c)
.collect(Collectors.joining(","));
return String.format(
"INSERT INTO %s (%s) VALUES (%s) ON CONFLICT DO NOTHING",
table, fields, placeholders
);
}
public SqlParameterSource createParameterSource(Map<String, Object> row) {
return new MapSqlParameterSource(row);
}
}
4.2. 批量插入实现
typescript
public class BatchInserter {
@Transactional
public void batchInsertMultiTable(
Map<String, List<Map<String, Object>>> dataByTable) {
dataByTable.forEach((table, rows) -> {
Set<String> columns = rows.get(0).keySet();
String sql = sqlBuilder.buildInsertSQL(table, columns);
jdbcTemplate.batchUpdate(sql,
rows.stream()
.map(sqlBuilder::createParameterSource)
.toArray(SqlParameterSource[]::new)
);
});
}
}
5、模板生成引擎
5.1. 模板构建实现
scss
public class TemplateBuilder {
public Workbook buildTemplate(ExcelConfig config) {
Workbook workbook = createWorkbook(config);
config.getSheets().forEach(sheet -> {
Sheet sheet = workbook.createSheet(sheet.getName());
buildHeaders(sheet, sheet.getColumns());
addValidations(sheet, sheet.getColumns());
});
return workbook;
}
private void addValidations(Sheet sheet, List<ColumnConfig> columns) {
columns.forEach(col -> {
if (col.hasDict()) {
addDropdownValidation(sheet, col);
}
if (col.hasRegex()) {
addRegexValidation(sheet, col);
}
});
}
private void addDropdownValidation(Sheet sheet, ColumnConfig col) {
DataValidationHelper helper = sheet.getDataValidationHelper();
String[] dictValues = dictService.getValues(col.getDictType());
DataValidationConstraint constraint =
helper.createExplicitListConstraint(dictValues);
CellRangeAddressList addressList = new CellRangeAddressList(
1, 100000, col.getIndex(), col.getIndex()
);
sheet.addValidationData(helper.createValidation(constraint, addressList));
}
}
6、异常处理增强
6.1. 自定义异常
scala
public class ExcelException extends RuntimeException {
private ErrorCode code;
private List<CellError> errors;
public ExcelException(ErrorCode code, String message) {
super(message);
this.code = code;
}
}
public enum ErrorCode {
FILE_TYPE_INVALID,
DATA_VALIDATION_FAILED,
TEMPLATE_MISMATCH
}
6.2. 全局异常处理
java
@ControllerAdvice
public class ExcelExceptionHandler {
@ExceptionHandler(ExcelException.class)
public ResponseEntity<ErrorResponse> handleExcelException(
ExcelException ex) {
ErrorResponse response = new ErrorResponse(
ex.getCode(),
ex.getMessage(),
ex.getErrors()
);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(response);
}
}
7、企业级扩展实现
7.1. 数据加密处理
typescript
public class DataMasker {
public Map<String, Object> processRow(Map<String, Object> row,
List<ColumnConfig> columns) {
return columns.stream()
.collect(Collectors.toMap(
ColumnConfig::getDbColumn,
col -> maskIfRequired(col, row.get(col.getDbColumn()))
));
}
private Object maskIfRequired(ColumnConfig col, Object value) {
if (col.needMask()) {
return MaskUtils.mask(value, col.getMaskPattern());
}
return value;
}
}
6.2. 分布式锁控制
typescript
public class ImportLockManager {
public void processWithLock(String businessKey, Runnable task) {
String lockKey = "import_lock:" + businessKey;
try {
if (redisLock.tryLock(lockKey, 30, TimeUnit.SECONDS)) {
task.run();
} else {
throw new BusinessException("存在正在处理的导入任务");
}
} finally {
redisLock.unlock(lockKey);
}
}
}
8、性能优化方案
8.1. 流式导出实现
ini
public class StreamingExporter {
public void exportLargeData(ExportRequest request, OutputStream output) {
try (Workbook workbook = new SXSSFWorkbook(100)) {
Sheet sheet = workbook.createSheet("Data");
jdbcTemplate.queryForStream(
buildQuerySQL(request),
rs -> {
Map<String, Object> row = parseRow(rs);
writeRow(sheet, row);
flushIfNeeded(sheet);
}
);
workbook.write(output);
}
}
private void flushIfNeeded(SXSSFSheet sheet) {
if (sheet.getLastRowNum() % 100 == 0) {
sheet.flushRows(100);
}
}
}
8.2. 缓存优化
typescript
@Cacheable(value = "excelConfig", key = "#businessKey")
public ExcelConfig loadConfig(String businessKey) {
return configRepository.findByBusinessKey(businessKey)
.orElseThrow(() -> new ConfigNotFoundException(businessKey));
}
@Cacheable(value = "dictValues", key = "#dictType")
public String[] getDictValues(String dictType) {
return dictRepository.findCodesByType(dictType);
}
9、使用示例
less
@RestController
@RequestMapping("/contract")
public class ContractController extends BaseExcelController {
@Autowired
private ContractService contractService;
@Override
protected DictService getDictService() {
return contractService.getContractDictService();
}
@Override
protected void beforeImport(ImportContext context) {
context.addParam("currentUser", getCurrentUser());
}
@PostMapping("/custom-export")
public void customExport(HttpServletResponse response,
@RequestBody ContractQuery query) {
ExportRequest request = new ExportRequest("contract_export", query);
super.exportData(response, request);
}
}
三、验证方案
1、三种场景实现示例
场景1:导出模板
1. 数据库配置
sql
-- 主配置
INSERT INTO excel_config (business_key, template_mode, file_types)
VALUES ('contract_template', true, '{xlsx}');
-- Sheet配置
INSERT INTO sheet_config (config_id, sheet_pattern, target_table)
VALUES (1, '^合同主表$', 'contract_main');
-- 列配置
INSERT INTO column_config (sheet_id, excel_col, db_column, data_type, format_pattern)
VALUES
(1, 'A', 'contract_no', 'string', 'text'),
(1, 'B', 'sign_date', 'date', 'yyyy-MM-dd'),
(1, 'C', 'amount', 'number', '#,##0.00');
-- 字典配置示例(假设存在字典表)
INSERT INTO dict_data (dict_type, dict_code, dict_name)
VALUES
('contract_type', '01', '采购合同'),
('contract_type', '02', '销售合同');
2. 调用代码
scala
@RestController
@RequestMapping("/contract")
public class ContractController extends BaseExcelController {
// 导出模板
@GetMapping("/template")
public void downloadTemplate(HttpServletResponse response) {
exportTemplate(response, "contract_template");
}
}
3. 输出结果
- 生成包含以下内容的Excel文件:
lua
| 合同编号 | 签订日期 | 合同金额 |
|----------|-----------|----------|
(带数据验证的下拉列表和格式)
场景2:数据导入
1. 数据库配置
sql
-- 主配置
UPDATE excel_config SET import_mode = true
WHERE business_key = 'customer';
-- 验证规则
INSERT INTO import_validation (sheet_id, rule_type, rule_expression, error_message)
VALUES
(2, 'cell', 'regex:^[A-Za-z0-9]+$', '客户编码格式错误'),
(2, 'cell', 'dict:customer_level', '无效客户等级'),
(2, 'file', 'fileSize<5000', '文件不得超过5MB');
2. 调用代码
less
@PostMapping("/import")
public Result<?> importCustomer(@RequestParam MultipartFile file) {
return importData(file, "customer");
}
3. 输入文件示例(CSV)
客户编码,客户名称,客户等级
CUST001,测试客户,钻石级
4. 处理流程
css
DBServiceControllerClientDBServiceControllerClientalt[文件校验失败][Sheet校验失败][单元格校验失败][全部校验通过]上传文件开始验证返回错误返回错误返回详细错误批量插入返回成功
场景3:数据导出
1. 数据库配置
sql
-- 导出列配置
INSERT INTO export_column_config (config_id, db_column, excel_header, display_order)
VALUES
(3, 'order_no', '订单编号', 1),
(3, 'create_time', '下单时间', 2),
(3, 'total_amount', '订单金额', 3);
-- 导出条件
INSERT INTO export_condition (config_id, param_name, data_type)
VALUES
(3, 'start_time', 'date'),
(3, 'end_time', 'date');
2. 调用代码
less
@PostMapping("/export")
public void exportOrders(@RequestBody ExportRequest request,
HttpServletResponse response) {
request.setBusinessKey("order_export");
exportData(response, request);
}
3. 请求示例
json
{
"businessKey": "order_export",
"params": {
"start_time": "2023-01-01",
"end_time": "2023-12-31"
}
}
4. 输出结果
- 生成包含时间段内订单的Excel文件:
lua
| 订单编号 | 下单时间 | 订单金额 |
|----------|-------------------------|----------|
| O2023001 | 2023-05-01 14:30:00 | 12,500.00|
2、测试方案
2.1. 功能测试
测试场景 | 测试步骤 | 预期结果 |
---|---|---|
模板导出 | 1. 调用/template接口 | 返回带数据验证的规范模板 |
数据导入 | 1. 上传符合要求的CSV 2. 上传包含错误数据的文件 | 1. 返回成功 2. 返回具体错误位置 |
数据导出 | 1. 使用有效参数调用export接口 2. 使用无效时间范围 | 1. 返回正确Excel 2. 返回空文件提示 |
字典校验 | 导入包含未定义字典值的数据 | 返回"无效字典值"错误 |
2.2. 边界情况测试
测试类别 | 测试场景 | 预期结果 |
---|---|---|
文件大小 | 上传10MB的CSV文件 | 返回"文件超过限制"错误 |
行数限制 | 导入100001行数据 | 返回"超出最大行数限制" |
特殊字符 | 客户名称含emoji符号 | 编码转换后正常存储 |
时区验证 | 导出时使用UTC时间参数 | 数据按时区转换正确 |
空文件 | 上传0KB的Excel文件 | 返回"空文件"错误 |
2.3. 压力测试方案
测试工具:JMeter + Prometheus监控
测试类型 | 测试参数 | 通过标准 |
---|---|---|
单接口压测 | 100并发导出模板 | 平均RT < 500ms 错误率 < 0.1% |
组合场景 | 50并发导入+50并发导出 | 系统资源利用率 < 80% |
大数据量 | 导出1,000,000行数据 | 内存峰值 < 2GB 导出时间 < 60s |
长时间运行 | 持续运行24小时混合负载 | 无内存泄漏 TPS波动 < 10% |
监控指标:
- JVM内存使用(堆内存、GC次数)
- 数据库连接池使用率
- Excel文件生成速率(行/秒)
- 导入数据吞吐量(行/秒)
3、测试数据生成脚本
3.1. 大数据量导入测试文件生成(Python)
python
import csv
from faker import Faker
fake = Faker('zh_CN')
with open('large_data.csv', 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['客户编码', '客户名称', '客户等级'])
for _ in range(100000):
writer.writerow([
f"CUST{fake.unique.random_number(digits=6)}",
fake.company(),
fake.random_element(['钻石级','金牌级','银牌级'])
])
3.2. 压力测试JMeter配置
xml
<TestPlan>
<ThreadGroup>
<numThreads>100</numThreads>
<rampUp>60</rampUp>
<HTTPSampler>
<method>POST</method>
<path>/api/export</path>
<Body>
{"businessKey":"order_export","params":{"start_time":"2023-01-01"}}
</Body>
</HTTPSampler>
<ResultCollector>
<name>Aggregate Report</name>
</ResultCollector>
</ThreadGroup>
</TestPlan>