Commit 6f8d3b2a by zhangxingmin

通用Excel导入接口

parent 2baef10c
......@@ -6,6 +6,7 @@ import com.yd.oss.feign.client.ApiExcelFeignClient;
import com.yd.oss.feign.request.ApiOssExportAppointmentExcelRequest;
import com.yd.oss.feign.response.ApiOssExcelParseResponse;
import com.yd.oss.feign.response.ApiOssExportAppointmentExcelResponse;
import com.yd.oss.feign.result.ImportResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
......@@ -47,4 +48,28 @@ public class ApiExcelController implements ApiExcelFeignClient {
return apiExcelService.parse(file,sheetClassNames);
}
/**
* 通用Excel导入接口
* @param file Excel文件
* @param headerRow 表头行号(默认第1行,从0开始)
* @param dataStartRow 数据开始行号(默认第2行,从0开始)
* @param requiredFields 必填字段列表(多个字段逗号分隔)
* @return 导入的结果
*/
@Override
public Result<ImportResult> importExcel(MultipartFile file, Integer headerRow,
Integer dataStartRow, String requiredFields) {
return apiExcelService.importExcel(file,headerRow,dataStartRow,requiredFields);
}
/**
* 简化导入接口
* @param file
* @return
*/
@Override
public Result<ImportResult> simpleImport(MultipartFile file) {
return apiExcelService.simpleImport(file);
}
}
......@@ -4,6 +4,7 @@ import com.yd.common.result.Result;
import com.yd.oss.feign.request.ApiOssExportAppointmentExcelRequest;
import com.yd.oss.feign.response.ApiOssExcelParseResponse;
import com.yd.oss.feign.response.ApiOssExportAppointmentExcelResponse;
import com.yd.oss.feign.result.ImportResult;
import org.springframework.web.multipart.MultipartFile;
public interface ApiExcelService {
......@@ -11,4 +12,9 @@ public interface ApiExcelService {
Result<ApiOssExportAppointmentExcelResponse> exportAppointment(ApiOssExportAppointmentExcelRequest request);
Result<ApiOssExcelParseResponse> parse(MultipartFile file, String[] sheetClassNames);
Result<ImportResult> importExcel(MultipartFile file, Integer headerRow,
Integer dataStartRow, String requiredFields);
Result<ImportResult> simpleImport(MultipartFile file);
}
......@@ -6,12 +6,17 @@ import com.yd.oss.api.service.ApiExcelService;
import com.yd.oss.feign.request.ApiOssExportAppointmentExcelRequest;
import com.yd.oss.feign.response.ApiOssExcelParseResponse;
import com.yd.oss.feign.response.ApiOssExportAppointmentExcelResponse;
import com.yd.oss.feign.result.ImportResult;
import com.yd.oss.service.service.AppointmentExcelService;
import com.yd.oss.service.service.ExcelImportService;
import com.yd.oss.service.service.ExcelParserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@Slf4j
......@@ -24,6 +29,9 @@ public class ApiExcelServiceImpl implements ApiExcelService {
@Autowired
private ExcelParserService excelParserService;
@Autowired
private ExcelImportService excelImportService;
/**
* 导出excel-预约信息
* @param request
......@@ -65,4 +73,35 @@ public class ApiExcelServiceImpl implements ApiExcelService {
}
}
/**
* 通用Excel导入接口
* @param file Excel文件
* @param headerRow 表头行号(默认第1行,从0开始)
* @param dataStartRow 数据开始行号(默认第2行,从0开始)
* @param requiredFields 必填字段列表(多个字段逗号分隔)
* @return 导入的结果
*/
@Override
public Result<ImportResult> importExcel(MultipartFile file, Integer headerRow,
Integer dataStartRow, String requiredFields) {
List<String> requiredFieldList = null;
if (requiredFields != null && !requiredFields.isEmpty()) {
requiredFieldList = Arrays.asList(requiredFields.split(","));
}
ImportResult importResult = excelImportService.genericImport(file, headerRow, dataStartRow, requiredFieldList);
return Result.success(importResult);
}
/**
* 简化导入接口
* @param file
* @return
*/
@Override
public Result<ImportResult> simpleImport(MultipartFile file) {
ImportResult importResult = excelImportService.simpleImport(file);
return Result.success(importResult);
}
}
......@@ -5,11 +5,13 @@ import com.yd.oss.feign.fallback.ApiExcelFeignFallbackFactory;
import com.yd.oss.feign.request.ApiOssExportAppointmentExcelRequest;
import com.yd.oss.feign.response.ApiOssExcelParseResponse;
import com.yd.oss.feign.response.ApiOssExportAppointmentExcelResponse;
import com.yd.oss.feign.result.ImportResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
......@@ -21,6 +23,7 @@ public interface ApiExcelFeignClient {
/**
* 导出excel-预约信息
* @param request
* @return
*/
@PostMapping("/export/appointment")
......@@ -28,9 +31,34 @@ public interface ApiExcelFeignClient {
/**
* 通用-Excel解析(支持多sheet页解析)
* @param file
* @param sheetClassNames
* @return
*/
@PostMapping(value = "/parse-excel", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
Result<ApiOssExcelParseResponse> parse(@RequestPart("file") MultipartFile file,
@RequestPart("sheetClassNames") String[] sheetClassNames);
/**
* 通用Excel导入接口
* @param file Excel文件
* @param headerRow 表头行号(默认第1行,从0开始)
* @param dataStartRow 数据开始行号(默认第2行,从0开始)
* @param requiredFields 必填字段列表(多个字段逗号分隔)
* @return 导入的结果
*/
@PostMapping("/import")
Result<ImportResult> importExcel(
@RequestParam("file") MultipartFile file,
@RequestParam(value = "headerRow", required = false) Integer headerRow,
@RequestParam(value = "dataStartRow", required = false) Integer dataStartRow,
@RequestParam(value = "requiredFields", required = false) String requiredFields);
/**
* 简化导入接口
* @param file
* @return
*/
@PostMapping("/simple-import")
Result<ImportResult> simpleImport(@RequestParam("file") MultipartFile file);
}
......@@ -6,6 +6,7 @@ import com.yd.oss.feign.request.ApiOssExcelParseRequest;
import com.yd.oss.feign.request.ApiOssExportAppointmentExcelRequest;
import com.yd.oss.feign.response.ApiOssExcelParseResponse;
import com.yd.oss.feign.response.ApiOssExportAppointmentExcelResponse;
import com.yd.oss.feign.result.ImportResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
......@@ -30,6 +31,17 @@ public class ApiExcelFeignFallbackFactory implements FallbackFactory<ApiExcelFei
return null;
}
@Override
public Result<ImportResult> importExcel(MultipartFile file, Integer headerRow,
Integer dataStartRow, String requiredFields) {
return null;
}
@Override
public Result<ImportResult> simpleImport(MultipartFile file) {
return null;
}
};
}
}
package com.yd.oss.feign.result;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 导入结果
*/
public class ImportResult {
private boolean success;
private String message;
private boolean valid;
private int totalCount;
private List<String> headers;
private List<Map<String, Object>> data;
private List<String> errorMessages;
public ImportResult() {
this.headers = new ArrayList<>();
this.data = new ArrayList<>();
this.errorMessages = new ArrayList<>();
}
// getter和setter方法
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public boolean isValid() {
return valid;
}
public void setValid(boolean valid) {
this.valid = valid;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public List<String> getHeaders() {
return headers;
}
public void setHeaders(List<String> headers) {
this.headers = headers;
}
public List<Map<String, Object>> getData() {
return data;
}
public void setData(List<Map<String, Object>> data) {
this.data = data;
}
public List<String> getErrorMessages() {
return errorMessages;
}
public void setErrorMessages(List<String> errorMessages) {
this.errorMessages = errorMessages;
}
}
\ No newline at end of file
package com.yd.oss.feign.result;
import java.util.ArrayList;
import java.util.List;
/**
* 数据验证结果
*/
public class ValidationResult {
private boolean valid;
private List<String> errors;
public ValidationResult() {
this.errors = new ArrayList<>();
this.valid = true;
}
// getter和setter方法
public boolean isValid() {
return valid;
}
public void setValid(boolean valid) {
this.valid = valid;
}
public List<String> getErrors() {
return errors;
}
public void setErrors(List<String> errors) {
this.errors = errors;
}
public void addError(String error) {
this.errors.add(error);
this.valid = false;
}
public String getErrorMsg() {
return String.join("; ", errors);
}
}
\ No newline at end of file
package com.yd.oss.service.service;
import com.yd.oss.feign.result.ImportResult;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
public interface ExcelImportService {
ImportResult genericImport(
MultipartFile file,
Integer headerRow,
Integer dataStartRow,
List<String> requiredFields);
ImportResult simpleImport(MultipartFile file);
}
package com.yd.oss.service.service.impl;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import com.yd.oss.feign.result.ImportResult;
import com.yd.oss.feign.result.ValidationResult;
import com.yd.oss.service.service.ExcelImportService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.*;
/**
* 通用Excel导入工具类
* 支持动态表头解析
*/
@Slf4j
@Service
public class ExcelImportServiceImpl implements ExcelImportService {
/**
* 通用Excel导入
* @param file Excel文件
* @param headerRow 表头行号(默认第1行,从0开始)
* @param dataStartRow 数据开始行号(默认第2行,从0开始)
* @param requiredFields 必填字段列表
* @return 导入结果
*/
@Override
public ImportResult genericImport(MultipartFile file,
Integer headerRow,
Integer dataStartRow,
List<String> requiredFields) {
ImportResult result = new ImportResult();
try {
// 参数默认值处理
int headerRowNum = headerRow != null ? headerRow : 0;
int dataStartRowNum = dataStartRow != null ? dataStartRow : 1;
// 1. 获取表头信息
List<String> headers = getExcelHeaders(file, headerRowNum);
result.setHeaders(headers);
// 2. 导入Excel数据
ExcelImportResult<Map<String, Object>> importResult =
importExcel(file, headerRowNum, dataStartRowNum);
// 3. 处理导入结果
List<Map<String, Object>> data =
processImportResult(importResult, headers);
result.setData(data);
result.setTotalCount(data.size());
// 4. 数据验证
if (requiredFields != null && !requiredFields.isEmpty()) {
ValidationResult validationResult =
validateData(data, requiredFields);
result.setValid(validationResult.isValid());
result.setErrorMessages(validationResult.getErrors());
} else {
result.setValid(true);
}
result.setSuccess(true);
result.setMessage("导入成功,共导入" + data.size() + "条数据");
} catch (Exception e) {
result.setSuccess(false);
result.setMessage("导入失败:" + e.getMessage());
}
return result;
}
/**
* 简化的导入方法(使用默认参数)
* @param file
* @return
*/
@Override
public ImportResult simpleImport(MultipartFile file) {
return genericImport(file, 0, 1, null);
}
/**
* 通用Excel导入方法
* @param file Excel文件
* @param headerRowNum 表头所在行号(从0开始)
* @param dataStartRowNum 数据开始行号(从0开始)
* @return 导入结果
*/
public static ExcelImportResult<Map<String, Object>> importExcel(
MultipartFile file,
int headerRowNum,
int dataStartRowNum) throws Exception {
ImportParams params = new ImportParams();
params.setHeadRows(headerRowNum + 1); // 表头行数
params.setStartRows(dataStartRowNum); // 数据开始行
// 修正:方法名拼写错误,应该是setNeedVerify
params.setNeedVerify(true); // 需要校验
// 使用Map接收数据
return ExcelImportUtil.importExcelMore(
file.getInputStream(),
Map.class,
params
);
}
/**
* 获取Excel表头信息
* @param file Excel文件
* @param headerRowNum 表头所在行号(从0开始)
* @return 表头字段列表
*/
public static List<String> getExcelHeaders(MultipartFile file, int headerRowNum) throws Exception {
List<String> headers = new ArrayList<>();
// 修正:使用WorkbookFactory.create()静态方法
try (Workbook workbook = WorkbookFactory.create(file.getInputStream())) {
Sheet sheet = workbook.getSheetAt(0);
Row headerRow = sheet.getRow(headerRowNum);
if (headerRow != null) {
for (Cell cell : headerRow) {
String headerValue = getCellValue(cell);
if (headerValue != null && !headerValue.trim().isEmpty()) {
headers.add(headerValue.trim());
}
}
}
}
return headers;
}
/**
* 获取单元格值
* @param cell
* @return
*/
public static String getCellValue(Cell cell) {
if (cell == null) {
return null;
}
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue();
case NUMERIC:
return String.valueOf(cell.getNumericCellValue());
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case FORMULA:
return cell.getCellFormula();
default:
return "";
}
}
/**
* 处理导入结果,转换为更友好的数据结构
* @param result 导入结果
* @param headers 表头信息
* @return 处理后的数据
*/
public static List<Map<String, Object>> processImportResult(
ExcelImportResult<Map<String, Object>> result,
List<String> headers) {
List<Map<String, Object>> processedData = new ArrayList<>();
if (result != null && result.getList() != null) {
for (Map<String, Object> rowData : result.getList()) {
Map<String, Object> processedRow = new LinkedHashMap<>();
// 按照表头顺序重新组织数据
for (String header : headers) {
processedRow.put(header, rowData.get(header));
}
processedData.add(processedRow);
}
}
return processedData;
}
/**
* 验证导入数据
* @param data 导入的数据
* @param requiredFields 必填字段
* @return 验证结果
*/
public static ValidationResult validateData(List<Map<String, Object>> data, List<String> requiredFields) {
ValidationResult result = new ValidationResult();
result.setValid(true);
for (int i = 0; i < data.size(); i++) {
Map<String, Object> row = data.get(i);
int rowNum = i + 1; // 实际行号(从1开始)
// 检查必填字段
for (String field : requiredFields) {
Object value = row.get(field);
if (value == null || value.toString().trim().isEmpty()) {
result.setValid(false);
result.getErrors().add("第" + rowNum + "行,字段[" + field + "]不能为空");
}
}
// 这里可以添加更多的验证规则
// 例如:数据类型验证、格式验证等
}
return result;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment