考勤,日历排班结果列表导出导入接口

zm_dev
sy 10 months ago
parent 5d44b211ea
commit 2d6b992cda

@ -0,0 +1,16 @@
package com.api.attendance.component.ImportAndExport;
import com.engine.attendance.component.ImportAndExport.web.ExcelController;
import lombok.extern.slf4j.Slf4j;
import javax.ws.rs.Path;
/**
* @Author: sy
* @Description:
* @Date: 2024/6/7
**/
@Path("/attendance/excel")
@Slf4j
public class ExcelControllerApi extends ExcelController {
}

@ -1015,7 +1015,7 @@ public class AttendanceSummaryServiceImpl extends Service implements AttendanceS
itemMap.put("ls", String.valueOf(time));
}
if (accountUnit.equals("2")) {
itemMap.put("lf", String.valueOf(time));
itemMap.put("lf", String.valueOf((int) time));
}
cqAddList.add(itemMap);
}
@ -1127,7 +1127,7 @@ public class AttendanceSummaryServiceImpl extends Service implements AttendanceS
itemMap.put("ls", String.valueOf(time));
}
if (accountUnit.equals("2")) {
itemMap.put("lf", String.valueOf(time));
itemMap.put("lf", String.valueOf((int) time));
}
cqjtAddList.add(itemMap);
}

@ -0,0 +1,28 @@
package com.engine.attendance.component.ImportAndExport.service;
import com.engine.attendance.component.ImportAndExport.service.param.ImportParam;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.util.Map;
/**
* @Author: sy
* @Description: excel
* @Date: 2024/6/5
**/
public interface ExcelExportImportService {
/**
*
* @param paramMap
* @return
*/
XSSFWorkbook exportSchedule(Map<String,Object> paramMap);
/**
*
* @param param
* @return
*/
Map<String, Object> importSchedule(ImportParam param);
}

