diff --git a/src/com/api/attendance/component/ImportAndExport/ExcelControllerApi.java b/src/com/api/attendance/component/ImportAndExport/ExcelControllerApi.java new file mode 100644 index 0000000..13b8a7d --- /dev/null +++ b/src/com/api/attendance/component/ImportAndExport/ExcelControllerApi.java @@ -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 { +} diff --git a/src/com/engine/attendance/attendanceanalysis/service/impl/AttendanceSummaryServiceImpl.java b/src/com/engine/attendance/attendanceanalysis/service/impl/AttendanceSummaryServiceImpl.java index f8dec02..ff42ecb 100644 --- a/src/com/engine/attendance/attendanceanalysis/service/impl/AttendanceSummaryServiceImpl.java +++ b/src/com/engine/attendance/attendanceanalysis/service/impl/AttendanceSummaryServiceImpl.java @@ -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); } diff --git a/src/com/engine/attendance/component/ImportAndExport/service/ExcelExportImportService.java b/src/com/engine/attendance/component/ImportAndExport/service/ExcelExportImportService.java new file mode 100644 index 0000000..4a4b0b6 --- /dev/null +++ b/src/com/engine/attendance/component/ImportAndExport/service/ExcelExportImportService.java @@ -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 paramMap); + + /** + * 日历排班页面中的排班列表导入 + * @param param + * @return + */ + Map importSchedule(ImportParam param); +} diff --git a/src/com/engine/attendance/component/ImportAndExport/service/impl/ExcelExportImportServiceImpl.java b/src/com/engine/attendance/component/ImportAndExport/service/impl/ExcelExportImportServiceImpl.java new file mode 100644 index 0000000..3a145d9 --- /dev/null +++ b/src/com/engine/attendance/component/ImportAndExport/service/impl/ExcelExportImportServiceImpl.java @@ -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 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 scheduleResult = getWorkRulesService(user).getDepartSchedule(paramMap); + List columns = buildScheduleColumns((List>) scheduleResult.get("columns")); + List> records = buildScheduleRecords((List>) scheduleResult.get("datas")); + + List> excelSheetData = new ArrayList<>(); + //工作簿名称 + String sheetName = "日历排班"; + excelSheetData.add(Arrays.asList(columns.stream().map(WeaTableColumn::getText).toArray())); + + //工作簿数据 + List> rows = new LinkedList<>(); + for (Map recordData : records) { + List 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> buildScheduleRecords(List> dataInfo) { + List> result = new ArrayList<>(); + if (dataInfo != null && dataInfo.size() > 0) { + Map dayItem; + Map record; + for (Map 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 entry : dataItem.entrySet()) { + if (DateUtil.dateIsValid(entry.getKey())) { + dayItem = (Map) entry.getValue(); + record.put(entry.getKey(), Util.null2String(dayItem.get("title"))); + } + } + result.add(record); + } + } + return result; + } + + private List buildScheduleColumns(List> columnInfo) { + List list = new ArrayList<>(); + if (columnInfo != null && columnInfo.size() > 0) { + for (Map columnItem : columnInfo) { + list.add(new WeaTableColumn("150px", Util.null2String(columnItem.get("title")), Util.null2String(columnItem.get("dataIndex")))); + } + } + return list; + } + + @Override + public Map importSchedule(ImportParam param) { + + if (StringUtils.isBlank(param.getImageId())) { + throw new AttendanceRunTimeException("导入文件id为空!"); + } + int successCount = 0; + int errorCount = 0; + //查询formmodeid + Map formModeIdMap = Utils.getFormmodeIdMap(); + String formModeId = formModeIdMap.get("uf_pbjg"); + // 获取所有人员信息 + List> employeeInfoList = getAllEmpInfo(); + //获取班次名称对于班次信息的映射 + Map shiftMapWithMc = getShiftInfoToMc(); + // 待入库数据 + List> toImportScheduleInfos = new ArrayList<>(); + // 待处理数据 + InputStream fileInputStream = null; + // 待处理数据关联的人员ids + List 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 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 headers = ExcelSupport.getSheetHeader(sheet, 1); + log.info("headers数据:{}", headers); + // 错误sheet数据 + List> errorData = new LinkedList<>(); + // 错误提示 + List> excelComments = new LinkedList<>(); + // 处理数值 + List> data = ExcelParseHelper.parse2Map(sheet, 2, 1); + log.info("excel导入数据:[{}]", data); + //单行记录 + Map map; + for (int i = 0; i < data.size(); i++) { + map = data.get(i); + boolean isError = false; + Map 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 apidatas = new HashMap(); + apidatas.put("successCount", successCount); + apidatas.put("errorCount", errorCount); + apidatas.put("errorData", excelComments); + return apidatas; + } finally { + IOUtils.closeQuietly(fileInputStream); + } + + } + + private List> 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> empInfo = DbTools.getSqlToList(sql); + return empInfo; + } + + private Map getShiftInfoToMc() { + String sql = "select id, mc, sfxx from uf_jcl_kq_bcxx "; + List> shiftInfo = DbTools.getSqlToList(sql); + Map shiftMapWithMc = shiftInfo.stream().collect(Collectors.toMap(e->e.get("mc").toString(), e->e)); + return shiftMapWithMc; + } + + public boolean singleScheduleLineCheck(Map singleCheck, String yearMonth, int monthDays, + List> toImportScheduleInfos, List> employeeByIds, + Map shiftMapWithMc, List> excelComments, int index, String formModeId, List 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> targetEmpInfo = matchImportEmp(employeeByIds, lastName, subCompany, department, workCode); + if (CollectionUtils.isEmpty(targetEmpInfo)) { + Map errorMessageMap = new HashMap<>(); + errorMessageMap.put("message", rowIndex + "员工信息不存在!"); + excelComments.add(errorMessageMap); + isError = true; + return isError; + } else if (targetEmpInfo.size() > 1) { + Map 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 errorMessageMap = new HashMap<>(); + errorMessageMap.put("message", rowIndex + "表格中同一员工不可存在多组排班数据!"); + excelComments.add(errorMessageMap); + isError = true; + return isError; + } + //获取目标人员目标月日期类型对日期的映射 + List> rqlxInfo = CommonUtil.getYearCalendarList(employeeId, yearMonth.substring(0, 4)); + Map 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> singleToImportScheduleInfos = new ArrayList<>(); + //排班日期、班次名称 + String scheduleDate = ""; + String shiftName = ""; + Map shiftInfo; + Map 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) shiftMapWithMc.get(shiftName); + if (!"".equals(shiftName) && shiftInfo == null) { + Map 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> matchImportEmp(List> 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> toImportScheduleInfos, List empIds, String yearMonth, int monthDays) { + if (toImportScheduleInfos.size() > 0 && empIds.size() > 0) { + //获取日期集合 + List 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"); + } + } +} diff --git a/src/com/engine/attendance/component/ImportAndExport/service/param/ImportParam.java b/src/com/engine/attendance/component/ImportAndExport/service/param/ImportParam.java new file mode 100644 index 0000000..2c44bd7 --- /dev/null +++ b/src/com/engine/attendance/component/ImportAndExport/service/param/ImportParam.java @@ -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; +} diff --git a/src/com/engine/attendance/component/ImportAndExport/web/ExcelController.java b/src/com/engine/attendance/component/ImportAndExport/web/ExcelController.java new file mode 100644 index 0000000..b54c08b --- /dev/null +++ b/src/com/engine/attendance/component/ImportAndExport/web/ExcelController.java @@ -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 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>(user).run(getExcelService(user)::importSchedule, param); + } +} diff --git a/src/com/engine/common/util/DateUtil.java b/src/com/engine/common/util/DateUtil.java index ada9290..a3220a6 100644 --- a/src/com/engine/common/util/DateUtil.java +++ b/src/com/engine/common/util/DateUtil.java @@ -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); + } } diff --git a/src/com/engine/common/util/excel/ExcelParseException.java b/src/com/engine/common/util/excel/ExcelParseException.java new file mode 100644 index 0000000..d316ad4 --- /dev/null +++ b/src/com/engine/common/util/excel/ExcelParseException.java @@ -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; + } + +} diff --git a/src/com/engine/common/util/excel/ExcelParseHelper.java b/src/com/engine/common/util/excel/ExcelParseHelper.java new file mode 100644 index 0000000..206180e --- /dev/null +++ b/src/com/engine/common/util/excel/ExcelParseHelper.java @@ -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 excel中第几个sheet,从0开始 + * @param rowIndex 从第几行开始解析,第一行是0 + * @param standardCellNum 模板验证,该sheet应有多少列 + * @return + */ + public static List parse2Map(MultipartFile file, Class clazz, int sheetIndex, int rowIndex, int standardCellNum) { + List> result = parse2Map(file, sheetIndex, rowIndex, standardCellNum); + List list = new ArrayList(); + for (List rowDatas : result) { + T t = setField(clazz, rowDatas); + list.add(t); + } + return list; + } + + /** + * 将 Excel 解析为 JavaBean 对象 + * + * @param file excel文件 + * @param clazz 解析bean的类 + * @param sheetIndex excel中第几个sheet,从0开始 + * @param rowIndex 从第几行开始解析,第一行是0 + * @param standardCellNum 模板验证,该sheet应有多少列 + * @param fileName 文件名 + * @return + */ + public static List parse2Map(InputStream file, Class clazz, int sheetIndex, int rowIndex, int standardCellNum, String fileName) { + List> result = parse2Map(file, sheetIndex, rowIndex, standardCellNum, fileName); + List list = new ArrayList(); + for (List rowDatas : result) { + T t = setField(clazz, rowDatas); + list.add(t); + } + return list; + } + + /** + * 获取excel数据。 + * + * @param file 文件 + * @param sheetIndex 解析第几个sheet + * @param rowIndex 从第几行开始解析,第一行为 0,依次类推 + * @return 二维数据集合 + */ + private static List> 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> result = new ArrayList>(); + for (; rowIndex < rowCount; rowIndex++) { + List cellResult = new ArrayList(); + for (int j = 0; j < cellCount; j++) { + cellResult.add(ExcelSupport.getCellValue(sheet, rowIndex, j)); + } + result.add(cellResult); + } + return result; + } + + /** + * 获取excel数据。 + * + * @param file 文件 + * @param sheetIndex 解析第几个sheet + * @param rowIndex 从第几行开始解析,第一行为 0,依次类推 + * @return 二维数据集合 + */ + private static List> 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> result = new ArrayList>(); + for (; rowIndex < rowCount; rowIndex++) { + List cellResult = new ArrayList(); + for (int j = 0; j < cellCount; j++) { + cellResult.add(ExcelSupport.getCellValue(sheet, rowIndex, j)); + } + result.add(cellResult); + } + return result; + } + + + /** + * 将sheet数据转为map + * + * @param file + * @param sheetIndex sheet下标 + * @param rowIndex 从哪行开始解析 + * @return + */ + public static List> 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 sheetHeader = ExcelSupport.getSheetHeader(sheet, PARSE_EXCEL_ROW_VALID_CELL_INDEX); + + List> result = new ArrayList<>(); + for (; rowIndex < rowCount; rowIndex++) { + Map 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; + } + + + /** + * 将sheet数据转为map + * + * @param rowIndex 从哪行开始解析 + * @return + */ + public static List> 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 sheetHeader = ExcelSupport.getSheetHeader(sheet, PARSE_EXCEL_ROW_VALID_CELL_INDEX); + log.info("sheetHeader: {}", sheetHeader); + + List> result = new ArrayList<>(); + for (; rowIndex < rowCount; rowIndex++) { + Map 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; + } + + /** + * 将sheet数据转为map + * + * @param rowIndex 从哪行开始解析 + * @param headerRowIndex 抽取列数的参考行 + * @return + */ + public static List> parse2Map(Sheet sheet, int rowIndex, int headerRowIndex) { + int rowCount = sheet.getPhysicalNumberOfRows(); // 总行数 + int cellCount = sheet.getRow(headerRowIndex).getPhysicalNumberOfCells(); // 总列数 + + List sheetHeader = ExcelSupport.getSheetHeader(sheet, headerRowIndex); + + List> result = new ArrayList<>(); + for (; rowIndex < rowCount; rowIndex++) { + Map 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; + } + + /** + * 将sheet数据转为List + * + * @param rowIndex 从哪行开始解析 + * @return + */ + public static List> parse2List(Sheet sheet, int rowIndex) { + int rowCount = sheet.getPhysicalNumberOfRows(); // 总行数 + int cellCount = sheet.getRow(PARSE_EXCEL_ROW_VALID_CELL_INDEX).getPhysicalNumberOfCells(); // 总列数 + + List> result = new ArrayList>(); + for (; rowIndex < rowCount; rowIndex++) { + List cellResult = new ArrayList(); + for (int j = 0; j < cellCount; j++) { + cellResult.add(ExcelSupport.getCellValue(sheet, rowIndex, j)); + } + result.add(cellResult); + } + return result; + } + + /** + * 将sheet数据转为List + * @param rowIndex 从哪行开始解析 + * @param headerRowIndex 抽取列数的参考行 + * @return + */ + public static List> parse2List(Sheet sheet, int rowIndex, int headerRowIndex) { + int rowCount = sheet.getPhysicalNumberOfRows(); // 总行数 + int cellCount = sheet.getRow(headerRowIndex).getPhysicalNumberOfCells(); // 总列数 + + List> result = new ArrayList>(); + for (; rowIndex < rowCount; rowIndex++) { + List cellResult = new ArrayList(); + for (int j = 0; j < cellCount; j++) { + cellResult.add(ExcelSupport.getCellValue(sheet, rowIndex, j)); + } + result.add(cellResult); + } + return result; + } + + + /** + * 为对象的每一个属性赋值 + * + * @param clazz + * @param rowDatas + * @param + * @return + */ + private static T setField(Class clazz, List 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); + } + } + + /** + * 获取javaBean属性值 + * + * @param field javaBean的对象属性 + * @param value excel中对应的值 + * @param excelProperty javaBean中解析excel注解,包含日期格式、错误提示信息 + * @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; + } +} + diff --git a/src/com/engine/common/util/excel/ExcelProperty.java b/src/com/engine/common/util/excel/ExcelProperty.java new file mode 100644 index 0000000..10fc1b3 --- /dev/null +++ b/src/com/engine/common/util/excel/ExcelProperty.java @@ -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中数据格式错误而造成的解析异常时,提示的错误信息 +} diff --git a/src/com/engine/common/util/excel/ExcelSupport.java b/src/com/engine/common/util/excel/ExcelSupport.java new file mode 100644 index 0000000..856a03f --- /dev/null +++ b/src/com/engine/common/util/excel/ExcelSupport.java @@ -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 sheet下标,从0开始 + * @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 sheet下标,从0开始 + * @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 getSheetHeader(Sheet sheet, int headerIndex) { + List 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); + } +} diff --git a/src/com/engine/common/util/excel/ExcelUtil.java b/src/com/engine/common/util/excel/ExcelUtil.java new file mode 100644 index 0000000..7641d90 --- /dev/null +++ b/src/com/engine/common/util/excel/ExcelUtil.java @@ -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> 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 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 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> 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 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 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; + } +}