@ -0,0 +1,332 @@
package com.engine.attendance.component.ImportAndExport.service.impl;
import cn.hutool.core.util.StrUtil;
import com.cloudstore.eccom.pc.table.WeaTableColumn;
import com.engine.attendance.component.ImportAndExport.service.ExcelExportImportService;
import com.engine.attendance.component.ImportAndExport.service.param.ImportParam;
import com.engine.attendance.component.calendarscheduling.service.WorkRulesService;
import com.engine.attendance.component.calendarscheduling.service.impl.WorkRulesServiceImpl;
import com.engine.attendance.enums.ApplicableOrganizationEnum;
import com.engine.attendance.enums.SchedulingApproachEnum;
import com.engine.common.exception.AttendanceRunTimeException;
import com.engine.common.util.*;
import com.engine.common.util.excel.ExcelParseHelper;
import com.engine.common.util.excel.ExcelSupport;
import com.engine.common.util.excel.ExcelUtil;
import com.engine.core.impl.Service;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import weaver.file.ImageFileManager;
import weaver.general.Util;
import weaver.hrm.User;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
import static com.engine.common.util.excel.ExcelSupport.EXCEL_TYPE_XLSX;
/**
* @Author: sy
* @Description:
* @Date: 2024/6/5
**/
@Slf4j
public class ExcelExportImportServiceImpl extends Service implements ExcelExportImportService {
private WorkRulesService getWorkRulesService(User user) {
return ServiceUtil.getService(WorkRulesServiceImpl.class,user);
}
@Override
public XSSFWorkbook exportSchedule(Map<String, Object> paramMap) {
String total = Util.null2String(paramMap.get("total"));
if ("".equals(total) || "0".equals(total)) {
paramMap.put("pageSize", "9999");
} else {
paramMap.put("pageSize", total);
}
paramMap.put("pageindex", "1");
Map<String, Object> scheduleResult = getWorkRulesService(user).getDepartSchedule(paramMap);
List<WeaTableColumn> columns = buildScheduleColumns((List<Map<String, Object>>) scheduleResult.get("columns"));
List<Map<String, Object>> records = buildScheduleRecords((List<Map<String, Object>>) scheduleResult.get("datas"));
List<List<Object>> excelSheetData = new ArrayList<>();
//工作簿名称
String sheetName = "日历排班";
excelSheetData.add(Arrays.asList(columns.stream().map(WeaTableColumn::getText).toArray()));
//工作簿数据
List<List<Object>> rows = new LinkedList<>();
for (Map<String, Object> recordData : records) {
List<Object> row = new LinkedList<>();
for (WeaTableColumn column : columns) {
row.add(recordData.get(column.getColumn()));
}
rows.add(row);
}
excelSheetData.addAll(rows);
String dateTime = Util.null2String(paramMap.get("dateTime"));
return ExcelUtil.genWorkbookV2(excelSheetData, sheetName, dateTime, columns.size());
}
private List<Map<String, Object>> buildScheduleRecords(List<Map<String, Object>> dataInfo) {
List<Map<String, Object>> result = new ArrayList<>();
if (dataInfo != null && dataInfo.size() > 0) {
Map<String, Object> dayItem;
Map<String, Object> record;
for (Map<String, Object> dataItem : dataInfo) {
record = new HashMap<>();
record.put("workcode", Util.null2String(dataItem.get("workcode")));
record.put("lastname", Util.null2String(dataItem.get("lastname")));
record.put("subcompany", Util.null2String(dataItem.get("subcompany")));
record.put("department", Util.null2String(dataItem.get("department")));
for (Map.Entry<String, Object> entry : dataItem.entrySet()) {
if (DateUtil.dateIsValid(entry.getKey())) {
dayItem = (Map<String, Object>) entry.getValue();
record.put(entry.getKey(), Util.null2String(dayItem.get("title")));
}
}
result.add(record);
}
}
return result;
}
private List<WeaTableColumn> buildScheduleColumns(List<Map<String,Object>> columnInfo) {
List<WeaTableColumn> list = new ArrayList<>();
if (columnInfo != null && columnInfo.size() > 0) {
for (Map<String, Object> columnItem : columnInfo) {
list.add(new WeaTableColumn("150px", Util.null2String(columnItem.get("title")), Util.null2String(columnItem.get("dataIndex"))));
}
}
return list;
}
@Override
public Map<String, Object> importSchedule(ImportParam param) {
if (StringUtils.isBlank(param.getImageId())) {
throw new AttendanceRunTimeException("导入文件id为空");
}
int successCount = 0;
int errorCount = 0;
//查询formmodeid
Map<String,String> formModeIdMap = Utils.getFormmodeIdMap();
String formModeId = formModeIdMap.get("uf_pbjg");
// 获取所有人员信息
List<Map<String, Object>> employeeInfoList = getAllEmpInfo();
//获取班次名称对于班次信息的映射
Map<String,Object> shiftMapWithMc = getShiftInfoToMc();
// 待入库数据
List<Map<String, Object>> toImportScheduleInfos = new ArrayList<>();
// 待处理数据
InputStream fileInputStream = null;
// 待处理数据关联的人员ids
List<String> empIds = new ArrayList<>();
try {
fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(param.getImageId()));
if (fileInputStream == null) {
throw new AttendanceRunTimeException("excel文件解析失败");
}
Sheet sheet = ExcelSupport.parseFile(fileInputStream, 0, EXCEL_TYPE_XLSX);
//标题
List<String> titles = ExcelSupport.getSheetHeader(sheet, 0);
String title = titles.get(0);
log.info("处理前年月信息:{}",title);
//年月格式的转换处理
if (StrUtil.isNotBlank(title) && title.length() > 7) {
title = title.substring(0, 7);
log.info("处理后年月信息:{}",title);
}
if (StrUtil.isNotBlank(title) && !DateUtil.checkYearMonth(title.replace("/", "-"))) {
throw new AttendanceRunTimeException("excel首行'年月'时间格式错误,正确格式为yyyy-mm或者yyyy-mm-dd或者yyyy/mm或者yyyy/mm/dd");
}
int monthDays = DateUtil.getDays(title, Calendar.DAY_OF_MONTH);
// 表头
List<String> headers = ExcelSupport.getSheetHeader(sheet, 1);
log.info("headers数据{}", headers);
// 错误sheet数据
List<Map<String, Object>> errorData = new LinkedList<>();
// 错误提示
List<Map<String, String>> excelComments = new LinkedList<>();
// 处理数值
List<Map<String, Object>> data = ExcelParseHelper.parse2Map(sheet, 2, 1);
log.info("excel导入数据[{}]", data);
//单行记录
Map<String, Object> map;
for (int i = 0; i < data.size(); i++) {
map = data.get(i);
boolean isError = false;
Map<String, String> singleCheck = new HashMap<>();
for (int j = 0; j < headers.size(); j++) {
//组装单条数据基础数据
String key = headers.get(j);
if (key == null) {
continue;
}
singleCheck.put(key, Optional.ofNullable(map.get(key)).orElse("").toString());
}
log.info(i + 3 + "-singleCheck[{}]", singleCheck);
isError = singleScheduleLineCheck(singleCheck, title, monthDays, toImportScheduleInfos, employeeInfoList, shiftMapWithMc, excelComments, i + 3, formModeId, empIds);
if (isError) {
errorCount += 1;
// 添加错误数据
errorData.add(map);
} else {
successCount += 1;
}
}
// 数据入库处理
handleScheduleImportData(toImportScheduleInfos, empIds, title, monthDays);
Map<String, Object> apidatas = new HashMap<String, Object>();
apidatas.put("successCount", successCount);
apidatas.put("errorCount", errorCount);
apidatas.put("errorData", excelComments);
return apidatas;
} finally {
IOUtils.closeQuietly(fileInputStream);
}
}
private List<Map<String, Object>> getAllEmpInfo() {
String sql = "select a.id, a.lastname, a.workcode, d.departmentname, s.subcompanyname " +
"from hrmresource a left join hrmdepartment d on d.id = a.departmentid " +
"left join hrmsubcompany s on s.id = a.subcompanyid1 ";
List<Map<String, Object>> empInfo = DbTools.getSqlToList(sql);
return empInfo;
}
private Map<String, Object> getShiftInfoToMc() {
String sql = "select id, mc, sfxx from uf_jcl_kq_bcxx ";
List<Map<String, Object>> shiftInfo = DbTools.getSqlToList(sql);
Map<String,Object> shiftMapWithMc = shiftInfo.stream().collect(Collectors.toMap(e->e.get("mc").toString(), e->e));
return shiftMapWithMc;
}
public boolean singleScheduleLineCheck(Map<String, String> singleCheck, String yearMonth, int monthDays,
List<Map<String, Object>> toImportScheduleInfos, List<Map<String, Object>> employeeByIds,
Map<String,Object> shiftMapWithMc, List<Map<String, String>> excelComments, int index, String formModeId, List<String> empIds) {
boolean isError = false;
String workCode = Util.null2String(singleCheck.get("编号"));
String lastName = Util.null2String(singleCheck.get("姓名"));
String subCompany = Util.null2String(singleCheck.get("分部"));
String department = Util.null2String(singleCheck.get("部门"));
String rowIndex = "第" + index + "行";
//校验该行数据中员工信息是否唯一存在
List<Map<String, Object>> targetEmpInfo = matchImportEmp(employeeByIds, lastName, subCompany, department, workCode);
if (CollectionUtils.isEmpty(targetEmpInfo)) {
Map<String, String> errorMessageMap = new HashMap<>();
errorMessageMap.put("message", rowIndex + "员工信息不存在!");
excelComments.add(errorMessageMap);
isError = true;
return isError;
} else if (targetEmpInfo.size() > 1) {
Map<String, String> errorMessageMap = new HashMap<>();
errorMessageMap.put("message", rowIndex + "员工信息存在多个匹配的员工!");
excelComments.add(errorMessageMap);
isError = true;
return isError;
}
String employeeId = Util.null2String(targetEmpInfo.get(0).get("id"));
if (empIds.size() > 0 && empIds.contains(employeeId)) {
Map<String, String> errorMessageMap = new HashMap<>();
errorMessageMap.put("message", rowIndex + "表格中同一员工不可存在多组排班数据!");
excelComments.add(errorMessageMap);
isError = true;
return isError;
}
//获取目标人员目标月日期类型对日期的映射
List<Map<String,Object>> rqlxInfo = CommonUtil.getYearCalendarList(employeeId, yearMonth.substring(0, 4));
Map<String, String> rqlxInfoWithRq = rqlxInfo.stream().filter(f -> f.get("rq").toString().contains(yearMonth)).collect(Collectors.toMap(e->e.get("rq").toString(), e->e.get("rqlx").toString()));
//暂存本次调用中的导入数据
List<Map<String, Object>> singleToImportScheduleInfos = new ArrayList<>();
//排班日期、班次名称
String scheduleDate = "";
String shiftName = "";
Map<String, Object> shiftInfo;
Map<String, Object> toImportItem;
for (int i = 1; i <= monthDays; i++) {
shiftName = Util.null2String(singleCheck.get(String.valueOf(i)));
scheduleDate = i < 10 ? yearMonth + "-0" + i : yearMonth + "-" + i;
//获取班次id
shiftInfo = (Map<String, Object>) shiftMapWithMc.get(shiftName);
if (!"".equals(shiftName) && shiftInfo == null) {
Map<String, String> errorMessageMap = new HashMap<>();
errorMessageMap.put("message", rowIndex + "班次名称-" + shiftName + ", 找不到对应的班次信息,检查是否编辑有误!");
excelComments.add(errorMessageMap);
isError = true;
}
if (!isError) {
toImportItem = new HashMap<>();
if ("".equals(shiftName)) {
//设置排班数据
toImportItem.put("sfxx", "1");
toImportItem.put("bcxx", null);
} else {
//设置排班数据
toImportItem.put("sfxx", shiftInfo.get("sfxx").toString());
toImportItem.put("bcxx", shiftInfo.get("id").toString());
}
toImportItem.put("formmodeid",formModeId);
toImportItem.put("modeuuid", UUID.randomUUID().toString());
toImportItem.put("modedatacreater","1");
toImportItem.put("modedatacreatertype","0");
toImportItem.put("modedatacreatedate", DateUtil.getCurrentTime().split(" ")[0]);
toImportItem.put("modedatacreatetime",DateUtil.getCurrentTime().split(" ")[1]);
// toImportItem.put("szjg", );
toImportItem.put("pbtj", SchedulingApproachEnum.IMPORT.getKey());
toImportItem.put("dxlx", ApplicableOrganizationEnum.PERSONNEL.getKey());
toImportItem.put("bcrq", scheduleDate);
toImportItem.put("rqlx", rqlxInfoWithRq.get(scheduleDate));
toImportItem.put("sfdkpp", "0");
toImportItem.put("pbrq", DateUtil.getCurrentDate());
toImportItem.put("pbsj", DateUtil.getCurrentTime("yyyy-MM-dd HH:mm").split(" ")[1]);
toImportItem.put("pbdxry", employeeId);
singleToImportScheduleInfos.add(toImportItem);
}
}
if (!isError) {
empIds.add(employeeId);
toImportScheduleInfos.addAll(singleToImportScheduleInfos);
}
return isError;
}
private List<Map<String, Object>> matchImportEmp(List<Map<String, Object>> employeeByIds, String lastName, String subCompany, String department, String workCode) {
employeeByIds = employeeByIds.stream().filter(e ->
(StrUtil.isBlank(workCode) || Objects.equals(e.get("workcode").toString(), workCode))
&& (StrUtil.isBlank(lastName) || Objects.equals(e.get("lastname").toString(), lastName))
&& (StringUtils.isBlank(department) || Objects.equals(e.get("departmentname"), department))
&& (StringUtils.isBlank(subCompany) || Objects.equals(e.get("subcompanyname"), subCompany)))
.collect(Collectors.toList());
return employeeByIds;
}
public void handleScheduleImportData(List<Map<String, Object>> toImportScheduleInfos, List<String> empIds, String yearMonth, int monthDays) {
if (toImportScheduleInfos.size() > 0 && empIds.size() > 0) {
//获取日期集合
List<String> dateList = new ArrayList<>();
for (int i = 1; i <= monthDays; i++) {
dateList.add(i < 10 ? yearMonth + "-0" + i : yearMonth + "-" + i);
}
//删除老数据
String delSql = " delete from uf_pbjg where dxlx = " + ApplicableOrganizationEnum.PERSONNEL.getKey()
+ " and bcrq in ('"+String.join("','",dateList)+"') and pbdxry in (" + String.join(",",empIds) + ")";
boolean delSign = DbTools.update(delSql);
//插入数据
boolean insertSign = CommonUtil.insertBatch(toImportScheduleInfos, "uf_pbjg");
}
}
}

@ -0,0 +1,22 @@
package com.engine.attendance.component.ImportAndExport.service.param;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author: sy
* @Description:
* @Date: 2024/6/5
**/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ImportParam {
/**
* id
*/
String imageId;
}

@ -0,0 +1,66 @@
package com.engine.attendance.component.ImportAndExport.web;
import com.engine.attendance.component.ImportAndExport.service.ExcelExportImportService;
import com.engine.attendance.component.ImportAndExport.service.impl.ExcelExportImportServiceImpl;
import com.engine.attendance.component.ImportAndExport.service.param.ImportParam;
import com.engine.common.util.ParamUtil;
import com.engine.common.util.ResponseResult;
import com.engine.common.util.ServiceUtil;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import weaver.hrm.HrmUserVarify;
import weaver.hrm.User;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.util.Map;
/**
* @Author: sy
* @Description:
* @Date: 2024/6/5
**/
public class ExcelController {
public ExcelExportImportService getExcelService(User user) {
return ServiceUtil.getService(ExcelExportImportServiceImpl.class, user);
}
@GET
@Path("/schedule/export")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response scheduleExport(@Context HttpServletRequest request, @Context HttpServletResponse response) {
User user = HrmUserVarify.getUser(request, response);
Map<String,Object> paramMap = ParamUtil.request2Map(request);
XSSFWorkbook workbook = getExcelService(user).exportSchedule(paramMap);
String time = LocalDate.now().toString();
String fileName = "日批排班列表" + time;
try {
fileName = URLEncoder.encode(fileName + ".xlsx", "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
StreamingOutput output = outputStream -> {
workbook.write(outputStream);
outputStream.flush();
};
response.setContentType("application/octet-stream");
return Response.ok(output).header("Content-disposition", "attachment;filename=" + fileName).header("Cache-Control", "no-cache").build();
}
@POST
@Path("/schedule/import")
@Produces(MediaType.APPLICATION_JSON)
public String importSchedule(@Context HttpServletRequest request, @Context HttpServletResponse response, @RequestBody ImportParam param) {
User user = HrmUserVarify.getUser(request, response);
return new ResponseResult<ImportParam, Map<String, Object>>(user).run(getExcelService(user)::importSchedule, param);
}
}

@ -1,11 +1,15 @@
package com.engine.common.util;
import org.apache.commons.lang3.StringUtils;
import weaver.general.TimeUtil;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DateUtil {
public static DateTimeFormatter yyyyMMdd = DateTimeFormatter.ofPattern("yyyy-MM-dd");
@ -14,6 +18,15 @@ public class DateUtil {
public static DateTimeFormatter yyyyMM = DateTimeFormatter.ofPattern("yyyy-MM");
public static DateTimeFormatter yyyy = DateTimeFormatter.ofPattern("yyyy");
/**
* yyyy-MM
**/
private static final String MONTH_REGEX = "^([1-9]\\d{3})-(([0][1-9])|([1][0-2]))$";
/**
* yyyy-MM-dd,
**/
private static final String DATE_PATTERN = "^\\d{4}-\\d{2}-\\d{2}$";
public static String beforeMonth(String time,int month){
LocalDateTime localDateTime = DateUtil.getTime(time);
return localDateTime.minusMonths(month).format(yyyyMMdd);
@ -296,4 +309,50 @@ public class DateUtil {
return date.split("-")[0]+"-12-31";
}
}
public static String getFormatLocalDate(Date date) {
if (date == null) {
return StringUtils.EMPTY;
}
LocalDateTime localDateTime = dateToLocalDateTime(date);
return getFormatLocalDate(localDateTime);
}
public static String getFormatLocalDate(LocalDateTime localDateTime) {
if (localDateTime == null) {
return StringUtils.EMPTY;
}
try {
return localDateTime.format(yyyyMMdd);
} catch (Exception e) {
return StringUtils.EMPTY;
}
}
public static LocalDateTime dateToLocalDateTime(Date date) {
Instant instant = date.toInstant();
ZoneId zone = ZoneId.systemDefault();
return LocalDateTime.ofInstant(instant, zone);
}
// 正则表达式用于匹配日期格式yyyy-MM-dd不验证日期是否合法
public static boolean dateIsValid(String date) {
if (date == null) {
return false;
}
// 编译正则表达式
Pattern pattern = Pattern.compile(DATE_PATTERN);
// 匹配日期字符串
Matcher matcher = pattern.matcher(date);
// 返回是否匹配的结果
return matcher.matches();
}
/**
*
*
* @param yearMonth
* @return
*/
public static boolean checkYearMonth(String yearMonth) {
return Pattern.matches(MONTH_REGEX, yearMonth);
}
}

@ -0,0 +1,42 @@
package com.engine.common.util.excel;
import org.apache.commons.lang3.exception.ContextedRuntimeException;
/**
* @Author: sy
* @Description:
* @Date: 2024/6/5
**/
public class ExcelParseException extends ContextedRuntimeException {
private static final long serialVersionUID = -8696742623977630854L;
public ExcelParseException(String message) {
super(message);
this.msgCode = DEFAULT_CODE;
}
public ExcelParseException(String message, Throwable cause) {
super(message, cause);
this.msgCode = DEFAULT_CODE;
}
/**
*
*/
private static final String DEFAULT_CODE = "EXCP0000";
/**
*
*/
private String msgCode;
public String getMsgCode() {
return msgCode;
}
public void setMsgCode(String msgCode) {
this.msgCode = msgCode;
}
}

@ -0,0 +1,313 @@
package com.engine.common.util.excel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.exception.ContextedRuntimeException;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import static com.engine.common.util.excel.ExcelSupport.EXCEL_TYPE_XLSX;
/**
* Excel
**/
@Slf4j
public class ExcelParseHelper {
//待校验的行号
private static final int PARSE_EXCEL_ROW_VALID_CELL_INDEX = 0;
//字符开始下标
private static final int CHARACTER_FIRST_INDEX = 0;
/**
* Excel JavaBean
*
* @param file excel
* @param clazz bean
* @param sheetIndex excelsheet0
* @param rowIndex ,0
* @param standardCellNum sheet
* @return
*/
public static <T> List<T> parse2Map(MultipartFile file, Class<T> clazz, int sheetIndex, int rowIndex, int standardCellNum) {
List<List<String>> result = parse2Map(file, sheetIndex, rowIndex, standardCellNum);
List<T> list = new ArrayList<T>();
for (List<String> rowDatas : result) {
T t = setField(clazz, rowDatas);
list.add(t);
}
return list;
}
/**
* Excel JavaBean
*
* @param file excel
* @param clazz bean
* @param sheetIndex excelsheet0
* @param rowIndex ,0
* @param standardCellNum sheet
* @param fileName
* @return
*/
public static <T> List<T> parse2Map(InputStream file, Class<T> clazz, int sheetIndex, int rowIndex, int standardCellNum, String fileName) {
List<List<String>> result = parse2Map(file, sheetIndex, rowIndex, standardCellNum, fileName);
List<T> list = new ArrayList<T>();
for (List<String> rowDatas : result) {
T t = setField(clazz, rowDatas);
list.add(t);
}
return list;
}
/**
* <strong>excel</strong>
*
* @param file
* @param sheetIndex sheet
* @param rowIndex 0
* @return
*/
private static List<List<String>> parse2Map(MultipartFile file, int sheetIndex, int rowIndex, int standardCellNum) {
Sheet sheet = ExcelSupport.parseFile(file, sheetIndex);
int rowCount = sheet.getPhysicalNumberOfRows(); // 总行数
int cellCount = sheet.getRow(PARSE_EXCEL_ROW_VALID_CELL_INDEX).getPhysicalNumberOfCells(); // 总列数
Validate.isTrue(standardCellNum == cellCount, "Error in excel template! Page %s sheet should have %s column data, existing in %s column , please check the template!", sheetIndex, standardCellNum, cellCount);
List<List<String>> result = new ArrayList<List<String>>();
for (; rowIndex < rowCount; rowIndex++) {
List<String> cellResult = new ArrayList<String>();
for (int j = 0; j < cellCount; j++) {
cellResult.add(ExcelSupport.getCellValue(sheet, rowIndex, j));
}
result.add(cellResult);
}
return result;
}
/**
* <strong>excel</strong>
*
* @param file
* @param sheetIndex sheet
* @param rowIndex 0
* @return
*/
private static List<List<String>> parse2Map(InputStream file, int sheetIndex, int rowIndex, int standardCellNum, String fileName) {
Sheet sheet = ExcelSupport.parseFile(file, sheetIndex, fileName);
int rowCount = sheet.getPhysicalNumberOfRows(); // 总行数
int cellCount = sheet.getRow(PARSE_EXCEL_ROW_VALID_CELL_INDEX).getPhysicalNumberOfCells(); // 总列数
Validate.isTrue(standardCellNum == cellCount, "Error in excel template! Page %s sheet should have %s column data, existing in %s column , please check the template!", sheetIndex, standardCellNum, cellCount);
List<List<String>> result = new ArrayList<List<String>>();
for (; rowIndex < rowCount; rowIndex++) {
List<String> cellResult = new ArrayList<String>();
for (int j = 0; j < cellCount; j++) {
cellResult.add(ExcelSupport.getCellValue(sheet, rowIndex, j));
}
result.add(cellResult);
}
return result;
}
/**
* sheetmap
*
* @param file
* @param sheetIndex sheet
* @param rowIndex
* @return
*/
public static List<Map<String, Object>> parse2Map(InputStream file, int sheetIndex, int rowIndex) {
Sheet sheet = ExcelSupport.parseFile(file, sheetIndex, EXCEL_TYPE_XLSX);
int rowCount = sheet.getPhysicalNumberOfRows(); // 总行数
int cellCount = sheet.getRow(PARSE_EXCEL_ROW_VALID_CELL_INDEX).getPhysicalNumberOfCells(); // 总列数
List<String> sheetHeader = ExcelSupport.getSheetHeader(sheet, PARSE_EXCEL_ROW_VALID_CELL_INDEX);
List<Map<String, Object>> result = new ArrayList<>();
for (; rowIndex < rowCount; rowIndex++) {
Map<String, Object> cellResult = new HashMap<>();
for (int j = 0; j < cellCount; j++) {
String key = sheetHeader.get(j);
cellResult.put(key, ExcelSupport.getCellValue(sheet, rowIndex, j));
}
result.add(cellResult);
}
return result;
}
/**
* sheetmap
*
* @param rowIndex
* @return
*/
public static List<Map<String, Object>> parse2Map(Sheet sheet, int rowIndex) {
int rowCount = sheet.getPhysicalNumberOfRows(); // 总行数
int cellCount = sheet.getRow(PARSE_EXCEL_ROW_VALID_CELL_INDEX).getPhysicalNumberOfCells(); // 总列数
log.info("rowCount: {}", rowCount);
log.info("cellCount: {}", cellCount);
List<String> sheetHeader = ExcelSupport.getSheetHeader(sheet, PARSE_EXCEL_ROW_VALID_CELL_INDEX);
log.info("sheetHeader: {}", sheetHeader);
List<Map<String, Object>> result = new ArrayList<>();
for (; rowIndex < rowCount; rowIndex++) {
Map<String, Object> cellResult = new HashMap<>();
for (int j = 0; j < cellCount; j++) {
String key = sheetHeader.get(j);
cellResult.put(key, ExcelSupport.getCellValue(sheet, rowIndex, j));
}
result.add(cellResult);
}
return result;
}
/**
* sheetmap
*
* @param rowIndex
* @param headerRowIndex
* @return
*/
public static List<Map<String, Object>> parse2Map(Sheet sheet, int rowIndex, int headerRowIndex) {
int rowCount = sheet.getPhysicalNumberOfRows(); // 总行数
int cellCount = sheet.getRow(headerRowIndex).getPhysicalNumberOfCells(); // 总列数
List<String> sheetHeader = ExcelSupport.getSheetHeader(sheet, headerRowIndex);
List<Map<String, Object>> result = new ArrayList<>();
for (; rowIndex < rowCount; rowIndex++) {
Map<String, Object> cellResult = new HashMap<>();
for (int j = 0; j < cellCount; j++) {
String key = sheetHeader.get(j);
cellResult.put(key, ExcelSupport.getCellValue(sheet, rowIndex, j));
}
result.add(cellResult);
}
return result;
}
/**
* sheetList
*
* @param rowIndex
* @return
*/
public static List<List<String>> parse2List(Sheet sheet, int rowIndex) {
int rowCount = sheet.getPhysicalNumberOfRows(); // 总行数
int cellCount = sheet.getRow(PARSE_EXCEL_ROW_VALID_CELL_INDEX).getPhysicalNumberOfCells(); // 总列数
List<List<String>> result = new ArrayList<List<String>>();
for (; rowIndex < rowCount; rowIndex++) {
List<String> cellResult = new ArrayList<String>();
for (int j = 0; j < cellCount; j++) {
cellResult.add(ExcelSupport.getCellValue(sheet, rowIndex, j));
}
result.add(cellResult);
}
return result;
}
/**
* sheetList
* @param rowIndex
* @param headerRowIndex
* @return
*/
public static List<List<String>> parse2List(Sheet sheet, int rowIndex, int headerRowIndex) {
int rowCount = sheet.getPhysicalNumberOfRows(); // 总行数
int cellCount = sheet.getRow(headerRowIndex).getPhysicalNumberOfCells(); // 总列数
List<List<String>> result = new ArrayList<List<String>>();
for (; rowIndex < rowCount; rowIndex++) {
List<String> cellResult = new ArrayList<String>();
for (int j = 0; j < cellCount; j++) {
cellResult.add(ExcelSupport.getCellValue(sheet, rowIndex, j));
}
result.add(cellResult);
}
return result;
}
/**
*
*
* @param clazz
* @param rowDatas
* @param <T>
* @return
*/
private static <T> T setField(Class<T> clazz, List<String> rowDatas) {
try {
T obj = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
if (excelProperty == null) {
continue;
}
int index = excelProperty.index();
Object value = getFieldValue(field, rowDatas.get(index), excelProperty);
field.setAccessible(true);
field.set(obj, value);
}
return obj;
} catch (Exception e) {
throw new ExcelParseException(e.getMessage(), e);
}
}
/**
* <strong>javaBean</strong>
*
* @param field javaBean
* @param value excel
* @param excelProperty javaBeanexcel
* @return
*/
@SuppressWarnings("rawtypes")
private static Object getFieldValue(Field field, String value, ExcelProperty excelProperty) {
if (StringUtils.isEmpty(value)) {
return null;
}
Object val = null;
try {
Class typeClass = field.getType();
if (typeClass == Integer.class) {
val = Integer.valueOf(value);
} else if (typeClass == Long.class) {
val = Long.valueOf(value);
} else if (typeClass == Float.class) {
val = Float.valueOf(value);
} else if (typeClass == Double.class) {
val = Double.valueOf(value);
} else if (typeClass == Date.class) {
val = ExcelSupport.getDate(value, excelProperty.format());
} else if (typeClass == Short.class) {
val = Short.valueOf(value);
} else if (typeClass == Character.class) {
val = value.charAt(CHARACTER_FIRST_INDEX);
} else if (typeClass == BigDecimal.class) {
val = new BigDecimal(value);
} else {
val = value;
}
} catch (Exception e) {
throw new ContextedRuntimeException(excelProperty.msg(), e);
}
return val;
}
}

@ -0,0 +1,14 @@
package com.engine.common.util.excel;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelProperty {
public int index(); // 指定 JavaBean 的属性对应 excel 的第几列
public String format() default "yyyy-MM-dd"; // 当 JavaBean 的属性为 Date 类型时,指定 Date 的格式化模式
public String msg() default "解析错误";//当因excel中数据格式错误而造成的解析异常时提示的错误信息
}

@ -0,0 +1,171 @@
package com.engine.common.util.excel;
import org.apache.commons.lang3.Validate;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
/**
* @Author: sy
* @Description:
* @Date: 2024/6/5
**/
public class ExcelSupport {
private static final String pattern = "yyyy-MM-dd HH:mm:ss";
//excel类型
public static final String EXCEL_TYPE_XLSX = "xlsx";
public static final String EXCEL_TYPE_XLS = "xls";
/**
* sheet
*
* @param file
* @param sheetIndex sheet0
* @return sheet
*/
public static Sheet parseFile(MultipartFile file, int sheetIndex) {
Workbook workBook = null;
try (InputStream ins = file.getInputStream();) {
String fileName = file.getOriginalFilename();
if (fileName.endsWith(EXCEL_TYPE_XLSX)) {
workBook = new XSSFWorkbook(ins);
} else if (fileName.endsWith(EXCEL_TYPE_XLS)) {
workBook = new HSSFWorkbook(ins);
} else {
throw new IllegalArgumentException("File format error! Only xlsx and xls types are supported");
}
return workBook.getSheetAt(sheetIndex);
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
/**
* sheet
*
* @param sheetIndex sheet0
* @return sheet
*/
public static Sheet parseFile(InputStream ins, int sheetIndex,String fileName) {
Workbook workBook = null;
try {
if (fileName.endsWith(EXCEL_TYPE_XLSX)) {
workBook = new XSSFWorkbook(new BufferedInputStream(ins));
} else if (fileName.endsWith(EXCEL_TYPE_XLS)) {
workBook = new HSSFWorkbook(new BufferedInputStream(ins));
} else {
throw new IllegalArgumentException("File format error! Only xlsx and xls types are supported");
}
return workBook.getSheetAt(sheetIndex);
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
/**
* sheet
*
* @param sheet
* @param headerIndex
* @return
*/
public static List<String> getSheetHeader(Sheet sheet, int headerIndex) {
List<java.lang.String> headers = new ArrayList<>();
Row headerRow = sheet.getRow(headerIndex);
Iterator cellIterator = headerRow.cellIterator();
while (cellIterator.hasNext()) {
Cell cell = (Cell) cellIterator.next();
java.lang.String stringCellValue = cell.getStringCellValue();
headers.add(stringCellValue);
// if (cell.getCellType().equals(CellType.NUMERIC)) {
// double numericValue = cell.getNumericCellValue();
// headers.add(String.valueOf(numericValue));
// } else if (cell.getCellType().equals(CellType.STRING)) {
// java.lang.String stringCellValue = cell.getStringCellValue();
// headers.add(stringCellValue);
// }
}
return headers;
}
/**
*
*
* @param sheet sheet
* @param rowIndex 0
* @param cellIndex 0
* @return
*/
public static String getCellValue(Sheet sheet, int rowIndex, int cellIndex) {
Validate.notNull(sheet.getRow(rowIndex), "Line %s is empty and cannot be resolved", rowIndex);
return getCellValue(sheet.getRow(rowIndex).getCell(cellIndex));
}
private static final DecimalFormat decimalFormat = new DecimalFormat("####################.###########");
/**
*
*/
public static String getCellValue(Cell cell) {
String cellValue = "";
if (cell != null) {
switch (cell.getCellType()) {
case NUMERIC: // 数值类型
if (DateUtil.isCellDateFormatted(cell)) {
cellValue = getDateStr(cell.getDateCellValue(), pattern);
} else {
// cell.setCellType(STRING);
// cellValue = cell.getStringCellValue();
cellValue = decimalFormat.format(cell.getNumericCellValue());
}
break;
case STRING: // 字符串类型
cellValue = cell.getStringCellValue();
break;
case BOOLEAN: // 布尔类型
cellValue = String.valueOf(cell.getBooleanCellValue());
break;
case FORMULA: // 公式类型
cellValue = String.valueOf(cell.getCellFormula());
break;
case BLANK: // 空白类型
cellValue = "";
break;
case ERROR:
cellValue = "";
break;
default:
cellValue = cell.toString().trim();
break;
}
}
return cellValue.trim();
}
public static Date getDate(String dateStr, String pattern) {
try {
return new SimpleDateFormat(pattern).parse(dateStr);
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
}
private static String getDateStr(Date date, String pattern) {
return new SimpleDateFormat(pattern).format(date);
}
}

@ -0,0 +1,219 @@
package com.engine.common.util.excel;
import com.engine.common.util.DateUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;
import java.util.Date;
import java.util.List;
/**
* @Author: sy
* @Description:
* @Date: 2024/6/5
**/
public class ExcelUtil {
public static XSSFWorkbook genWorkbookV2(List<List<Object>> rowList, String sheetName) {
XSSFWorkbook workbook = new XSSFWorkbook();
// 设置title样式
XSSFCellStyle titleCellStyle = workbook.createCellStyle();
XSSFFont titleFont = workbook.createFont();
titleFont.setBold(true);
titleFont.setFontName("仿宋");
titleFont.setFontHeightInPoints((short) 15);
titleCellStyle.setFont(titleFont);
titleCellStyle.setAlignment(HorizontalAlignment.CENTER);
titleCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());//背景色
titleCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
titleCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
titleCellStyle.setBorderLeft(BorderStyle.THIN);
titleCellStyle.setBorderRight(BorderStyle.THIN);
titleCellStyle.setBorderTop(BorderStyle.THIN);
titleCellStyle.setBorderBottom(BorderStyle.THIN);
// 设置主体样式
XSSFCellStyle cellStyle = workbook.createCellStyle();
XSSFFont font = workbook.createFont();
font.setFontName("宋体");
font.setFontHeightInPoints((short) 10);// 设置字体大小
cellStyle.setFont(font);// 选择需要用到的字体格式
cellStyle.setWrapText(true);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
XSSFSheet sheet = workbook.createSheet(sheetName);
//自适应宽度
sheet.autoSizeColumn(0, true);
//默认列宽
sheet.setDefaultColumnWidth(20);
//默认行高
sheet.setDefaultRowHeightInPoints(18);
//遍历设置列宽
List<Object> header = rowList.get(0);
for (int i = 0; i < header.size(); i++) {
sheet.setColumnWidth(i, Math.max(12, header.get(i).toString().length() * 4) * 256);
}
for (int rowIndex = 0; rowIndex < rowList.size(); rowIndex++) {
List<Object> infoList = rowList.get(rowIndex);
XSSFRow row = sheet.createRow(rowIndex);
float height = 18;
float finalHeight = 18;
for (int cellIndex = 0; cellIndex < infoList.size(); cellIndex++) {
XSSFCell cell = row.createCell(cellIndex);
if (rowIndex == 0) {
cell.setCellStyle(titleCellStyle);
} else {
cell.setCellStyle(cellStyle);
}
Object o = infoList.get(cellIndex);
if (o instanceof String) {
cell.setCellType(CellType.STRING);
cell.setCellValue(String.valueOf(o));
} else if (o instanceof Boolean) {
cell.setCellType(CellType.BOOLEAN);
cell.setCellValue(String.valueOf(o));
} else if (o instanceof Date) {
cell.setCellType(CellType.STRING);
cell.setCellValue(com.engine.common.util.DateUtil.getFormatLocalDate((Date) o));
} else {
cell.setCellType(CellType.STRING);
cell.setCellValue(o == null ? "" : o.toString());
}
//判断是否要调整高度
int width = sheet.getColumnWidth(cellIndex) / 256;
finalHeight = getFinalHeight(o, width, finalHeight, height);
}
row.setHeightInPoints(finalHeight);
}
return workbook;
}
public static XSSFWorkbook genWorkbookV2(List<List<Object>> rowList, String sheetName, String title, int titleCellNum) {
XSSFWorkbook workbook = new XSSFWorkbook();
// 设置title样式
XSSFCellStyle titleCellStyle = workbook.createCellStyle();
XSSFFont titleFont = workbook.createFont();
titleFont.setBold(true);
titleFont.setFontName("仿宋");
titleFont.setFontHeightInPoints((short) 15);
titleCellStyle.setFont(titleFont);
titleCellStyle.setAlignment(HorizontalAlignment.CENTER);
titleCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());//背景色
titleCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
titleCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
titleCellStyle.setBorderLeft(BorderStyle.THIN);
titleCellStyle.setBorderRight(BorderStyle.THIN);
titleCellStyle.setBorderTop(BorderStyle.THIN);
titleCellStyle.setBorderBottom(BorderStyle.THIN);
// 设置主体样式
XSSFCellStyle cellStyle = workbook.createCellStyle();
XSSFFont font = workbook.createFont();
font.setFontName("宋体");
font.setFontHeightInPoints((short) 10);// 设置字体大小
cellStyle.setFont(font);// 选择需要用到的字体格式
cellStyle.setWrapText(true);
cellStyle.setBorderLeft(BorderStyle.THIN);
cellStyle.setBorderRight(BorderStyle.THIN);
cellStyle.setBorderTop(BorderStyle.THIN);
cellStyle.setBorderBottom(BorderStyle.THIN);
XSSFSheet sheet = workbook.createSheet(sheetName);
//自适应宽度
sheet.autoSizeColumn(0, true);
//默认列宽
sheet.setDefaultColumnWidth(20);
//默认行高
sheet.setDefaultRowHeightInPoints(18);
// 合并第一行的前titleCellNum个单元格
CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 0, 0, titleCellNum - 1);
sheet.addMergedRegion(cellRangeAddress);
//遍历设置列宽
List<Object> header = rowList.get(0);
for (int i = 0; i < header.size(); i++) {
sheet.setColumnWidth(i, Math.max(12, header.get(i).toString().length() * 4) * 256);
}
for (int rowIndex = 0; rowIndex <= rowList.size(); rowIndex++) {
List<Object> infoList = rowList.get(rowIndex);
XSSFRow row = sheet.createRow(rowIndex);
float height = 18;
float finalHeight = 18;
if (rowIndex == 0) {
XSSFCell cell = row.createCell(0);
cell.setCellStyle(titleCellStyle);
cell.setCellType(CellType.STRING);
cell.setCellValue(title);
} else {
for (int cellIndex = 0; cellIndex < infoList.size(); cellIndex++) {
XSSFCell cell = row.createCell(cellIndex);
if (rowIndex == 1) {
cell.setCellStyle(titleCellStyle);
} else {
cell.setCellStyle(cellStyle);
}
Object o = infoList.get(cellIndex);
if (o instanceof String) {
cell.setCellType(CellType.STRING);
cell.setCellValue(String.valueOf(o));
} else if (o instanceof Boolean) {
cell.setCellType(CellType.BOOLEAN);
cell.setCellValue(String.valueOf(o));
} else if (o instanceof Date) {
cell.setCellType(CellType.STRING);
cell.setCellValue(DateUtil.getFormatLocalDate((Date) o));
} else {
cell.setCellType(CellType.STRING);
cell.setCellValue(o == null ? "" : o.toString());
}
//判断是否要调整高度
int width = sheet.getColumnWidth(cellIndex) / 256;
finalHeight = getFinalHeight(o, width, finalHeight, height);
}
}
row.setHeightInPoints(finalHeight);
}
return workbook;
}
public static float getFinalHeight(Object o, int width, float finalHeight, float height) {
if (o != null && getStrlength(o.toString()) > width) {
float remainder = getStrlength(o.toString()) % width;
int multiple = getStrlength(o.toString()) / width;
int finalMultiple = remainder > 0 ? (multiple + 1) : multiple;
float compareHeight = height * finalMultiple;
finalHeight = Math.max(finalHeight, compareHeight);
}
return finalHeight;
}
public static int getStrlength(String str) {
int strLength = 0;
String chinese = "[\u0391-\uFFE5]";
/* 获取字段值的长度如果含中文字符则每个中文字符长度为2否则为1 */
for (int i = 0; i < str.length(); i++) {
/* 从字符串中获取一个字符 */
String temp = str.substring(i, i + 1);
/* 判断是否为中文字符 */
if (temp.matches(chinese)) {
/* 中文字符长度为2 */
strLength += 2;
} else {
/* 其他字符长度为1 */
strLength += 1;
}
}
return strLength;
}
}
Loading…
Cancel
Save